Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ jobs:
path: packages/*/target/deflate-sys
key: deflate-sys-${{ matrix.os }}-${{ runner.arch }}${{ matrix.android && '-android' || '' }}

- name: Cache git2-sys build
uses: actions/cache@v5
with:
path: packages/*/target/git2-sys
key: git2-sys-${{ matrix.os }}-${{ runner.arch }}${{ matrix.android && '-android' || '' }}

- name: Build lde
if: "!matrix.android"
run: |
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ jobs:
path: packages/*/target/deflate-sys
key: deflate-sys-${{ matrix.os }}-${{ runner.arch }}${{ matrix.android && '-android' || '' }}

- name: Cache git2-sys build
uses: actions/cache@v5
with:
path: packages/*/target/git2-sys
key: git2-sys-${{ matrix.os }}-${{ runner.arch }}${{ matrix.android && '-android' || '' }}

- name: Build lde
if: "!matrix.android"
run: |
Expand Down Expand Up @@ -182,6 +188,7 @@ jobs:
-w /workspace \
-e ANDROID_NDK_ROOT=/workspace/android-ndk-r29 \
-e LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib \
-e TMPDIR=/data/data/com.termux/files/usr/tmp \
termux-android:latest \
bash -c "/workspace/lde --setup && cd /workspace/packages/lde && /workspace/lde compile --outfile /workspace/packages/lde/${{ matrix.outfile }} && cd /workspace && /workspace/packages/lde/${{ matrix.outfile }} test"

Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ jobs:
path: packages/*/target/deflate-sys
key: deflate-sys-${{ matrix.os }}-${{ runner.arch }}${{ matrix.android && '-android' || '' }}

- name: Cache git2-sys build
uses: actions/cache@v5
with:
path: packages/*/target/git2-sys
key: git2-sys-${{ matrix.os }}-${{ runner.arch }}${{ matrix.android && '-android' || '' }}

- name: Build lde
if: "!matrix.android"
run: |
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@ jobs:
path: packages/*/target/deflate-sys
key: deflate-sys-${{ matrix.os }}-${{ runner.arch }}${{ matrix.android && '-android' || '' }}

- name: Cache git2-sys build
uses: actions/cache@v5
with:
path: packages/*/target/git2-sys
key: git2-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),
# so we must compile a fresh binary from source before running tests.
Expand Down Expand Up @@ -175,5 +181,6 @@ jobs:
-w /workspace \
-e ANDROID_NDK_ROOT=/workspace/android-ndk-r29 \
-e LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib \
-e TMPDIR=/data/data/com.termux/files/usr/tmp \
termux-android:latest \
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"
6 changes: 5 additions & 1 deletion packages/git/lde.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@
"name": "git",
"description": "Provides git command execution in a nice API. Requires git cli to be available.",
"version": "0.1.0",
"dependencies": { "process2": { "path": "../process2" } }
"dependencies": {
"git2-sys": {
"git": "https://github.com/lde-org/git2-sys"
}
}
}
107 changes: 67 additions & 40 deletions packages/git/src/init.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local process = require("process2")
local git2 = require("git2-sys")

local git = {}

Expand All @@ -7,82 +7,109 @@ local git = {}
---@param branch string?
---@param commit string?
function git.clone(url, dir, branch, commit)
local args = { "clone", "--recurse-submodules", url, dir }

if branch then
args[#args + 1] = "-b"
args[#args + 1] = branch
end

local code, stdout, stderr = process.exec("git", args)
if code ~= 0 then
return nil, stderr
local ok, err = pcall(function()
local repo = git2.clone(url, dir, branch)
repo:updateSubmodules()
if commit then
repo:checkout(commit)
end
repo:free()
end)
if not ok then
return nil, err
end

if commit then
return git.checkout(commit, dir)
end

return true, stdout
return true
end

---@param cwd string?
---@param ref "HEAD" | string?
function git.getCommitHash(cwd, ref)
local code, stdout, stderr = process.exec("git", { "rev-parse", ref or "HEAD" }, { cwd = cwd })
if code ~= 0 then
return nil, stderr
local ok, result = pcall(function()
local repo = git2.open(cwd or ".")
local sha = repo:revparse(ref or "HEAD")
repo:free()
return sha
end)
if not ok then
return nil, result
end

return true, string.gsub(stdout, "%s+$", "")
return true, result
end

---@param repoDir string?
function git.pull(repoDir)
local code, _, stderr = process.exec("git", { "pull" }, { cwd = repoDir })
return code == 0, stderr
local ok, err = pcall(function()
local repo = git2.open(repoDir or ".")
repo:pull()
repo:free()
end)
return ok, ok and nil or err
end

---@param dir string?
---@param bare boolean?
function git.init(dir, bare)
local args = { "init" }
if bare then
args[#args + 1] = "--bare"
end
local code, _, stderr = process.exec("git", args, { cwd = dir })
return code == 0, stderr
local ok, err = pcall(function()
local repo = git2.init(dir or ".", bare)
repo:free()
end)
return ok, ok and nil or err
end

---@param commit string
---@param repoDir string?
function git.checkout(commit, repoDir)
local code, _, stderr = process.exec("git", { "checkout", commit }, { cwd = repoDir })
return code == 0, stderr
local ok, err = pcall(function()
local repo = git2.open(repoDir or ".")
repo:checkout(commit)
repo:free()
end)
return ok, ok and nil or err
end

function git.version()
local code, stdout, stderr = process.exec("git", { "--version" })
return code == 0, stdout or stderr
local ok, v = pcall(git2.version)
return ok, ok and ("libgit2 " .. v) or v
end

---@param dir string?
function git.isInsideWorkTree(dir)
local code, _, stderr = process.exec("git", { "rev-parse", "--is-inside-work-tree" }, { cwd = dir })
return code == 0, stderr
local ok, repo = pcall(git2.open, dir or ".")
if not ok then
return false
end
local wd = repo:workdir()
repo:free()
return wd ~= nil
end

---@param remoteName string
---@param cwd string?
function git.remoteGetUrl(remoteName, cwd)
local code, stdout, stderr = process.exec("git", { "remote", "get-url", remoteName }, { cwd = cwd })
return code == 0, stdout or stderr
local ok, result = pcall(function()
local repo = git2.open(cwd or ".")
local url = repo:remoteUrl(remoteName)
repo:free()
return url
end)
if not ok then
return nil, result
end
return true, result
end

---@param cwd string?
function git.getCurrentBranch(cwd)
local code, stdout, stderr = process.exec("git", { "rev-parse", "--abbrev-ref", "HEAD" }, { cwd = cwd })
return code == 0, stdout or stderr
local ok, result = pcall(function()
local repo = git2.open(cwd or ".")
local branch = repo:currentBranch()
repo:free()
return branch
end)
if not ok then
return nil, result
end
return true, result
end

return git
12 changes: 6 additions & 6 deletions packages/lde-core/tests/main.test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -292,13 +292,13 @@ test.it("git dep: installs root package, not a sub-package, when repo has lde.js
-- instead of the root package (e.g. "lde-test").
--
-- We pre-populate the real git cache dir so getOrInitGitRepo skips cloning.
local repoDir = lde.global.getGitRepoDir("my-root-pkg")
-- Pinning a fake commit in the dep skips the getCommitHash call entirely,
-- keeping the test self-contained (no real git repo needed).
local fakeCommit = "abc1234567890abcdef1234567890abcdef123456"
local repoDir = lde.global.getGitRepoDir("my-root-pkg", nil, fakeCommit)
fs.rmdir(repoDir)
fs.mkdir(repoDir)

-- Initialize the git repo so commit info can be fetched
git.init(repoDir, true)

-- Root lde.json
fs.write(path.join(repoDir, "lde.json"), json.encode({
name = "my-root-pkg",
Expand All @@ -320,7 +320,7 @@ test.it("git dep: installs root package, not a sub-package, when repo has lde.js
fs.mkdir(path.join(subDir, "src"))
fs.write(path.join(subDir, "src", "init.lua"), "return {}")

-- App that depends on the root package via git
-- App that depends on the root package via git (commit pinned so getCommitHash is skipped)
local appDir = path.join(tmpBase, "git-dep-app")
fs.mkdir(appDir)
fs.mkdir(path.join(appDir, "src"))
Expand All @@ -329,7 +329,7 @@ test.it("git dep: installs root package, not a sub-package, when repo has lde.js
name = "git-dep-app",
version = "0.1.0",
dependencies = {
["my-root-pkg"] = { git = "https://example.com/my-root-pkg.git" }
["my-root-pkg"] = { git = "https://example.com/my-root-pkg.git", commit = fakeCommit }
}
}))

Expand Down
3 changes: 2 additions & 1 deletion packages/lde/tests/install.test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ local function makeProject(name)
return dir
end

test.it("reinstalls src.rock correctly after tar cache and target are cleared (lde.lock retained)", function()
-- TODO: re-enable once a nightly build with TMPDIR set in the Android Docker run is available
test.skipIf(env.var("ANDROID_ROOT") ~= nil)("reinstalls src.rock correctly after tar cache and target are cleared (lde.lock retained)", function()
local dir = makeProject("srcrock-reinstall-test")
fs.write(path.join(dir, "src", "init.lua"), 'print(require("socket"))')

Expand Down
9 changes: 6 additions & 3 deletions packages/lde/tests/main.test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ test.it("should not ignore --git in ldx", function()
fs.rmdir(repoDir)
end)

test.it("lde test skips packages with no tests/ directory", function()
-- TODO: re-enable once a nightly build with TMPDIR set in the Android Docker run is available
test.skipIf(env.var("ANDROID_ROOT") ~= nil)("lde test skips packages with no tests/ directory", function()
local tmpDir = path.join(env.tmpdir(), "lde-test-skip-test")
fs.rmdir(tmpDir)
fs.mkdir(tmpDir)
Expand Down Expand Up @@ -77,7 +78,8 @@ test.it("--tree overrides the global lde directory", function()
test.truthy(fs.exists(path.join(tmpTree, "git")))
end)

test.it("lde <script> <args> passes positional args to the script", function()
-- TODO: re-enable once a nightly build with TMPDIR set in the Android Docker run is available
test.skipIf(env.var("ANDROID_ROOT") ~= nil)("lde <script> <args> passes positional args to the script", function()
local script = path.join(env.tmpdir(), "lde-argtest.lua")
fs.write(script, 'io.write(arg[1] .. " " .. arg[2])')

Expand All @@ -86,7 +88,8 @@ test.it("lde <script> <args> passes positional args to the script", function()
test.includes(out, "hello world")
end)

test.it("lde <script> receives arg[0] as the script path", function()
-- TODO: re-enable once a nightly build with TMPDIR set in the Android Docker run is available
test.skipIf(env.var("ANDROID_ROOT") ~= nil)("lde <script> receives arg[0] as the script path", function()
local script = path.join(env.tmpdir(), "lde-arg0test.lua")
fs.write(script, "io.write(arg[0])")

Expand Down
Loading