2023-02-19 17:54:02 +00:00
|
|
|
--
|
|
|
|
-- ComputerCraft Mekanism SCADA System Installer Utility
|
|
|
|
--
|
|
|
|
|
|
|
|
--[[
|
|
|
|
|
|
|
|
Copyright © 2023 Mikayla Fischler
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
|
|
associated documentation files (the “Software”), to deal in the Software without restriction,
|
|
|
|
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
|
|
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
|
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
|
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
]]--
|
|
|
|
|
2023-02-19 17:56:53 +00:00
|
|
|
local function println(message) print(tostring(message)) end
|
|
|
|
local function print(message) term.write(tostring(message)) end
|
2023-02-19 17:54:02 +00:00
|
|
|
|
2023-02-20 00:56:12 +00:00
|
|
|
local VERSION = "v0.8b"
|
2023-02-19 17:54:02 +00:00
|
|
|
|
|
|
|
local install_dir = "/.install-cache"
|
|
|
|
local repo_path = "http://raw.githubusercontent.com/MikaylaFischler/cc-mek-scada/devel/"
|
|
|
|
local install_manifest = repo_path .. "install_manifest.json"
|
|
|
|
|
|
|
|
local opts = { ... }
|
|
|
|
local mode = nil
|
|
|
|
local app = nil
|
|
|
|
|
2023-02-20 00:56:12 +00:00
|
|
|
-- record the local installation manifest
|
|
|
|
---@param manifest table
|
|
|
|
---@param dependencies table
|
2023-02-20 00:14:47 +00:00
|
|
|
local function write_install_manifest(manifest, dependencies)
|
|
|
|
local versions = {}
|
|
|
|
for key, value in pairs(manifest.versions) do
|
|
|
|
local is_dependency = false
|
|
|
|
for _, dependency in pairs(dependencies) do
|
|
|
|
if key == "bootloader" and dependency == "system" then
|
|
|
|
is_dependency = true
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-02-20 00:56:12 +00:00
|
|
|
if key == app or key == "comms" or is_dependency then
|
2023-02-20 00:14:47 +00:00
|
|
|
versions[key] = value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
manifest.versions = versions
|
|
|
|
|
|
|
|
local imfile = fs.open("install_manifest.json", "w")
|
|
|
|
imfile.write(textutils.serializeJSON(manifest))
|
|
|
|
imfile.close()
|
|
|
|
end
|
|
|
|
|
2023-02-19 17:54:02 +00:00
|
|
|
--
|
|
|
|
-- get and validate command line options
|
|
|
|
--
|
|
|
|
|
|
|
|
println("-- CC Mekanism SCADA Installer " .. VERSION .. " --")
|
|
|
|
|
2023-02-20 00:56:12 +00:00
|
|
|
if #opts == 0 or opts[1] == "help" then
|
2023-02-19 17:54:02 +00:00
|
|
|
println("note: only modifies files that are part of the device application")
|
2023-02-20 00:30:03 +00:00
|
|
|
println("usage: ccmsi <mode> <app>")
|
2023-02-19 17:54:02 +00:00
|
|
|
println("<mode>")
|
2023-02-20 00:30:03 +00:00
|
|
|
println(" check - check latest versions avilable")
|
2023-02-19 17:54:02 +00:00
|
|
|
println(" install - fresh install, overwrites config")
|
|
|
|
println(" update - update files EXCEPT for config/logs")
|
|
|
|
println(" remove - delete files EXCEPT for config/logs")
|
|
|
|
println(" purge - delete files INCLUDING config/logs")
|
|
|
|
println("<app>")
|
|
|
|
println(" reactor-plc - reactor PLC firmware")
|
|
|
|
println(" rtu - RTU firmware")
|
|
|
|
println(" supervisor - supervisor server application")
|
|
|
|
println(" coordinator - coordinator application")
|
|
|
|
println(" pocket - pocket application")
|
|
|
|
return
|
|
|
|
else
|
2023-02-20 00:41:32 +00:00
|
|
|
for _, v in pairs({ "check", "install", "update", "remove", "purge" }) do
|
2023-02-19 17:54:02 +00:00
|
|
|
if opts[1] == v then
|
|
|
|
mode = v
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if mode == nil then
|
|
|
|
println("unrecognized mode")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
for _, v in pairs({ "reactor-plc", "rtu", "supervisor", "coordinator", "pocket" }) do
|
|
|
|
if opts[2] == v then
|
|
|
|
app = v
|
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2023-02-20 00:41:32 +00:00
|
|
|
if app == nil and mode ~= "check" then
|
2023-02-19 17:54:02 +00:00
|
|
|
println("unrecognized application")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--
|
|
|
|
-- run selected mode
|
|
|
|
--
|
|
|
|
|
2023-02-20 00:30:03 +00:00
|
|
|
if mode == "check" then
|
2023-02-19 17:54:02 +00:00
|
|
|
-------------------------
|
|
|
|
-- GET REMOTE MANIFEST --
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
local response, error = http.get(install_manifest)
|
|
|
|
|
|
|
|
if response == nil then
|
2023-02-20 00:41:32 +00:00
|
|
|
term.setTextColor(colors.red)
|
2023-02-19 17:54:02 +00:00
|
|
|
println("failed to get installation manifest from GitHub, cannot update or install")
|
2023-02-19 17:56:53 +00:00
|
|
|
println("http error " .. error)
|
2023-02-20 00:41:32 +00:00
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 17:54:02 +00:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local ok, manifest = pcall(function () return textutils.unserializeJSON(response.readAll()) end)
|
|
|
|
|
|
|
|
if not ok then
|
2023-02-20 00:30:03 +00:00
|
|
|
term.setTextColor(colors.red)
|
2023-02-19 23:49:04 +00:00
|
|
|
println("error parsing remote installation manifest")
|
2023-02-20 00:30:03 +00:00
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 17:54:02 +00:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
------------------------
|
|
|
|
-- GET LOCAL MANIFEST --
|
|
|
|
------------------------
|
|
|
|
|
2023-02-19 22:15:26 +00:00
|
|
|
local imfile = fs.open("install_manifest.json", "r")
|
|
|
|
local local_ok = false
|
|
|
|
local local_manifest = {}
|
|
|
|
|
|
|
|
if imfile ~= nil then
|
|
|
|
local_ok, local_manifest = pcall(function () return textutils.unserializeJSON(imfile.readAll()) end)
|
|
|
|
imfile.close()
|
|
|
|
end
|
2023-02-19 17:54:02 +00:00
|
|
|
|
2023-02-20 00:30:03 +00:00
|
|
|
if not local_ok then
|
|
|
|
term.setTextColor(colors.yellow)
|
|
|
|
println("warning: failed to load local installation information")
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
end
|
|
|
|
|
|
|
|
for key, value in pairs(manifest.versions) do
|
2023-02-20 00:56:12 +00:00
|
|
|
term.setTextColor(colors.purple)
|
|
|
|
print(string.format("%-14s", "[" .. key .. "]"))
|
2023-02-20 00:30:03 +00:00
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
print(value)
|
2023-02-20 00:56:12 +00:00
|
|
|
if local_ok and (local_manifest.versions[key] ~= nil) then
|
|
|
|
term.setTextColor(colors.white)
|
2023-02-20 00:30:03 +00:00
|
|
|
print(" (current ")
|
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
print(value)
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
println(")")
|
|
|
|
else
|
2023-02-20 00:56:12 +00:00
|
|
|
term.setTextColor(colors.lightGray)
|
2023-02-20 00:30:03 +00:00
|
|
|
println(" (not installed)")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
elseif mode == "install" or mode == "update" then
|
|
|
|
-------------------------
|
|
|
|
-- GET REMOTE MANIFEST --
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
local response, error = http.get(install_manifest)
|
|
|
|
|
|
|
|
if response == nil then
|
|
|
|
term.setTextColor(colors.red)
|
|
|
|
println("failed to get installation manifest from GitHub, cannot update or install")
|
|
|
|
println("http error " .. error)
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local ok, manifest = pcall(function () return textutils.unserializeJSON(response.readAll()) end)
|
|
|
|
|
|
|
|
if not ok then
|
|
|
|
term.setTextColor(colors.red)
|
|
|
|
println("error parsing remote installation manifest")
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
end
|
|
|
|
|
|
|
|
------------------------
|
|
|
|
-- GET LOCAL MANIFEST --
|
|
|
|
------------------------
|
|
|
|
|
|
|
|
local imfile = fs.open("install_manifest.json", "r")
|
|
|
|
local local_ok = false
|
|
|
|
local local_manifest = {}
|
|
|
|
|
|
|
|
if imfile ~= nil then
|
|
|
|
local_ok, local_manifest = pcall(function () return textutils.unserializeJSON(imfile.readAll()) end)
|
|
|
|
imfile.close()
|
|
|
|
end
|
|
|
|
|
2023-02-19 17:54:02 +00:00
|
|
|
local local_app_version = nil
|
|
|
|
local local_comms_version = nil
|
|
|
|
local local_boot_version = nil
|
|
|
|
|
2023-02-20 00:18:06 +00:00
|
|
|
if not local_ok then
|
|
|
|
if mode == "update" then
|
|
|
|
term.setTextColor(colors.yellow)
|
|
|
|
println("warning: failed to load local installation information")
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
end
|
|
|
|
else
|
2023-02-19 17:54:02 +00:00
|
|
|
local_app_version = local_manifest.versions[app]
|
|
|
|
local_comms_version = local_manifest.versions.comms
|
|
|
|
local_boot_version = local_manifest.versions.bootloader
|
2023-02-20 00:18:06 +00:00
|
|
|
|
|
|
|
if local_manifest.versions[app] == nil then
|
|
|
|
term.setTextColor(colors.red)
|
|
|
|
println("another application is already installed, please purge it before installing a new application")
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
return
|
|
|
|
end
|
2023-02-19 17:54:02 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
local remote_app_version = manifest.versions[app]
|
|
|
|
local remote_comms_version = manifest.versions.comms
|
|
|
|
local remote_boot_version = manifest.versions.bootloader
|
|
|
|
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.green)
|
2023-02-19 17:54:02 +00:00
|
|
|
if mode == "install" then
|
|
|
|
println("installing " .. app .. " files...")
|
|
|
|
elseif mode == "update" then
|
|
|
|
println("updating " .. app .. " files... (keeping old config.lua)")
|
|
|
|
end
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 17:54:02 +00:00
|
|
|
|
|
|
|
if local_boot_version ~= nil then
|
|
|
|
if local_boot_version ~= remote_boot_version then
|
2023-02-19 22:15:26 +00:00
|
|
|
print("[bootldr] updating ")
|
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
print(local_boot_version)
|
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 23:49:04 +00:00
|
|
|
print(" \xbb ")
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
println(remote_boot_version)
|
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 17:54:02 +00:00
|
|
|
end
|
|
|
|
else
|
2023-02-19 23:49:04 +00:00
|
|
|
print("[bootldr] new install of ")
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
println(remote_boot_version)
|
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 17:54:02 +00:00
|
|
|
end
|
|
|
|
|
2023-02-19 23:49:04 +00:00
|
|
|
if local_app_version ~= nil then
|
|
|
|
if local_app_version ~= remote_app_version then
|
|
|
|
print("[" .. app .. "] updating ")
|
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
print(local_app_version)
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
print(" \xbb ")
|
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
println(remote_app_version)
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
end
|
|
|
|
else
|
2023-02-20 00:14:47 +00:00
|
|
|
print("[" .. app .. "] new install of ")
|
2023-02-19 23:52:21 +00:00
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
println(remote_app_version)
|
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 23:49:04 +00:00
|
|
|
end
|
|
|
|
|
2023-02-19 17:54:02 +00:00
|
|
|
if local_comms_version ~= nil then
|
|
|
|
if local_comms_version ~= remote_comms_version then
|
2023-02-19 22:15:26 +00:00
|
|
|
print("[comms] updating ")
|
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
print(local_comms_version)
|
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 23:49:04 +00:00
|
|
|
print(" \xbb ")
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
println(remote_comms_version)
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
|
|
|
|
print("[comms] ")
|
|
|
|
term.setTextColor(colors.yellow)
|
|
|
|
println("other devices on the network will require an update")
|
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 17:54:02 +00:00
|
|
|
end
|
|
|
|
else
|
2023-02-19 23:49:04 +00:00
|
|
|
print("[comms] new install of ")
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
println(remote_comms_version)
|
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 17:54:02 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
--------------------------
|
|
|
|
-- START INSTALL/UPDATE --
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
local space_required = 0
|
|
|
|
local space_available = fs.getFreeSpace("/")
|
|
|
|
|
|
|
|
local single_file_mode = false
|
|
|
|
local file_list = manifest.files
|
|
|
|
local size_list = manifest.sizes
|
|
|
|
local dependencies = manifest.depends[app]
|
|
|
|
local config_file = app .. "/config.lua"
|
|
|
|
|
2023-02-19 22:15:26 +00:00
|
|
|
table.insert(dependencies, app)
|
|
|
|
|
2023-02-19 17:54:02 +00:00
|
|
|
for _, dependency in pairs(dependencies) do
|
|
|
|
local size = size_list[dependency]
|
|
|
|
space_required = space_required + size
|
|
|
|
end
|
|
|
|
|
|
|
|
if space_available < space_required then
|
|
|
|
single_file_mode = true
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.red)
|
2023-02-19 17:54:02 +00:00
|
|
|
println("WARNING: Insuffienct space available for a full download!")
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 17:54:02 +00:00
|
|
|
println("Files will be downloaded one by one, so if you are replacing a current install this will not be a problem unless installation fails.")
|
|
|
|
println("Do you wish to continue? (y/N)")
|
|
|
|
|
|
|
|
local confirm = read()
|
|
|
|
if confirm ~= "y" or confirm ~= "Y" then
|
|
|
|
println("installation cancelled")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
---@diagnostic disable-next-line: undefined-field
|
|
|
|
os.sleep(2)
|
|
|
|
|
|
|
|
local success = true
|
|
|
|
|
|
|
|
if not single_file_mode then
|
|
|
|
if fs.exists(install_dir) then
|
|
|
|
fs.delete(install_dir)
|
|
|
|
fs.makeDir(install_dir)
|
|
|
|
end
|
|
|
|
|
|
|
|
for _, dependency in pairs(dependencies) do
|
2023-02-20 00:14:47 +00:00
|
|
|
if mode == "update" and ((dependency == "system" and local_boot_version == remote_boot_version) or (local_app_version == remote_app_version)) then
|
2023-02-19 23:49:04 +00:00
|
|
|
-- skip system package if unchanged, skip app package if not changed
|
|
|
|
-- skip packages that have no version if app version didn't change
|
2023-02-19 23:52:21 +00:00
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 23:49:04 +00:00
|
|
|
print("skipping download of unchanged package ")
|
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
println(dependency)
|
|
|
|
else
|
2023-02-19 23:52:21 +00:00
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 23:49:04 +00:00
|
|
|
print("downloading package ")
|
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
println(dependency)
|
|
|
|
|
|
|
|
term.setTextColor(colors.lightGray)
|
|
|
|
local files = file_list[dependency]
|
|
|
|
for _, file in pairs(files) do
|
|
|
|
println("get: " .. file)
|
|
|
|
local dl, err_c = http.get(repo_path .. file)
|
|
|
|
|
|
|
|
if dl == nil then
|
|
|
|
term.setTextColor(colors.red)
|
|
|
|
println("get: error " .. err_c)
|
|
|
|
success = false
|
|
|
|
break
|
|
|
|
else
|
|
|
|
local handle = fs.open(install_dir .. "/" .. file, "w")
|
|
|
|
handle.write(dl.readAll())
|
|
|
|
handle.close()
|
|
|
|
end
|
2023-02-19 17:54:02 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if success then
|
|
|
|
for _, dependency in pairs(dependencies) do
|
2023-02-20 00:14:47 +00:00
|
|
|
if mode == "update" and ((dependency == "system" and local_boot_version == remote_boot_version) or (local_app_version == remote_app_version)) then
|
2023-02-19 23:49:04 +00:00
|
|
|
-- skip system package if unchanged, skip app package if not changed
|
|
|
|
-- skip packages that have no version if app version didn't change
|
2023-02-19 23:52:21 +00:00
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 23:49:04 +00:00
|
|
|
print("skipping install of unchanged package ")
|
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
println(dependency)
|
|
|
|
else
|
2023-02-19 23:52:21 +00:00
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 23:49:04 +00:00
|
|
|
print("installing package ")
|
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
println(dependency)
|
|
|
|
|
|
|
|
term.setTextColor(colors.lightGray)
|
|
|
|
local files = file_list[dependency]
|
|
|
|
for _, file in pairs(files) do
|
|
|
|
if mode == "install" or file ~= config_file then
|
|
|
|
local temp_file = install_dir .. "/" .. file
|
2023-02-19 23:52:21 +00:00
|
|
|
if fs.exists(file) then fs.delete(file) end
|
2023-02-19 23:49:04 +00:00
|
|
|
fs.move(temp_file, file)
|
|
|
|
end
|
2023-02-19 17:54:02 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
fs.delete(install_dir)
|
|
|
|
|
|
|
|
if success then
|
|
|
|
-- if we made it here, then none of the file system functions threw exceptions
|
|
|
|
-- that means everything is OK
|
2023-02-20 00:14:47 +00:00
|
|
|
write_install_manifest(manifest, dependencies)
|
|
|
|
term.setTextColor(colors.green)
|
2023-02-19 17:54:02 +00:00
|
|
|
if mode == "install" then
|
|
|
|
println("installation completed successfully")
|
|
|
|
else
|
|
|
|
println("update completed successfully")
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if mode == "install" then
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.red)
|
2023-02-19 17:54:02 +00:00
|
|
|
println("installation failed")
|
|
|
|
else
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.orange)
|
2023-02-19 17:54:02 +00:00
|
|
|
println("update failed, existing files unmodified")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
else
|
|
|
|
for _, dependency in pairs(dependencies) do
|
2023-02-20 00:14:47 +00:00
|
|
|
if mode == "update" and ((dependency == "system" and local_boot_version == remote_boot_version) or (local_app_version == remote_app_version)) then
|
2023-02-19 23:49:04 +00:00
|
|
|
-- skip system package if unchanged, skip app package if not changed
|
|
|
|
-- skip packages that have no version if app version didn't change
|
2023-02-19 23:52:21 +00:00
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 23:49:04 +00:00
|
|
|
print("skipping install of unchanged package ")
|
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
println(dependency)
|
|
|
|
else
|
2023-02-19 23:52:21 +00:00
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 23:49:04 +00:00
|
|
|
print("installing package ")
|
|
|
|
term.setTextColor(colors.blue)
|
|
|
|
println(dependency)
|
|
|
|
|
|
|
|
term.setTextColor(colors.lightGray)
|
|
|
|
local files = file_list[dependency]
|
|
|
|
for _, file in pairs(files) do
|
|
|
|
println("get: " .. file)
|
|
|
|
local dl, err_c = http.get(repo_path .. file)
|
|
|
|
|
|
|
|
if dl == nil then
|
|
|
|
println("get: error " .. err_c)
|
|
|
|
success = false
|
|
|
|
break
|
|
|
|
else
|
|
|
|
local handle = fs.open("/" .. file, "w")
|
|
|
|
handle.write(dl.readAll())
|
|
|
|
handle.close()
|
|
|
|
end
|
2023-02-19 17:54:02 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if success then
|
|
|
|
-- if we made it here, then none of the file system functions threw exceptions
|
|
|
|
-- that means everything is OK
|
2023-02-20 00:14:47 +00:00
|
|
|
write_install_manifest(manifest, dependencies)
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.green)
|
2023-02-19 17:54:02 +00:00
|
|
|
if mode == "install" then
|
|
|
|
println("installation completed successfully")
|
|
|
|
else
|
|
|
|
println("update completed successfully")
|
|
|
|
end
|
|
|
|
else
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.red)
|
2023-02-19 17:54:02 +00:00
|
|
|
if mode == "install" then
|
|
|
|
println("installation failed, files may have been skipped")
|
|
|
|
else
|
|
|
|
println("update failed, files may have been skipped")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
elseif mode == "remove" or mode == "purge" then
|
2023-02-20 00:14:47 +00:00
|
|
|
local imfile = fs.open("install_manifest.json", "r")
|
|
|
|
local ok = false
|
|
|
|
local manifest = {}
|
|
|
|
|
|
|
|
if imfile ~= nil then
|
|
|
|
ok, manifest = pcall(function () return textutils.unserializeJSON(imfile.readAll()) end)
|
|
|
|
imfile.close()
|
|
|
|
end
|
2023-02-19 17:54:02 +00:00
|
|
|
|
|
|
|
if not ok then
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.red)
|
2023-02-19 23:49:04 +00:00
|
|
|
println("error parsing local installation manifest")
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.white)
|
2023-02-19 17:54:02 +00:00
|
|
|
return
|
2023-02-20 00:14:47 +00:00
|
|
|
elseif manifest.versions[app] == nil then
|
|
|
|
term.setTextColor(colors.red)
|
|
|
|
println(app .. " is not installed")
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
return
|
2023-02-19 22:15:26 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
term.setTextColor(colors.orange)
|
|
|
|
if mode == "remove" then
|
2023-02-19 17:54:02 +00:00
|
|
|
println("removing all " .. app .. " files except for config.lua and log.txt...")
|
|
|
|
elseif mode == "purge" then
|
|
|
|
println("purging all " .. app .. " files including config.lua and log.txt...")
|
|
|
|
end
|
|
|
|
|
|
|
|
---@diagnostic disable-next-line: undefined-field
|
|
|
|
os.sleep(2)
|
|
|
|
|
|
|
|
local file_list = manifest.files
|
|
|
|
local dependencies = manifest.depends[app]
|
|
|
|
local config_file = app .. "/config.lua"
|
|
|
|
|
2023-02-19 22:15:26 +00:00
|
|
|
table.insert(dependencies, app)
|
|
|
|
|
|
|
|
term.setTextColor(colors.lightGray)
|
|
|
|
|
2023-02-19 23:49:04 +00:00
|
|
|
-- delete log file if purging
|
|
|
|
if mode == "purge" then
|
2023-02-20 00:30:03 +00:00
|
|
|
local config = require(app .. ".config")
|
2023-02-20 00:14:47 +00:00
|
|
|
if fs.exists(config.LOG_PATH) then
|
|
|
|
fs.delete(config.LOG_PATH)
|
|
|
|
println("deleted log file " .. config.LOG_PATH)
|
|
|
|
end
|
2023-02-19 23:49:04 +00:00
|
|
|
end
|
|
|
|
|
2023-02-19 17:54:02 +00:00
|
|
|
-- delete all files except config unless purging
|
|
|
|
for _, dependency in pairs(dependencies) do
|
|
|
|
local files = file_list[dependency]
|
|
|
|
for _, file in pairs(files) do
|
|
|
|
if mode == "purge" or file ~= config_file then
|
2023-02-20 00:14:47 +00:00
|
|
|
if fs.exists(file) then
|
|
|
|
fs.delete(file)
|
|
|
|
println("deleted " .. file)
|
|
|
|
end
|
2023-02-19 17:54:02 +00:00
|
|
|
end
|
|
|
|
end
|
2023-02-20 00:41:32 +00:00
|
|
|
|
|
|
|
if mode == "purge" or dependency ~= app then
|
|
|
|
local folder = files[1]
|
|
|
|
while true do
|
|
|
|
local dir = fs.getDir(folder)
|
|
|
|
if dir == "" or dir == ".." then
|
|
|
|
break
|
|
|
|
else
|
|
|
|
folder = dir
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
fs.delete(folder)
|
|
|
|
println("deleted directory " .. folder)
|
|
|
|
elseif dependency == app then
|
2023-02-20 00:56:12 +00:00
|
|
|
for _, folder in pairs(files) do
|
|
|
|
while true do
|
|
|
|
local dir = fs.getDir(folder)
|
|
|
|
if dir == "" or dir == ".." or dir == app then
|
|
|
|
break
|
|
|
|
else
|
|
|
|
folder = dir
|
|
|
|
end
|
2023-02-20 00:41:32 +00:00
|
|
|
end
|
|
|
|
|
2023-02-20 00:56:12 +00:00
|
|
|
if folder ~= app and fs.exists(folder) then
|
|
|
|
fs.delete(folder)
|
|
|
|
println("deleted app subdirectory " .. folder)
|
|
|
|
end
|
2023-02-20 00:41:32 +00:00
|
|
|
end
|
|
|
|
end
|
2023-02-19 17:54:02 +00:00
|
|
|
end
|
|
|
|
|
2023-02-20 00:14:47 +00:00
|
|
|
if mode == "purge" then
|
|
|
|
fs.delete("install_manifest.json")
|
|
|
|
println("deleted install_manifest.json")
|
|
|
|
end
|
|
|
|
|
2023-02-19 22:15:26 +00:00
|
|
|
term.setTextColor(colors.green)
|
2023-02-19 17:54:02 +00:00
|
|
|
println("done!")
|
|
|
|
end
|
2023-02-19 22:15:26 +00:00
|
|
|
|
|
|
|
term.setTextColor(colors.white)
|