From bd409285920bcb04a9494aa50714baa5160eb77c Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sat, 11 Apr 2026 18:24:30 -0700 Subject: [PATCH 01/17] refactor: use curl-sys instead of http library --- packages/http/lde.json | 7 ---- packages/http/src/init.lua | 44 ---------------------- packages/lde-core/lde.json | 2 +- packages/lde-core/src/package/rockspec.lua | 20 ++++++---- packages/lde-core/src/util/init.lua | 18 ++++----- packages/lde/lde.json | 2 +- packages/lde/src/commands/upgrade.lua | 8 ++-- packages/lde/src/init.lua | 2 +- packages/rocked/lde.json | 4 +- packages/rocked/tests/basic.test.lua | 8 ++-- 10 files changed, 36 insertions(+), 79 deletions(-) delete mode 100644 packages/http/lde.json delete mode 100644 packages/http/src/init.lua diff --git a/packages/http/lde.json b/packages/http/lde.json deleted file mode 100644 index cf6b1e4a..00000000 --- a/packages/http/lde.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "http", - "version": "0.1.0", - "dependencies": { - "process2": { "path": "../process2" } - } -} diff --git a/packages/http/src/init.lua b/packages/http/src/init.lua deleted file mode 100644 index 533e8b6f..00000000 --- a/packages/http/src/init.lua +++ /dev/null @@ -1,44 +0,0 @@ -local http = {} - -local process = require("process2") - ---- Perform a HTTP GET request ----@param url string ----@return string|nil ----@return string|nil -function http.get(url) - if not url or type(url) ~= "string" or url == "" then - return nil, "Invalid URL" - end - - local code, stdout, stderr = process.exec("curl", { "-sL", url }) - if code ~= 0 then - return nil, stderr or "Request failed" - end - - return stdout -end - ---- Perform a HTTP POST request ----@param url string ----@param data string ----@return string|nil ----@return string|nil -function http.post(url, data) - if not url or type(url) ~= "string" or url == "" then - return nil, "Invalid URL" - end - - if not data or type(data) ~= "string" then - return nil, "Invalid data" - end - - local code, stdout, stderr = process.exec("curl", { "-sL", "-X", "POST", "-d", data, url }) - if code ~= 0 then - return nil, stderr or "Request failed" - end - - return stdout -end - -return http diff --git a/packages/lde-core/lde.json b/packages/lde-core/lde.json index bb2d148b..165b714e 100644 --- a/packages/lde-core/lde.json +++ b/packages/lde-core/lde.json @@ -11,7 +11,7 @@ "fs": { "path": "../fs" }, "env": { "path": "../env" }, "util": { "path": "../util" }, - "http": { "path": "../http" }, + "curl-sys": { "git": "https://github.com/lde-org/curl-sys" }, "semver": { "path": "../semver" }, "lde-test": { "path": "../lde-test" }, "git": { "path": "../git" }, diff --git a/packages/lde-core/src/package/rockspec.lua b/packages/lde-core/src/package/rockspec.lua index 590a79c2..40faceed 100644 --- a/packages/lde-core/src/package/rockspec.lua +++ b/packages/lde-core/src/package/rockspec.lua @@ -4,10 +4,10 @@ local lde = require("lde-core") local fs = require("fs") local env = require("env") -local http = require("http") local path = require("path") local process = require("process2") local util = require("util") +local curl = require("curl-sys") ---@param dir string? ---@param rockspecPath string? # Path to the rockspec file; if nil, scanned from dir @@ -41,12 +41,12 @@ local function openRockspec(dir, rockspecPath) if fs.exists(cacheFile) then content = fs.read(cacheFile) else - local err - content, err = http.get(rockspecPath) - if not content then + local res, err = curl.get(rockspecPath) + if not res then return nil, "Could not fetch rockspec: " .. rockspecPath .. ": " .. (err or "") end + content = res.body fs.write(cacheFile, content) end else -- Looks like a path @@ -151,7 +151,8 @@ local function openRockspec(dir, rockspecPath) if buildType == "make" then if not process.exec("make", { "--version" }) then - return nil, "Package '" .. (spec.package or "?") .. "' requires 'make' to build, but it was not found." .. + return nil, + "Package '" .. (spec.package or "?") .. "' requires 'make' to build, but it was not found." .. " Install make (e.g. build-essential on Debian/Ubuntu, Xcode Command Line Tools on macOS)." end @@ -444,8 +445,13 @@ local function openRockspec(dir, rockspecPath) end end - return lde.Package.Config.new({ name = spec.package, version = spec.version, bin = resolvedBin, dependencies = - deps }) + return lde.Package.Config.new({ + name = spec.package, + version = spec.version, + bin = resolvedBin, + dependencies = + deps + }) end return pkg, nil diff --git a/packages/lde-core/src/util/init.lua b/packages/lde-core/src/util/init.lua index 71e2128a..8f89750d 100644 --- a/packages/lde-core/src/util/init.lua +++ b/packages/lde-core/src/util/init.lua @@ -1,6 +1,5 @@ local util = {} -local http = require("http") local fs = require("fs") local path = require("path") local git = require("git") @@ -9,7 +8,7 @@ local rocked = require("rocked") local ansi = require("ansi") local lde = require("lde-core") local luarocks = require("luarocks") -local process = require("process2") +local curl = require("curl-sys") local Archive = require("archive") local MANIFEST_URL = "https://luarocks.org/manifest" @@ -34,14 +33,14 @@ local function getManifest() end local p = lde.verbose and ansi.progress("Fetching luarocks manifest") or nil - local content, err = http.get(MANIFEST_URL) - if not content then + local res, err = curl.get(MANIFEST_URL) + if not res then if p then p:fail() end return nil, "Failed to fetch manifest: " .. (err or "") end - fs.write(cacheFile, content) - cachedManifest = luarocks.Manifest.new(content) + fs.write(cacheFile, res.body) + cachedManifest = luarocks.Manifest.new(res.body) if p then p:done() end return cachedManifest end @@ -106,11 +105,12 @@ function util.openRockspecUrl(name, url, branch, commit) content = fs.read(rockspecCacheFile) end if not content then - local fetchErr - content, fetchErr = http.get(url) - if not content then + local res, fetchErr = curl.get(url) + if not res then return nil, nil, "Failed to fetch rockspec: " .. (fetchErr or "") end + + content = res.body fs.write(rockspecCacheFile, content) end diff --git a/packages/lde/lde.json b/packages/lde/lde.json index d9420df6..b3bf638f 100644 --- a/packages/lde/lde.json +++ b/packages/lde/lde.json @@ -9,7 +9,7 @@ "clap": { "path": "../clap" }, "fs": { "path": "../fs" }, "env": { "path": "../env" }, - "http": { "path": "../http" }, + "curl-sys": { "git": "https://github.com/lde-org/curl-sys" }, "semver": { "path": "../semver" }, "lde-core": { "path": "../lde-core" }, "winapi": { diff --git a/packages/lde/src/commands/upgrade.lua b/packages/lde/src/commands/upgrade.lua index 9853451e..dab71d48 100644 --- a/packages/lde/src/commands/upgrade.lua +++ b/packages/lde/src/commands/upgrade.lua @@ -1,4 +1,3 @@ -local http = require("http") local process = require("process2") local semver = require("semver") local json = require("json") @@ -6,6 +5,7 @@ local ansi = require("ansi") local path = require("path") local fs = require("fs") local env = require("env") +local curl = require("curl-sys") local lde = require("lde-core") @@ -40,13 +40,13 @@ local function upgrade(args) releaseUrl = releasesUrl .. "/tags/v" .. desiredVersion end - local out, err = http.get(releaseUrl) - if not out then + local res, err = curl.get(releaseUrl) + if not res then ansi.printf("{red}Failed to fetch latest release: %s", err) return end - local releaseInfo = json.decode(out) + local releaseInfo = json.decode(res.body) if not releaseInfo or not releaseInfo.tag_name or not releaseInfo.assets then ansi.printf("{red}Invalid release information received") return diff --git a/packages/lde/src/init.lua b/packages/lde/src/init.lua index 699449a3..18cc8a15 100755 --- a/packages/lde/src/init.lua +++ b/packages/lde/src/init.lua @@ -41,7 +41,7 @@ if os.getenv("BOOTSTRAP") then end local pathPackages = { - "ansi", "clap", "fs", "http", "env", "path", "json", "git", "luarocks", + "ansi", "clap", "fs", "env", "path", "json", "git", "luarocks", "process2", "sea", "semver", "util", "lde-core", "lde-test", "rocked", "archive" } diff --git a/packages/rocked/lde.json b/packages/rocked/lde.json index 16073e17..5fbac599 100644 --- a/packages/rocked/lde.json +++ b/packages/rocked/lde.json @@ -1,5 +1,7 @@ { "name": "rocked", "version": "0.1.0", - "devDependencies": { "http": { "path": "../http" } } + "devDependencies": { + "curl-sys": { "git": "https://github.com/lde-org/curl-sys" } + } } diff --git a/packages/rocked/tests/basic.test.lua b/packages/rocked/tests/basic.test.lua index 6732896c..da6778d0 100644 --- a/packages/rocked/tests/basic.test.lua +++ b/packages/rocked/tests/basic.test.lua @@ -1,17 +1,17 @@ local test = require("lde-test") local rocked = require("rocked") -local http = require("http") +local curl = require("curl-sys") test.it("should be able to parse busted's rockspec", function() - local spec, err = http.get( + local res, err = curl.get( "https://raw.githubusercontent.com/lunarmodules/busted/56e6d68204d1456afa77f1346bf4e050df65b629/rockspecs/busted-2.3.0-1.rockspec" ) - if not spec then + if not res then error("Failed to GET busted rockspec: " .. err) end - local ok, parsed = rocked.parse(spec) + local ok, parsed = rocked.parse(res.body) if not ok then error("Failed to parse rockspec: " .. parsed) end From 82ef6a06687fdbd9d9abd9bde41baf955500bfb9 Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sat, 11 Apr 2026 18:35:08 -0700 Subject: [PATCH 02/17] build(macos): add more tools for building curl --- .github/workflows/build.yml | 4 ++++ .github/workflows/nightly.yml | 4 ++++ .github/workflows/release.yml | 4 ++++ .github/workflows/test.yml | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9756e33b..846957a8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -80,6 +80,10 @@ jobs: if: matrix.android run: echo "SEA_CC=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang" >> $GITHUB_ENV + - name: Install macOS build deps + if: startsWith(matrix.os, 'macos') + run: brew install autoconf automake libtool + - uses: lde-org/setup-lde@master with: version: nightly diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 3f4ac4a0..fdf1d301 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -105,6 +105,10 @@ jobs: if: matrix.android run: echo "SEA_CC=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-aarch64/bin/aarch64-linux-android21-clang" >> $GITHUB_ENV + - name: Install macOS build deps + if: startsWith(matrix.os, 'macos') + run: brew install autoconf automake libtool + - uses: lde-org/setup-lde@master with: version: nightly diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 826a2f2c..3ea4651e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -84,6 +84,10 @@ jobs: if: matrix.android run: echo "SEA_CC=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang" >> $GITHUB_ENV + - name: Install macOS build deps + if: startsWith(matrix.os, 'macos') + run: brew install autoconf automake libtool + - uses: lde-org/setup-lde@master with: version: nightly diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2112d2b6..312640c4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -95,6 +95,10 @@ jobs: if: matrix.android run: echo "SEA_CC=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-aarch64/bin/aarch64-linux-android21-clang" >> $GITHUB_ENV + - name: Install macOS build deps + if: startsWith(matrix.os, 'macos') + run: brew install autoconf automake libtool + - uses: lde-org/setup-lde@master with: version: nightly From 011e2e526b4a1ede77e02450737131c80ed46500 Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sat, 11 Apr 2026 18:39:35 -0700 Subject: [PATCH 03/17] build(android): add openssl --- .github/workflows/nightly.yml | 4 ++-- .github/workflows/test.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index fdf1d301..3f3e4fc6 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -132,7 +132,7 @@ jobs: uses: actions/cache@v5 with: path: /tmp/termux-android.tar - key: termux-android-v1 + key: termux-android-v2 - name: Setup Android test image if: matrix.android @@ -144,7 +144,7 @@ jobs: docker run --privileged --platform linux/arm64 --name termux-build \ -e DEBIAN_FRONTEND=noninteractive \ termux/termux-docker:aarch64 \ - bash -c "apt update && apt upgrade -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold && apt install -y git clang curl zip make" + bash -c "apt update && apt upgrade -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold && apt install -y git clang curl zip make openssl" docker commit termux-build termux-android:latest docker rm termux-build docker save termux-android:latest -o /tmp/termux-android.tar diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 312640c4..5949ae72 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -125,7 +125,7 @@ jobs: uses: actions/cache@v5 with: path: /tmp/termux-android.tar - key: termux-android-v1 + key: termux-android-v2 - name: Setup Android test image if: matrix.android @@ -137,7 +137,7 @@ jobs: docker run --privileged --platform linux/arm64 --name termux-build \ -e DEBIAN_FRONTEND=noninteractive \ termux/termux-docker:aarch64 \ - bash -c "apt update && apt upgrade -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold && apt install -y git clang curl zip make" + bash -c "apt update && apt upgrade -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold && apt install -y git clang curl zip make openssl" docker commit termux-build termux-android:latest docker rm termux-build docker save termux-android:latest -o /tmp/termux-android.tar From 36fffc354493ac3424023033bb9e059ce0e1cfa7 Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sat, 11 Apr 2026 18:55:08 -0700 Subject: [PATCH 04/17] refactor!: use curl-sys for curl downloads --- packages/lde-core/src/global/init.lua | 19 ++++++++++--------- packages/lde/src/commands/upgrade.lua | 14 ++++---------- packages/sea/lde.json | 3 ++- packages/sea/src/init.lua | 7 ++++--- 4 files changed, 20 insertions(+), 23 deletions(-) diff --git a/packages/lde-core/src/global/init.lua b/packages/lde-core/src/global/init.lua index e1bb2f76..68fdfa8a 100644 --- a/packages/lde-core/src/global/init.lua +++ b/packages/lde-core/src/global/init.lua @@ -8,6 +8,7 @@ local lde = require("lde-core") local ansi = require("ansi") local env = require("env") local Archive = require("archive") +local curl = require("curl-sys") local global = {} package.loaded[(...)] = global @@ -218,10 +219,10 @@ function global.getOrInitArchive(url) local archiveFile = archiveDir .. ".archive" - local code, _, stderr = process.exec("curl", { "-sL", "-o", archiveFile, url }) - if code ~= 0 then + local ok, dlErr = curl.download(url, archiveFile) + if not ok then if p then p:fail(label) end - error("Failed to download archive '" .. url .. "': " .. (stderr or "")) + error("Failed to download archive '" .. url .. "': " .. (dlErr or "")) end local code2, err2 @@ -364,20 +365,20 @@ function global.ensureMingw() local sevenzPath = path.join(tmpDir, "7zr.exe") local archivePath = path.join(tmpDir, "mingw.7z") - local code, _, stderr = process.exec("curl", { "-sL", "-o", sevenzPath, SEVENZ_URL }) - if code ~= 0 then + local ok, dlErr = curl.download(SEVENZ_URL, sevenzPath) + if not ok then fs.rmdir(tmpDir) if p1 then p1:fail() end - error("Failed to download 7zr.exe: " .. (stderr or "")) + error("Failed to download 7zr.exe: " .. (dlErr or "")) end if p1 then p1:done() end local p2 = lde.verbose and ansi.progress("Downloading MinGW toolchain") or nil - code, _, stderr = process.exec("curl", { "-sL", "-o", archivePath, MINGW_URL }) - if code ~= 0 then + local ok2, dlErr2 = curl.download(MINGW_URL, archivePath) + if not ok2 then fs.rmdir(tmpDir) if p2 then p2:fail() end - error("Failed to download MinGW archive: " .. (stderr or "")) + error("Failed to download MinGW archive: " .. (dlErr2 or "")) end if p2 then p2:done() end diff --git a/packages/lde/src/commands/upgrade.lua b/packages/lde/src/commands/upgrade.lua index dab71d48..132992bb 100644 --- a/packages/lde/src/commands/upgrade.lua +++ b/packages/lde/src/commands/upgrade.lua @@ -1,4 +1,3 @@ -local process = require("process2") local semver = require("semver") local json = require("json") local ansi = require("ansi") @@ -99,15 +98,10 @@ local function upgrade(args) ansi.printf("{green}==> Downloading {white}%s {green}from {cyan}%s", artifactName, downloadUrl) - -- Download directly to file to avoid output size limits in process.exec - local child, spawnErr = process.spawn("curl", { "-sL", "-o", tempNewLocation, downloadUrl }) - if not child then - ansi.printf("{red}Failed to download binary: %s", spawnErr) - return - end - local downloadCode = child:wait() - if downloadCode ~= 0 then - ansi.printf("{red}Failed to download binary: curl exited with code %d", downloadCode) + -- Download directly to file + local dlOk, dlErr = curl.download(downloadUrl, tempNewLocation) + if not dlOk then + ansi.printf("{red}Failed to download binary: %s", dlErr) return end diff --git a/packages/sea/lde.json b/packages/sea/lde.json index 609fc401..8cccadf0 100644 --- a/packages/sea/lde.json +++ b/packages/sea/lde.json @@ -7,6 +7,7 @@ "path": { "path": "../path" }, "env": { "path": "../env" }, "util": { "path": "../util" }, - "archive": { "path": "../archive" } + "archive": { "path": "../archive" }, + "curl-sys": { "git": "https://github.com/lde-org/curl-sys" } } } diff --git a/packages/sea/src/init.lua b/packages/sea/src/init.lua index 12168872..65978dc8 100644 --- a/packages/sea/src/init.lua +++ b/packages/sea/src/init.lua @@ -6,6 +6,7 @@ local env = require("env") local fs = require("fs") local jit = require("jit") local Archive = require("archive") +local curl = require("curl-sys") local util = require("util") @@ -103,9 +104,9 @@ local function getLuajitPath(compiler) ) local tarballPath = path.join(cacheDir, tarballName) - local code, _, stderr = process.exec("curl", { "-L", "-o", tarballPath, downloadUrl }) - if code ~= 0 then - error("Failed to download LuaJIT from " .. downloadUrl .. ": " .. (stderr or "")) + local ok, dlErr = curl.download(downloadUrl, tarballPath) + if not ok then + error("Failed to download LuaJIT from " .. downloadUrl .. ": " .. (dlErr or "")) end local ok, err = Archive.new(tarballPath):extract(cacheDir) From 90c2dff47a9dc114b4fb1e1fd55c9347462433a6 Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sat, 11 Apr 2026 21:20:12 -0700 Subject: [PATCH 05/17] tests(android): add /usr/lib to termux library search path --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5949ae72..6a6c096c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -150,5 +150,7 @@ jobs: --platform linux/arm64 \ -v ${{ github.workspace }}:/workspace \ -w /workspace \ + -e ANDROID_NDK_ROOT=/workspace/android-ndk-r29 \ + -e LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib \ termux-android:latest \ bash -c "/workspace/packages/lde/${{ env.OUTFILE }} test" From 4720777f746b895150f316db3f4e16df2d7b0682 Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sat, 11 Apr 2026 21:23:39 -0700 Subject: [PATCH 06/17] tests(android): debug code --- .github/workflows/test.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6a6c096c..1fab6030 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -143,6 +143,12 @@ jobs: docker save termux-android:latest -o /tmp/termux-android.tar fi + - name: Debug libssl (Android) + if: matrix.android + run: | + docker run --rm --platform linux/arm64 termux-android:latest \ + bash -c "find /data/data/com.termux/files/usr/lib -name 'libssl*'" + - name: Run tests (Android) if: matrix.android run: | From 1ec1217225c4e712087c9ec8c0acae5253e36bfb Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sat, 11 Apr 2026 22:53:12 -0700 Subject: [PATCH 07/17] tests(android): add more deps --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1fab6030..69b80c1a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -137,7 +137,7 @@ jobs: docker run --privileged --platform linux/arm64 --name termux-build \ -e DEBIAN_FRONTEND=noninteractive \ termux/termux-docker:aarch64 \ - bash -c "apt update && apt upgrade -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold && apt install -y git clang curl zip make openssl" + bash -c "apt update && apt upgrade -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold && apt install -y git clang curl zip make cmake autoconf automake libtool openssl perl" docker commit termux-build termux-android:latest docker rm termux-build docker save termux-android:latest -o /tmp/termux-android.tar From d25fdb803979d6c8fd2cee85e156475235f80bca Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sun, 12 Apr 2026 00:16:53 -0700 Subject: [PATCH 08/17] fix: run internal test callbacks inside of lde environment without upvalues So apparently the callbacks were just running without any of the patches and this was never noticed because you'd always use things like lde-test as an upvalue --- packages/lde-core/src/package/test.lua | 11 ++++++----- packages/lde-core/src/runtime.lua | 13 +++++++++++-- packages/lde-core/tests/main.test.lua | 19 ++++++++++++++++++- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/packages/lde-core/src/package/test.lua b/packages/lde-core/src/package/test.lua index 428b285f..7b3c0e10 100644 --- a/packages/lde-core/src/package/test.lua +++ b/packages/lde-core/src/package/test.lua @@ -76,23 +76,24 @@ local function runTests(package) local testObj = ldeTest.new() - local ok, err = runtime.executeFile(testFile, { + local ok, results = runtime.executeFile(testFile, { packagePath = luaPath, packageCPath = luaCPath, preload = { ["lpm-test"] = function() return testObj end, -- Compat - ["lde-test"] = function() return testObj end - } + ["lde-test"] = function() return testObj end, + ["lde-test.run"] = function() return testObj.run end + }, + postexec = function() return testObj.run() end }) if not ok then files[#files + 1] = { file = relativePath, results = {}, - error = err + error = results } else - local results = testObj.run() local failCount = 0 local skipCount = 0 for _, r in ipairs(results) do diff --git a/packages/lde-core/src/runtime.lua b/packages/lde-core/src/runtime.lua index da30415c..95967001 100644 --- a/packages/lde-core/src/runtime.lua +++ b/packages/lde-core/src/runtime.lua @@ -28,6 +28,7 @@ local builtinModules = { ---@field packageCPath string? ---@field preload table? ---@field cwd string? +---@field postexec (fun(): any)? --- Clears non-builtin entries from a table, returning the saved contents. ---@param t table @@ -122,13 +123,21 @@ local function executeWith(compile, opts, scriptName) local ok, result = pcall(function() package.path = opts.packagePath or oldPath package.cpath = opts.packageCPath or oldCPath + + local a, b, c, d, e, f if opts.args then arg = opts.args arg[0] = scriptName - return chunk(unpack(opts.args)) + a, b, c, d, e, f = chunk(unpack(opts.args)) else - return chunk() + a, b, c, d, e, f = chunk() + end + + if opts.postexec then + return opts.postexec() end + + return a, b, c, d, e, f end) for k, v in pairs(oldEnvVars) do env.set(k, v) end diff --git a/packages/lde-core/tests/main.test.lua b/packages/lde-core/tests/main.test.lua index 27a9d3e9..e25c7e27 100644 --- a/packages/lde-core/tests/main.test.lua +++ b/packages/lde-core/tests/main.test.lua @@ -4,7 +4,6 @@ local fs = require("fs") local env = require("env") local path = require("path") local json = require("json") -local process = require("process2") local git = require("git") local lde = require("lde-core") @@ -18,6 +17,24 @@ fs.rmdir(tmpBase) -- runtime.executeFile -- +test.it("runtime.executeFile postexec runs inside os.tmpname override", function() + fs.mkdir(tmpBase) + local scriptPath = path.join(tmpBase, "tmpname.lua") + fs.write(scriptPath, "") + + local tmpnameResult + local ok = lde.runtime.executeFile(scriptPath, { + postexec = function() + tmpnameResult = os.tmpname() + end + }) + test.truthy(ok) + test.truthy(tmpnameResult) + -- The overridden os.tmpname uses env.tmpdir(), not C tmpnam() which uses /tmp + local tmpdir = env.tmpdir() + test.truthy(tmpnameResult:sub(1, #tmpdir) == tmpdir, "tmpname should be under tmpdir, got: " .. tostring(tmpnameResult)) +end) + test.it("runtime.executeFile runs a Lua script", function() fs.mkdir(tmpBase) local scriptPath = path.join(tmpBase, "hello.lua") From 865b2cdaa275148552229196c45667fe1c7f0e45 Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sun, 12 Apr 2026 00:33:35 -0700 Subject: [PATCH 09/17] tests: cache curl-sys build --- .github/workflows/test.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 69b80c1a..73545221 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -103,6 +103,12 @@ jobs: with: version: nightly + - name: Cache curl-sys build + uses: actions/cache@v5 + with: + path: packages/*/target/curl-sys + key: curl-sys-${{ matrix.os }}-${{ hashFiles('lde.lock') }} + - name: Build lde # lde's own tests invoke the lde binary directly (e.g. to test CLI flags), # so we must compile a fresh binary from source before running tests. From 8a9067ecba3984b1752c6a3344861fb60f1053aa Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sun, 12 Apr 2026 00:58:53 -0700 Subject: [PATCH 10/17] test: remove libssl debug and fix android using linux cache --- .github/workflows/test.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 73545221..874fc735 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -107,7 +107,7 @@ jobs: uses: actions/cache@v5 with: path: packages/*/target/curl-sys - key: curl-sys-${{ matrix.os }}-${{ hashFiles('lde.lock') }} + key: curl-sys-${{ matrix.os }}${{ matrix.android && '-android' || '' }} - name: Build lde # lde's own tests invoke the lde binary directly (e.g. to test CLI flags), @@ -149,12 +149,6 @@ jobs: docker save termux-android:latest -o /tmp/termux-android.tar fi - - name: Debug libssl (Android) - if: matrix.android - run: | - docker run --rm --platform linux/arm64 termux-android:latest \ - bash -c "find /data/data/com.termux/files/usr/lib -name 'libssl*'" - - name: Run tests (Android) if: matrix.android run: | From 03dd3a6d6fa678edc1983df0b75a789e1b9d3565 Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sun, 12 Apr 2026 01:04:26 -0700 Subject: [PATCH 11/17] test: disambiguate curl-sys cache keys further --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 874fc735..ada72fa5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -107,7 +107,7 @@ jobs: uses: actions/cache@v5 with: path: packages/*/target/curl-sys - key: curl-sys-${{ matrix.os }}${{ matrix.android && '-android' || '' }} + key: curl-sys-${{ matrix.os }}-${{ runner.arch }}${{ matrix.android && '-android' || '' }} - name: Build lde # lde's own tests invoke the lde binary directly (e.g. to test CLI flags), From 6c2b7ee2511c794a127dc5283b4dd66b4a951518 Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sun, 12 Apr 2026 01:32:39 -0700 Subject: [PATCH 12/17] test(android): replace initial host build with android setup --- .github/workflows/test.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ada72fa5..15706874 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -100,8 +100,17 @@ jobs: run: brew install autoconf automake libtool - uses: lde-org/setup-lde@master + if: "!matrix.android" + with: + version: nightly + + - name: Setup lde (Android) + if: matrix.android + uses: lde-org/setup-lde@master with: version: nightly + platform: Android + arch: aarch64 - name: Cache curl-sys build uses: actions/cache@v5 @@ -113,6 +122,7 @@ jobs: # lde's own tests invoke the lde binary directly (e.g. to test CLI flags), # so we must compile a fresh binary from source before running tests. # Using the pre-installed nightly binary would miss any CLI changes in this PR. + if: "!matrix.android" run: | cd packages/lde lde compile --outfile ${{ env.OUTFILE }} @@ -155,8 +165,9 @@ jobs: docker run --rm --privileged \ --platform linux/arm64 \ -v ${{ github.workspace }}:/workspace \ + -v $HOME/.lde/lde:/workspace/lde \ -w /workspace \ -e ANDROID_NDK_ROOT=/workspace/android-ndk-r29 \ -e LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib \ termux-android:latest \ - bash -c "/workspace/packages/lde/${{ env.OUTFILE }} test" + bash -c "/workspace/lde compile --outfile packages/lde/${{ env.OUTFILE }} && /workspace/packages/lde/${{ env.OUTFILE }} test" From 1f92669977451cbb6ab65ba0deabb2fa37cb17a1 Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sun, 12 Apr 2026 01:37:03 -0700 Subject: [PATCH 13/17] test(android): run lde setup in container --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 15706874..1839b79a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -170,4 +170,4 @@ jobs: -e ANDROID_NDK_ROOT=/workspace/android-ndk-r29 \ -e LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib \ termux-android:latest \ - bash -c "/workspace/lde compile --outfile packages/lde/${{ env.OUTFILE }} && /workspace/packages/lde/${{ env.OUTFILE }} test" + bash -c "/workspace/lde --setup && /workspace/lde compile --outfile packages/lde/${{ env.OUTFILE }} && /workspace/packages/lde/${{ env.OUTFILE }} test" From f08659e03a201af5f6ef1e4081c60315cc2473b2 Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sun, 12 Apr 2026 01:41:55 -0700 Subject: [PATCH 14/17] test(android): give full path to lde --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1839b79a..e31ba796 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -170,4 +170,4 @@ jobs: -e ANDROID_NDK_ROOT=/workspace/android-ndk-r29 \ -e LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib \ termux-android:latest \ - bash -c "/workspace/lde --setup && /workspace/lde compile --outfile packages/lde/${{ env.OUTFILE }} && /workspace/packages/lde/${{ env.OUTFILE }} test" + bash -c "/workspace/lde --setup && cd /workspace/packages/lde && /workspace/lde compile --outfile /workspace/packages/lde/${{ env.OUTFILE }} && /workspace/packages/lde/${{ env.OUTFILE }} test" From 7575c8298a93a056299ac30322b3ca3b38d2f6e8 Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sun, 12 Apr 2026 01:52:20 -0700 Subject: [PATCH 15/17] build(android): update other workflows --- .github/workflows/build.yml | 59 +++++++++++++++++++++++++++++++++-- .github/workflows/nightly.yml | 21 ++++++++++++- .github/workflows/release.yml | 59 +++++++++++++++++++++++++++++++++-- 3 files changed, 134 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 846957a8..50f09ddc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,7 +21,7 @@ jobs: outfile: lde-macos-x86-64 - os: macos-15 outfile: lde-macos-aarch64 - - os: ubuntu-22.04 + - os: ubuntu-22.04-arm outfile: lde-android-aarch64 android: true @@ -76,23 +76,78 @@ jobs: shell: pwsh run: echo "SEA_CC=aarch64-w64-mingw32-clang" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + - name: Cache Android NDK + if: matrix.android + id: cache-android-ndk + uses: actions/cache@v5 + with: + path: android-ndk-r29 + key: android-ndk-r29-aarch64 + + - name: Setup Android NDK + if: matrix.android + run: | + if [[ "${{ steps.cache-android-ndk.outputs.cache-hit }}" != "true" ]]; then + wget -q https://github.com/lzhiyong/termux-ndk/releases/download/android-ndk/android-ndk-r29-aarch64.7z + 7z x android-ndk-r29-aarch64.7z -o. > /dev/null + fi + echo "ANDROID_NDK_ROOT=$PWD/android-ndk-r29" >> $GITHUB_ENV + - name: Set SEA_CC (Android) if: matrix.android - run: echo "SEA_CC=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang" >> $GITHUB_ENV + run: echo "SEA_CC=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-aarch64/bin/aarch64-linux-android21-clang" >> $GITHUB_ENV - name: Install macOS build deps if: startsWith(matrix.os, 'macos') run: brew install autoconf automake libtool - uses: lde-org/setup-lde@master + if: "!matrix.android" + with: + version: nightly + + - name: Setup lde (Android) + if: matrix.android + uses: lde-org/setup-lde@master with: version: nightly + platform: Android + arch: aarch64 + + - name: Cache curl-sys build + uses: actions/cache@v5 + with: + path: packages/*/target/curl-sys + key: curl-sys-${{ matrix.os }}-${{ runner.arch }}${{ matrix.android && '-android' || '' }} - name: Build lde + if: "!matrix.android" run: | cd packages/lde lde compile --outfile ${{ matrix.outfile }} + - name: Setup Android build image + if: matrix.android + run: | + docker run --privileged --platform linux/arm64 --name termux-build \ + -e DEBIAN_FRONTEND=noninteractive \ + termux/termux-docker:aarch64 \ + bash -c "apt update && apt upgrade -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold && apt install -y git clang curl zip make cmake autoconf automake libtool openssl perl" + docker commit termux-build termux-android:latest + docker rm termux-build + + - name: Build lde (Android) + if: matrix.android + run: | + docker run --rm --privileged \ + --platform linux/arm64 \ + -v ${{ github.workspace }}:/workspace \ + -v $HOME/.lde/lde:/workspace/lde \ + -w /workspace \ + -e ANDROID_NDK_ROOT=/workspace/android-ndk-r29 \ + termux-android:latest \ + bash -c "/workspace/lde --setup && cd /workspace/packages/lde && /workspace/lde compile --outfile /workspace/packages/lde/${{ matrix.outfile }}" + - name: Upload artifact uses: actions/upload-artifact@v7 with: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 3f3e4fc6..b77c9b47 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -110,10 +110,26 @@ jobs: run: brew install autoconf automake libtool - uses: lde-org/setup-lde@master + if: "!matrix.android" + with: + version: nightly + + - name: Setup lde (Android) + if: matrix.android + uses: lde-org/setup-lde@master with: version: nightly + platform: Android + arch: aarch64 + + - name: Cache curl-sys build + uses: actions/cache@v5 + with: + path: packages/*/target/curl-sys + key: curl-sys-${{ matrix.os }}-${{ runner.arch }}${{ matrix.android && '-android' || '' }} - name: Build lde + if: "!matrix.android" run: | cd packages/lde lde compile --outfile ${{ matrix.outfile }} @@ -156,9 +172,12 @@ jobs: docker run --rm --privileged \ --platform linux/arm64 \ -v ${{ github.workspace }}:/workspace \ + -v $HOME/.lde/lde:/workspace/lde \ -w /workspace \ + -e ANDROID_NDK_ROOT=/workspace/android-ndk-r29 \ + -e LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib \ termux-android:latest \ - bash -c "/workspace/packages/lde/${{ matrix.outfile }} test" + bash -c "/workspace/lde --setup && cd /workspace/packages/lde && /workspace/lde compile --outfile /workspace/packages/lde/${{ matrix.outfile }} && /workspace/packages/lde/${{ matrix.outfile }} test" - name: Upload nightly release asset uses: softprops/action-gh-release@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3ea4651e..7855ca23 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,7 +25,7 @@ jobs: outfile: lde-macos-x86-64 - os: macos-15 outfile: lde-macos-aarch64 - - os: ubuntu-22.04 + - os: ubuntu-22.04-arm outfile: lde-android-aarch64 android: true @@ -80,23 +80,78 @@ jobs: shell: pwsh run: echo "SEA_CC=aarch64-w64-mingw32-clang" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + - name: Cache Android NDK + if: matrix.android + id: cache-android-ndk + uses: actions/cache@v5 + with: + path: android-ndk-r29 + key: android-ndk-r29-aarch64 + + - name: Setup Android NDK + if: matrix.android + run: | + if [[ "${{ steps.cache-android-ndk.outputs.cache-hit }}" != "true" ]]; then + wget -q https://github.com/lzhiyong/termux-ndk/releases/download/android-ndk/android-ndk-r29-aarch64.7z + 7z x android-ndk-r29-aarch64.7z -o. > /dev/null + fi + echo "ANDROID_NDK_ROOT=$PWD/android-ndk-r29" >> $GITHUB_ENV + - name: Set SEA_CC (Android) if: matrix.android - run: echo "SEA_CC=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang" >> $GITHUB_ENV + run: echo "SEA_CC=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-aarch64/bin/aarch64-linux-android21-clang" >> $GITHUB_ENV - name: Install macOS build deps if: startsWith(matrix.os, 'macos') run: brew install autoconf automake libtool - uses: lde-org/setup-lde@master + if: "!matrix.android" with: version: nightly + - name: Setup lde (Android) + if: matrix.android + uses: lde-org/setup-lde@master + with: + version: nightly + platform: Android + arch: aarch64 + + - name: Cache curl-sys build + uses: actions/cache@v5 + with: + path: packages/*/target/curl-sys + key: curl-sys-${{ matrix.os }}-${{ runner.arch }}${{ matrix.android && '-android' || '' }} + - name: Build lde + if: "!matrix.android" run: | cd packages/lde lde compile --outfile ${{ matrix.outfile }} + - name: Setup Android build image + if: matrix.android + run: | + docker run --privileged --platform linux/arm64 --name termux-build \ + -e DEBIAN_FRONTEND=noninteractive \ + termux/termux-docker:aarch64 \ + bash -c "apt update && apt upgrade -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confold && apt install -y git clang curl zip make cmake autoconf automake libtool openssl perl" + docker commit termux-build termux-android:latest + docker rm termux-build + + - name: Build lde (Android) + if: matrix.android + run: | + docker run --rm --privileged \ + --platform linux/arm64 \ + -v ${{ github.workspace }}:/workspace \ + -v $HOME/.lde/lde:/workspace/lde \ + -w /workspace \ + -e ANDROID_NDK_ROOT=/workspace/android-ndk-r29 \ + termux-android:latest \ + bash -c "/workspace/lde --setup && cd /workspace/packages/lde && /workspace/lde compile --outfile /workspace/packages/lde/${{ matrix.outfile }}" + - name: Upload release asset uses: softprops/action-gh-release@v2 with: From 0b5108c0b8901ea088252cd55a345bcf21397aeb Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sun, 12 Apr 2026 02:11:32 -0700 Subject: [PATCH 16/17] build(android): fix workspace perms --- .github/workflows/build.yml | 4 ++++ .github/workflows/release.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 50f09ddc..2839f48b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -126,6 +126,10 @@ jobs: cd packages/lde lde compile --outfile ${{ matrix.outfile }} + - name: Fix workspace permissions (Android) + if: matrix.android + run: chmod -R a+rw ${{ github.workspace }} + - name: Setup Android build image if: matrix.android run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7855ca23..a4624ee1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -130,6 +130,10 @@ jobs: cd packages/lde lde compile --outfile ${{ matrix.outfile }} + - name: Fix workspace permissions (Android) + if: matrix.android + run: chmod -R a+rw ${{ github.workspace }} + - name: Setup Android build image if: matrix.android run: | From 27777d579d5116c67f87bcb918e83f9300513669 Mon Sep 17 00:00:00 2001 From: David Cruz Date: Sun, 12 Apr 2026 02:16:43 -0700 Subject: [PATCH 17/17] test(android): run all tests --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e31ba796..d330b77b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -170,4 +170,4 @@ jobs: -e ANDROID_NDK_ROOT=/workspace/android-ndk-r29 \ -e LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib \ termux-android:latest \ - bash -c "/workspace/lde --setup && cd /workspace/packages/lde && /workspace/lde compile --outfile /workspace/packages/lde/${{ env.OUTFILE }} && /workspace/packages/lde/${{ env.OUTFILE }} test" + bash -c "/workspace/lde --setup && cd /workspace/packages/lde && /workspace/lde compile --outfile /workspace/packages/lde/${{ env.OUTFILE }} && cd /workspace && /workspace/packages/lde/${{ env.OUTFILE }} test"