refactor(wt): extract shell module

Amolith created

Assisted-by: Claude Opus 4.5 via Amp

Change summary

dist/wt          | 82 ++++++++++++++++++++++++++++++-------------------
src/main.lua     | 49 +++--------------------------
src/wt/shell.lua | 55 +++++++++++++++++++++++++++++++++
3 files changed, 110 insertions(+), 76 deletions(-)

Detailed changes

dist/wt 🔗

@@ -45,42 +45,80 @@ M.EXIT_SYSTEM_ERROR = 2
 return M
 ]]
 
-
-if _VERSION < "Lua 5.2" then
-	io.stderr:write("error: wt requires Lua 5.2 or later\n")
-	os.exit(1)
-end
+_EMBEDDED_MODULES["wt.shell"] = [[-- SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
+--
+-- SPDX-License-Identifier: GPL-3.0-or-later
 
 local exit = require("wt.exit")
-local EXIT_SUCCESS = exit.EXIT_SUCCESS
-local EXIT_USER_ERROR = exit.EXIT_USER_ERROR
-local EXIT_SYSTEM_ERROR = exit.EXIT_SYSTEM_ERROR
+
+---@class wt.shell
+local M = {}
 
 ---Execute command, return output and exit code
 ---@param cmd string
 ---@return string output
 ---@return integer code
-local function run_cmd(cmd)
+function M.run_cmd(cmd)
 	local handle = io.popen(cmd .. " 2>&1")
 	if not handle then
-		return "", EXIT_SYSTEM_ERROR
+		return "", exit.EXIT_SYSTEM_ERROR
 	end
 	local output = handle:read("*a") or ""
 	local success, _, code = handle:close()
 	if success then
 		return output, 0
 	end
-	return output, code or EXIT_SYSTEM_ERROR
+	return output, code or exit.EXIT_SYSTEM_ERROR
 end
 
 ---Execute command silently, return success boolean
 ---@param cmd string
 ---@return boolean success
-local function run_cmd_silent(cmd)
+function M.run_cmd_silent(cmd)
 	local success = os.execute(cmd .. " >/dev/null 2>&1")
 	return success == true
 end
 
+---Get current working directory
+---@return string|nil cwd
+function M.get_cwd()
+	local handle = io.popen("pwd")
+	if not handle then
+		return nil
+	end
+	local cwd = handle:read("*l")
+	handle:close()
+	return cwd
+end
+
+---Print error message and exit
+---@param msg string
+---@param code? integer
+function M.die(msg, code)
+	io.stderr:write("error: " .. msg .. "\n")
+	os.exit(code or exit.EXIT_USER_ERROR)
+end
+
+return M
+]]
+
+
+if _VERSION < "Lua 5.2" then
+	io.stderr:write("error: wt requires Lua 5.2 or later\n")
+	os.exit(1)
+end
+
+local exit = require("wt.exit")
+local EXIT_SUCCESS = exit.EXIT_SUCCESS
+local EXIT_USER_ERROR = exit.EXIT_USER_ERROR
+local EXIT_SYSTEM_ERROR = exit.EXIT_SYSTEM_ERROR
+
+local shell = require("wt.shell")
+local run_cmd = shell.run_cmd
+local run_cmd_silent = shell.run_cmd_silent
+local get_cwd = shell.get_cwd
+local die = shell.die
+
 ---Walk up from cwd looking for .git file pointing to .bare, or .bare/ directory
 ---@return string|nil root
 ---@return string|nil error
@@ -162,14 +200,6 @@ local function _extract_project_name(url) -- luacheck: ignore 211
 	return name
 end
 
----Print error message and exit
----@param msg string
----@param code? integer
-local function die(msg, code)
-	io.stderr:write("error: " .. msg .. "\n")
-	os.exit(code or EXIT_USER_ERROR)
-end
-
 ---Print usage information
 local function print_usage()
 	print("wt - git worktree manager")
@@ -368,18 +398,6 @@ local function get_default_branch()
 	return "main"
 end
 
----Get current working directory
----@return string|nil
-local function get_cwd()
-	local handle = io.popen("pwd")
-	if not handle then
-		return nil
-	end
-	local cwd = handle:read("*l")
-	handle:close()
-	return cwd
-end
-
 ---Convert branch name to worktree path
 ---@param root string
 ---@param branch string

src/main.lua 🔗

@@ -14,30 +14,11 @@ local EXIT_SUCCESS = exit.EXIT_SUCCESS
 local EXIT_USER_ERROR = exit.EXIT_USER_ERROR
 local EXIT_SYSTEM_ERROR = exit.EXIT_SYSTEM_ERROR
 
----Execute command, return output and exit code
----@param cmd string
----@return string output
----@return integer code
-local function run_cmd(cmd)
-	local handle = io.popen(cmd .. " 2>&1")
-	if not handle then
-		return "", EXIT_SYSTEM_ERROR
-	end
-	local output = handle:read("*a") or ""
-	local success, _, code = handle:close()
-	if success then
-		return output, 0
-	end
-	return output, code or EXIT_SYSTEM_ERROR
-end
-
----Execute command silently, return success boolean
----@param cmd string
----@return boolean success
-local function run_cmd_silent(cmd)
-	local success = os.execute(cmd .. " >/dev/null 2>&1")
-	return success == true
-end
+local shell = require("wt.shell")
+local run_cmd = shell.run_cmd
+local run_cmd_silent = shell.run_cmd_silent
+local get_cwd = shell.get_cwd
+local die = shell.die
 
 ---Walk up from cwd looking for .git file pointing to .bare, or .bare/ directory
 ---@return string|nil root
@@ -120,14 +101,6 @@ local function _extract_project_name(url) -- luacheck: ignore 211
 	return name
 end
 
----Print error message and exit
----@param msg string
----@param code? integer
-local function die(msg, code)
-	io.stderr:write("error: " .. msg .. "\n")
-	os.exit(code or EXIT_USER_ERROR)
-end
-
 ---Print usage information
 local function print_usage()
 	print("wt - git worktree manager")
@@ -326,18 +299,6 @@ local function get_default_branch()
 	return "main"
 end
 
----Get current working directory
----@return string|nil
-local function get_cwd()
-	local handle = io.popen("pwd")
-	if not handle then
-		return nil
-	end
-	local cwd = handle:read("*l")
-	handle:close()
-	return cwd
-end
-
 ---Convert branch name to worktree path
 ---@param root string
 ---@param branch string

src/wt/shell.lua 🔗

@@ -0,0 +1,55 @@
+-- SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
+--
+-- SPDX-License-Identifier: GPL-3.0-or-later
+
+local exit = require("wt.exit")
+
+---@class wt.shell
+local M = {}
+
+---Execute command, return output and exit code
+---@param cmd string
+---@return string output
+---@return integer code
+function M.run_cmd(cmd)
+	local handle = io.popen(cmd .. " 2>&1")
+	if not handle then
+		return "", exit.EXIT_SYSTEM_ERROR
+	end
+	local output = handle:read("*a") or ""
+	local success, _, code = handle:close()
+	if success then
+		return output, 0
+	end
+	return output, code or exit.EXIT_SYSTEM_ERROR
+end
+
+---Execute command silently, return success boolean
+---@param cmd string
+---@return boolean success
+function M.run_cmd_silent(cmd)
+	local success = os.execute(cmd .. " >/dev/null 2>&1")
+	return success == true
+end
+
+---Get current working directory
+---@return string|nil cwd
+function M.get_cwd()
+	local handle = io.popen("pwd")
+	if not handle then
+		return nil
+	end
+	local cwd = handle:read("*l")
+	handle:close()
+	return cwd
+end
+
+---Print error message and exit
+---@param msg string
+---@param code? integer
+function M.die(msg, code)
+	io.stderr:write("error: " .. msg .. "\n")
+	os.exit(code or exit.EXIT_USER_ERROR)
+end
+
+return M