#274 cleanup functionality added to installer

This commit is contained in:
Mikayla Fischler
2023-07-16 19:42:20 -04:00
parent e1b4d72ef8
commit 2a541ef3fe
2 changed files with 112 additions and 44 deletions

154
ccmsi.lua
View File

@ -20,7 +20,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
local function println(message) print(tostring(message)) end local function println(message) print(tostring(message)) end
local function print(message) term.write(tostring(message)) end local function print(message) term.write(tostring(message)) end
local CCMSI_VERSION = "v1.5a" local CCMSI_VERSION = "v1.6"
local install_dir = "/.install-cache" local install_dir = "/.install-cache"
local manifest_path = "https://mikaylafischler.github.io/cc-mek-scada/manifests/" local manifest_path = "https://mikaylafischler.github.io/cc-mek-scada/manifests/"
@ -56,13 +56,13 @@ local function ask_y_n(question, default)
end end
-- print out a white + blue text message -- print out a white + blue text message
local function pkg_message(message, package) white(); print(message .. " "); blue(); println(package); white() end local function pkg_message(message, package) white();print(message .. " ");blue();println(package);white() end
-- indicate actions to be taken based on package differences for installs/updates -- indicate actions to be taken based on package differences for installs/updates
local function show_pkg_change(name, v_local, v_remote) local function show_pkg_change(name, v_local, v_remote)
if v_local ~= nil then if v_local ~= nil then
if v_local ~= v_remote then if v_local ~= v_remote then
print("[" .. name .. "] updating "); blue(); print(v_local); white(); print(" \xbb "); blue(); println(v_remote); white() print("[" .. name .. "] updating ");blue();print(v_local);white();print(" \xbb ");blue();println(v_remote);white()
elseif mode == "install" then elseif mode == "install" then
pkg_message("[" .. name .. "] reinstalling", v_local) pkg_message("[" .. name .. "] reinstalling", v_local)
end end
@ -87,15 +87,13 @@ end
local function get_remote_manifest() local function get_remote_manifest()
local response, error = http.get(install_manifest) local response, error = http.get(install_manifest)
if response == nil then if response == nil then
orange(); println("failed to get installation manifest from GitHub, cannot update or install") orange();println("failed to get installation manifest from GitHub, cannot update or install")
red(); println("HTTP error: " .. error); white() red();println("HTTP error: " .. error);white()
return false, {} return false, {}
end end
local ok, manifest = pcall(function () return textutils.unserializeJSON(response.readAll()) end) local ok, manifest = pcall(function () return textutils.unserializeJSON(response.readAll()) end)
if not ok then if not ok then red();println("error parsing remote installation manifest");white() end
red(); println("error parsing remote installation manifest"); white()
end
return ok, manifest return ok, manifest
end end
@ -107,7 +105,7 @@ local function write_install_manifest(manifest, dependencies)
local is_dependency = false local is_dependency = false
for _, dependency in pairs(dependencies) do for _, dependency in pairs(dependencies) do
if (key == "bootloader" and dependency == "system") or key == dependency then if (key == "bootloader" and dependency == "system") or key == dependency then
is_dependency = true; break is_dependency = true;break
end end
end end
if key == app or key == "comms" or is_dependency then versions[key] = value end if key == app or key == "comms" or is_dependency then versions[key] = value end
@ -120,6 +118,73 @@ local function write_install_manifest(manifest, dependencies)
imfile.close() imfile.close()
end end
-- recursively build a tree out of the file manifest
local function gen_tree(manifest)
local function _tree_add(tree, split)
if #split > 1 then
local name = table.remove(split, 1)
if tree[name] == nil then tree[name] = {} end
table.insert(tree[name], _tree_add(tree[name], split))
else return split[1] end
return nil
end
local list, tree = {}, {}
-- make a list of each and every file
for _, files in pairs(manifest.files) do for i = 1, #files do table.insert(list, files[i]) end end
for i = 1, #list do
local split = {}
string.gsub(list[i], "([^/]+)", function(c) split[#split + 1] = c end)
if #split == 1 then table.insert(tree, list[i])
else table.insert(tree, _tree_add(tree, split)) end
end
return tree
end
local function _in_array(val, array)
for _, v in pairs(array) do if v == val then return true end end
return false
end
local function _clean_dir(dir, tree)
local ls = fs.list(dir)
for _, val in pairs(ls) do
local path = dir.."/"..val
if fs.isDir(path) then
_clean_dir(path, tree[val])
if #fs.list(path) == 0 then
fs.delete(path);red();println("deleted dir " .. path);white()
end
elseif not _in_array(val, tree) then
fs.delete(val)
red();println("deleted " .. path);white()
end
end
end
-- go through app/common directories to delete unused files
local function clean(manifest)
local root_ext = false
local tree = gen_tree(manifest)
table.insert(tree, "install_manifest.json")
table.insert(tree, "ccmsi.lua")
table.insert(tree, "log.txt")
local ls = fs.list("/")
for _, val in pairs(ls) do
if fs.isDir(val) then
if tree[val] ~= nil then _clean_dir("/" .. val, tree[val]) end
if #fs.list(val) == 0 then fs.delete(val) end
elseif not _in_array(val, tree) then
root_ext = true
yellow();println(val .. " not used");white()
end
end
if root_ext then println("Files in root directory won't be automatically deleted.") end
end
-- get and validate command line options -- get and validate command line options
println("-- CC Mekanism SCADA Installer " .. CCMSI_VERSION .. " --") println("-- CC Mekanism SCADA Installer " .. CCMSI_VERSION .. " --")
@ -136,33 +201,33 @@ if #opts == 0 or opts[1] == "help" then
println(" update - update files EXCEPT for config/logs") println(" update - update files EXCEPT for config/logs")
println(" remove - delete files EXCEPT for config/logs") println(" remove - delete files EXCEPT for config/logs")
println(" purge - delete files INCLUDING config/logs") println(" purge - delete files INCLUDING config/logs")
white(); println("<app>"); lgray() white();println("<app>");lgray()
println(" reactor-plc - reactor PLC firmware") println(" reactor-plc - reactor PLC firmware")
println(" rtu - RTU firmware") println(" rtu - RTU firmware")
println(" supervisor - supervisor server application") println(" supervisor - supervisor server application")
println(" coordinator - coordinator application") println(" coordinator - coordinator application")
println(" pocket - pocket application") println(" pocket - pocket application")
white(); println("<branch>"); yellow() white();println("<branch>");yellow()
println(" second parameter when used with check") println(" second parameter when used with check")
lgray(); println(" main (default) | latest | devel"); white() lgray();println(" main (default) | latest | devel");white()
return return
else else
mode = get_opt(opts[1], { "check", "install", "update", "remove", "purge" }) mode = get_opt(opts[1], { "check", "install", "update", "remove", "purge" })
if mode == nil then if mode == nil then
red(); println("Unrecognized mode."); white() red();println("Unrecognized mode.");white()
return return
end end
app = get_opt(opts[2], { "reactor-plc", "rtu", "supervisor", "coordinator", "pocket" }) app = get_opt(opts[2], { "reactor-plc", "rtu", "supervisor", "coordinator", "pocket" })
if app == nil and mode ~= "check" then if app == nil and mode ~= "check" then
red(); println("Unrecognized application."); white() red();println("Unrecognized application.");white()
return return
end end
-- determine target -- determine target
if mode == "check" then target = opts[2] else target = opts[3] end if mode == "check" then target = opts[2] else target = opts[3] end
if (target ~= "main") and (target ~= "latest") and (target ~= "devel") then if (target ~= "main") and (target ~= "latest") and (target ~= "devel") then
if (target and target ~= "") then yellow(); println("Unknown target, defaulting to 'main'"); white() end if (target and target ~= "") then yellow();println("Unknown target, defaulting to 'main'");white() end
target = "main" target = "main"
end end
@ -179,7 +244,7 @@ if mode == "check" then
local local_ok, local_manifest = read_local_manifest() local local_ok, local_manifest = read_local_manifest()
if not local_ok then if not local_ok then
yellow(); println("failed to load local installation information"); white() yellow();println("failed to load local installation information");white()
local_manifest = { versions = { installer = CCMSI_VERSION } } local_manifest = { versions = { installer = CCMSI_VERSION } }
else else
local_manifest.versions.installer = CCMSI_VERSION local_manifest.versions.installer = CCMSI_VERSION
@ -190,16 +255,16 @@ if mode == "check" then
term.setTextColor(colors.purple) term.setTextColor(colors.purple)
print(string.format("%-14s", "[" .. key .. "]")) print(string.format("%-14s", "[" .. key .. "]"))
if key == "installer" or (local_ok and (local_manifest.versions[key] ~= nil)) then if key == "installer" or (local_ok and (local_manifest.versions[key] ~= nil)) then
blue(); print(local_manifest.versions[key]) blue();print(local_manifest.versions[key])
if value ~= local_manifest.versions[key] then if value ~= local_manifest.versions[key] then
white(); print(" (") white();print(" (")
term.setTextColor(colors.cyan) term.setTextColor(colors.cyan)
print(value); white(); println(" available)") print(value);white();println(" available)")
else green(); println(" (up to date)") end else green();println(" (up to date)") end
else else
lgray(); print("not installed"); white(); print(" (latest ") lgray();print("not installed");white();print(" (latest ")
term.setTextColor(colors.cyan) term.setTextColor(colors.cyan)
print(value); white(); println(")") print(value);white();println(")")
end end
end end
elseif mode == "install" or mode == "update" then elseif mode == "install" or mode == "update" then
@ -218,7 +283,7 @@ elseif mode == "install" or mode == "update" then
local local_ok, local_manifest = read_local_manifest() local local_ok, local_manifest = read_local_manifest()
if not local_ok then if not local_ok then
if mode == "update" then if mode == "update" then
red(); println("failed to load local installation information, cannot update"); white() red();println("failed to load local installation information, cannot update");white()
return return
end end
else else
@ -229,13 +294,13 @@ elseif mode == "install" or mode == "update" then
ver.lockbox.v_local = local_manifest.versions.lockbox ver.lockbox.v_local = local_manifest.versions.lockbox
if local_manifest.versions[app] == nil then if local_manifest.versions[app] == nil then
red(); println("another application is already installed, please purge it before installing a new application"); white() red();println("another application is already installed, please purge it before installing a new application");white()
return return
end end
local_manifest.versions.installer = CCMSI_VERSION local_manifest.versions.installer = CCMSI_VERSION
if manifest.versions.installer ~= CCMSI_VERSION then if manifest.versions.installer ~= CCMSI_VERSION then
yellow(); println("a newer version of the installer is available, it is recommended to download it"); white() yellow();println("a newer version of the installer is available, it is recommended to download it");white()
end end
end end
@ -265,7 +330,7 @@ elseif mode == "install" or mode == "update" then
show_pkg_change("comms", ver.comms.v_local, ver.comms.v_remote) show_pkg_change("comms", ver.comms.v_local, ver.comms.v_remote)
ver.comms.changed = ver.comms.v_local ~= ver.comms.v_remote ver.comms.changed = ver.comms.v_local ~= ver.comms.v_remote
if ver.comms.changed and ver.comms.v_local ~= nil then if ver.comms.changed and ver.comms.v_local ~= nil then
print("[comms] "); yellow(); println("other devices on the network will require an update"); white() print("[comms] ");yellow();println("other devices on the network will require an update");white()
end end
-- display graphics version change information -- display graphics version change information
@ -302,7 +367,7 @@ elseif mode == "install" or mode == "update" then
-- check space constraints -- check space constraints
if space_available < space_required then if space_available < space_required then
single_file_mode = true single_file_mode = true
yellow(); println("WARNING: Insufficient space available for a full download!"); white() yellow();println("WARNING: Insufficient space available for a full download!");white()
println("Files can be downloaded one by one, so if you are replacing a current install this will not be a problem unless installation fails.") println("Files can be downloaded one by one, so if you are replacing a current install this will not be a problem unless installation fails.")
if mode == "update" then println("If installation still fails, delete this device's log file or uninstall the app (not purge) and try again.") end if mode == "update" then println("If installation still fails, delete this device's log file or uninstall the app (not purge) and try again.") end
if not ask_y_n("Do you wish to continue?", false) then if not ask_y_n("Do you wish to continue?", false) then
@ -343,7 +408,7 @@ elseif mode == "install" or mode == "update" then
local dl, err = http.get(repo_path .. file) local dl, err = http.get(repo_path .. file)
if dl == nil then if dl == nil then
red(); println("GET HTTP Error " .. err) red();println("GET HTTP Error " .. err)
success = false success = false
break break
else else
@ -384,10 +449,12 @@ elseif mode == "install" or mode == "update" then
if mode == "install" then if mode == "install" then
println("Installation completed successfully.") println("Installation completed successfully.")
else println("Update completed successfully.") end else println("Update completed successfully.") end
println("Ready to clean up unused files, press enter to continue...")
read();clean(manifest)
else else
if mode == "install" then if mode == "install" then
red(); println("Installation failed.") red();println("Installation failed.")
else orange(); println("Update failed, existing files unmodified.") end else orange();println("Update failed, existing files unmodified.") end
end end
else else
-- go through all files and replace one by one -- go through all files and replace one by one
@ -405,7 +472,7 @@ elseif mode == "install" or mode == "update" then
local dl, err = http.get(repo_path .. file) local dl, err = http.get(repo_path .. file)
if dl == nil then if dl == nil then
red(); println("GET HTTP Error " .. err) red();println("GET HTTP Error " .. err)
success = false success = false
break break
else else
@ -424,6 +491,8 @@ elseif mode == "install" or mode == "update" then
if mode == "install" then if mode == "install" then
println("Installation completed successfully.") println("Installation completed successfully.")
else println("Update completed successfully.") end else println("Update completed successfully.") end
println("Ready to clean up unused files, press enter to continue...")
read();clean(manifest)
else else
red() red()
if mode == "install" then if mode == "install" then
@ -434,10 +503,10 @@ elseif mode == "install" or mode == "update" then
elseif mode == "remove" or mode == "purge" then elseif mode == "remove" or mode == "purge" then
local ok, manifest = read_local_manifest() local ok, manifest = read_local_manifest()
if not ok then if not ok then
red(); println("Error parsing local installation manifest."); white() red();println("Error parsing local installation manifest.");white()
return return
elseif mode == "remove" and manifest.versions[app] == nil then elseif mode == "remove" and manifest.versions[app] == nil then
red(); println(app .. " is not installed, cannot remove."); white() red();println(app .. " is not installed, cannot remove.");white()
return return
end end
@ -451,6 +520,9 @@ elseif mode == "remove" or mode == "purge" then
-- ask for confirmation -- ask for confirmation
if not ask_y_n("Continue?", false) then return end if not ask_y_n("Continue?", false) then return end
-- delete unused files first
clean(manifest)
local file_list = manifest.files local file_list = manifest.files
local dependencies = manifest.depends[app] local dependencies = manifest.depends[app]
local config_file = app .. "/config.lua" local config_file = app .. "/config.lua"
@ -469,9 +541,9 @@ elseif mode == "remove" or mode == "purge" then
end) end)
if not log_deleted then if not log_deleted then
red(); println("failed to delete log file") red();println("failed to delete log file")
white(); println("press enter to continue...") white();println("press enter to continue...")
read(); lgray() read();lgray()
end end
end end
@ -480,10 +552,7 @@ elseif mode == "remove" or mode == "purge" then
local files = file_list[dependency] local files = file_list[dependency]
for _, file in pairs(files) do for _, file in pairs(files) do
if mode == "purge" or file ~= config_file then if mode == "purge" or file ~= config_file then
if fs.exists(file) then if fs.exists(file) then fs.delete(file);println("deleted " .. file) end
fs.delete(file)
println("deleted " .. file)
end
end end
end end
@ -508,8 +577,7 @@ elseif mode == "remove" or mode == "purge" then
end end
if folder ~= app and fs.isDir(folder) then if folder ~= app and fs.isDir(folder) then
fs.delete(folder) fs.delete(folder);println("deleted app subdirectory " .. folder)
println("deleted app subdirectory " .. folder)
end end
end end
end end
@ -527,7 +595,7 @@ elseif mode == "remove" or mode == "purge" then
imfile.close() imfile.close()
end end
green(); println("Done!") green();println("Done!")
end end
white() white()

File diff suppressed because one or more lines are too long