1
0
forked from a/repotool
repotool/src/git.lua
2025-07-06 12:57:04 -05:00

151 lines
4.3 KiB
Lua

local cmd = require("cmd")
local git = {}
-- Parse a git URL into domain and path components
function git.parse_url(url)
local domain, path
-- Check if it's an HTTP(S) URL
-- First try without authentication
domain, path = url:match("^https?://([^@/]+)/(.+)%.git$")
if not domain then
domain, path = url:match("^https?://([^@/]+)/(.+)$")
end
-- If that didn't match, try with authentication
if not domain then
domain, path = url:match("^https?://[^@]+@([^/]+)/(.+)%.git$")
end
if not domain then
domain, path = url:match("^https?://[^@]+@([^/]+)/(.+)$")
end
-- Check if it's an SSH URL (git@host:path or ssh://...)
if not domain then
domain, path = url:match("^[^@]+@([^:]+):(.+)%.git$")
end
if not domain then
domain, path = url:match("^[^@]+@([^:]+):(.+)$")
end
if not domain then
domain, path = url:match("^ssh://[^@]*@?([^/]+)/(.+)%.git$")
end
if not domain then
domain, path = url:match("^ssh://[^@]*@?([^/]+)/(.+)$")
end
-- Check if it's a bare domain path (e.g., gfx.cafe/oku/trade)
if not domain then
domain, path = url:match("^([^/]+%.%w+)/(.+)$")
end
return domain, path
end
-- Get domain and path from current git repository's origin
function git.parse_origin()
local origin_url = cmd.read_stdout("git config --get remote.origin.url")
origin_url = origin_url:gsub("\n", "")
if origin_url == "" then
return nil, nil
end
return git.parse_url(origin_url)
end
-- Validate if a URL is a valid git repository URL
function git.valid_url(url)
if url:match("^https?://") then
return 1 -- HTTP(S)
elseif url:match("^[^:]+@[^:]+:") or url:match("^ssh://") then
return 2 -- SSH
elseif url:match("^[^/]+%.%w+/[^/]+") then
return 3 -- Bare domain path
else
return -1 -- Invalid
end
end
-- Execute command and return output
function git.execute(command)
return cmd.read(command)
end
-- Check if we're in a git repository
function git.in_repo()
local _, success = git.execute("git rev-parse --git-dir")
return success
end
-- Get repository root
function git.get_repo_root()
local output, success = git.execute("git rev-parse --show-toplevel")
if success then
return output:gsub("\n", "")
end
return nil
end
-- Get git common directory (for worktree detection)
function git.get_common_dir()
local output, success = git.execute("git rev-parse --git-common-dir")
if success then
return output:gsub("\n", "")
end
return nil
end
-- Get list of all worktrees with their properties
function git.worktree_list()
local worktrees = {}
local output = cmd.read_stdout("git worktree list --porcelain")
local current_worktree = nil
for line in output:gmatch("[^\n]+") do
local worktree_path = line:match("^worktree (.+)$")
if worktree_path then
-- Save previous worktree if any
if current_worktree then
table.insert(worktrees, current_worktree)
end
-- Start new worktree
current_worktree = {
path = worktree_path,
head = nil,
branch = nil,
bare = false,
detached = false,
locked = false,
prunable = false
}
elseif current_worktree then
-- Parse other worktree properties
local head = line:match("^HEAD (.+)$")
if head then
current_worktree.head = head
elseif line:match("^branch (.+)$") then
current_worktree.branch = line:match("^branch (.+)$")
elseif line == "bare" then
current_worktree.bare = true
elseif line == "detached" then
current_worktree.detached = true
elseif line:match("^locked") then
current_worktree.locked = true
elseif line == "prunable gitdir file points to non-existent location" then
current_worktree.prunable = true
end
end
end
-- Don't forget the last worktree
if current_worktree then
table.insert(worktrees, current_worktree)
end
return worktrees
end
return git