Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local PROGRAM_VERSION = [["1.3"]]
- local PROGRAM_VERSION_CONVERTED = "local PROGRAM_VERSION = ".."[["..PROGRAM_VERSION.."]]"
- local PROGRAM_LINK = "1RzY7DFx"
- -- downloads and installs all Libraries and APIs, downloads any programs that the computer should have based on its label, also updates this very file - how nifty
- -- try `wget` shell command, apparently can save a url to file, is shell.wget(url, filename), works, for pastebin use raw links
- -- TODO: migrate all ["link"]'s to gitlab links, make repo public, this will avoid silly restrictions on pastebin
- -- or use pipelines to push live files to gitlab pages and collect them there via `shell.run("wget", url, filename)`
- -- TODO: change over checkVersion() & checkSelf() to wget so files can be collected from gitlab pages
- -- TODO: if api is already loaded then should reload it, as it may have been updated
- -- TODO: adds checks for remaining disk space (also check type of computer to get total diskspace, or is there a total disk space command?)
- -- TODO: add check to see if computer has a label, if not exit and ask user to label computer
- -- a list of all dependencies (libraries/apis) that wishers programs use
- local DEPENDENCIES = {
- [1] = {
- ["file"] = "wLibMining",
- ["link"] = "XkajLyXx",
- ["path"] = "wisher/"
- },
- [2] = {
- ["file"] = "wLibVariables",
- ["link"] = "FuGd7TXY",
- ["path"] = "wisher/"
- }
- }
- -- list of all programs
- -- programs are nested again to allow downloading multiple programs
- -- these programs should sit in the base directory unlike library/apis which sit in the wisher/ directory
- local COMPUTER_PROGRAMS = {
- [1] = {
- ["label"] = "stripMine",
- [1] = {
- ["file"] = "stripMine",
- ["link"] = "nVAXKrBz",
- ["autorun"] = false
- },
- [2] = {
- ["file"] = "exhaust",
- ["link"] = "HcBLDp4r",
- ["autorun"] = false
- }
- },
- [2] = {
- ["label"] = "tester",
- [1] = {
- ["file"] = "exhaust",
- ["link"] = "nVAXKrBz",
- ["autorun"] = false
- }
- },
- [3] = {
- ["label"] = "exhaust",
- [1] = {
- ["file"] = "exhaust",
- ["link"] = "nVAXKrBz",
- ["autorun"] = true
- }
- },
- [4] = {
- ["label"] = "b_unirail",
- [1] = {
- ["file"] = "botania_uniRail",
- ["link"] = "0XHwwCkU",
- ["autorun"] = true
- }
- }
- }
- -- table which stores what happened to each file during startup, used for verbose, could be used for debugging or other useful things too
- local fileStatus = {
- [1] = {
- ["type"] = "Dependencies",
- [1] = {
- ["status"] = "Fresh Download: "
- },
- [2] = {
- ["status"] = "Loaded: "
- },
- [3] = { -- in-case startup is manually executed after actual startup for some reason
- ["status"] = "Already Loaded: "
- },
- [4] = {
- ["status"] = "Updated: "
- }
- },
- [2] = { -- Programs
- ["type"] = "Programs",
- [1] = {
- ["status"] = "Fresh Download: "
- },
- [2] = {
- ["status"] = "Loaded: "
- },
- [3] = { -- in-case startup is manually executed after actual startup for some reason
- ["status"] = "Already Loaded: "
- },
- [4] = {
- ["status"] = "Updated: "
- }
- }
- }
- -- fileStatusIndexType - used to determin whether for Dependency or Programs, range 1-2 || MANUALLY SET TO VALUE REQUIRED IN FUNCTION WHICH UTILIZES
- -- fileStatusIndexStatus - used to determin whether for Downloaded, Loaded, Already Loaded or updated files range 1-4 in order
- -- fileStatusIndexFilename - needs to be logged locally for each IndexStatus
- -- set this to true if any file fails something it should succeed, e.g. loading api/lib, freshly downloading program, updating program etc.
- -- if this is true then print a message to check a log file. and open another window (unfocused) with log?? how do windows work on these computers
- -- this is set true inside logFailed() as that is only called when something fails
- local fileStatusFailed = false
- -- used to delete the log on each boot
- local logIndex = 0
- -- helper function to get a particular type of application state, and persist the default if it's not set
- function getState(type)
- local DEFAULT_STATE = 0
- local filepath = "wisher/_states/_" .. type
- if (fs.exists(filepath)) then
- local handle = fs.open(filepath, "r")
- local state = tonumber(handle.read())
- handle.close()
- return state
- else
- -- persist the default if no state has been persisted already
- return setState(type, DEFAULT_STATE)
- end
- end
- -- helper function to persist a particular type of application state
- function setState(type, state)
- local filepath = "wisher/_states/_" .. type
- local handle = fs.open(filepath, "w")
- handle.write(state)
- handle.close()
- return state
- end
- -- returns the state, can be used for persistence accross file being closed (ie self update) or computer shutting down (chunk unloaded, server restarted etc.)
- function getStartupState()
- return getState("startup")
- end
- -- sets the state, used for file persistence
- function setStartupState(state)
- setState("startup", state)
- end
- -- used by checkSelf(), start() to determin what to do, 1=upToDate, 2=needs updating, 3=error(file not downloaded/copied), 4=Updated this boot
- function getStartupUpdate()
- return getState("startupUpdate")
- end
- -- sets the update status
- function setStartupUpdate(state)
- setState("startupUpdate", state)
- end
- -- returns the file PROGRAM_VERSION as a string for a specified file, this should be the first line in any live file
- function getVersion(filepath)
- local handle = fs.open(filepath, "r")
- local version = tostring(handle.readLine())
- handle.close()
- return version
- end
- -- Appends the filenames of any failed files to a log with the server system date at the top of the file ie
- -- "programName: ".."status".." ".."failed"
- -- will mention whether it failed to download, update etc.
- -- sets fileStatusFailed to true which is used to print a message to read the log
- function logFailed(programName, programStatus)
- local filepath = "wisher/_log/_startup"
- logIndex = logIndex + 1
- if (logIndex == 1) then -- if this is the first file to be logged this boot then delete the previous log file to save storage space
- fs.delete(filepath)
- end
- local handle = fs.open(filepath, "a")
- if (logIndex == 1) then handle.writeLine(os.date()) end -- top line should be date for clarification
- handle.writeLine(programName .. ": " .. programStatus .. "Failed")
- handle.close()
- fileStatusFailed = true
- end
- -- checks if a file needs updating by downloading and comparing the version number
- -- logs updates into fileStatus{}, logs fails to logFailed()
- -- we can always assume the 2nd fileStatus index is 4 since 4 = updated
- function checkVersion(fileCurrent, fileLink, verboseIndexType, verboseIndexFilename, ...)
- --make sure to pass file path and file name if library for fileCurrent
- local fileBasename = fileCurrent
- local isUpdate = false
- if (#arg == 5) then
- fileBasename = arg[5] -- used for checkDependecies where the fileCurrent includes path, this is to neaten verbose
- end
- local remoteFileName = fileCurrent .. "VerCheck"
- local localFileVersion = getVersion(fileCurrent)
- shell.run("pastebin", "get", fileLink, remoteFileName)
- if (not fs.exists(remoteFileName)) then
- -- if the file failed to download then log updated failed
- logFailed(fileBasename, fileStatus[verboseIndexType][4])
- end
- if (fs.exists(remoteFileName)) then
- -- if the file successfully downloaded then proceed with logic and log the fileStatus
- local remoteFileVersion = getVersion(remoteFileName)
- if (not (localFileVersion == remoteFileVersion)) then -- if the remoteFile version is different then delete current and rename new
- fs.delete(fileCurrent)
- fs.move(remoteFileName, fileCurrent)
- fileStatus[verboseIndexType][4][verboseIndexFilename] = fileBasename
- isUpdate = true
- end
- if (localFileVersion == remoteFileVersion) then -- if file versions match then delete the comparison file
- fs.delete(remoteFileName)
- end
- end
- return isUpdate
- end
- -- Checks to see if this very program needs updating
- -- sets a value in a file to used persistently to determin whether the file needs updating
- -- refer to getStartupUpdate() comments to know what the numbers mean
- function checkSelf()
- local fileCurrent = "startup"
- local remoteFileName = fileCurrent .. "VerCheck"
- shell.run("pastebin", "get", PROGRAM_LINK, remoteFileName)
- if (not fs.exists(remoteFileName)) then
- setStartupUpdate(3)
- return
- end
- if (fs.exists(remoteFileName)) then
- local remoteFileVersion = getVersion(remoteFileName)
- if (not (PROGRAM_VERSION_CONVERTED == remoteFileVersion)) then
- fs.copy(fileCurrent, fileCurrent .. "Updater")
- if (fs.exists(fileCurrent .. "Updater")) then
- setStartupUpdate(2)
- return
- end
- if (not (fs.exists(fileCurrent .. "Updater"))) then
- setStartupUpdate(3)
- return
- end
- end
- if (PROGRAM_VERSION_CONVERTED == remoteFileVersion) then
- fs.delete(remoteFileName)
- setStartupUpdate(1)
- return
- end
- end
- end
- -- Ensures all Libraries/Apis are downloaded, logs successes to fileStatus{}, logs failures to logFailed()
- function checkDependencies()
- local libList = {} -- for libs physically located on the robot
- local apiExist = false
- local fileStatusIndexUpdate = 1 -- needs to be logged locally for each IndexStatus, index for the Filename, starts at 1 since we pass this into checkVersion() args, update if returns true, therefore first run must be 1 not 0
- local fileStatusIndexDownload = 0
- for i, v in ipairs(DEPENDENCIES) do
- local libName = DEPENDENCIES[i]["path"] .. DEPENDENCIES[i]["file"]
- local libLink = DEPENDENCIES[i]["link"]
- libList[i] = shell.resolveProgram(libName) -- attempts to add the filename of dependency[i] to libList to prove it exists
- if (libList[i] == libName) then --if the lib exists then check its version
- apiExist = true
- if (checkVersion(libName, libLink, 1, fileStatusIndexUpdate, DEPENDENCIES[i]["file"])) then -- only update index if checkVersion actually updates
- fileStatusIndexUpdate = fileStatusIndexUpdate + 1
- end
- end
- if (apiExist == false) then -- if the lib doesnt exist, download it by using the link in dependancy[i]
- shell.run("pastebin", "get", libLink, libName)
- if (fs.exists(libName)) then
- fileStatusIndexDownload = fileStatusIndexDownload + 1
- fileStatus[1][1][fileStatusIndexDownload] = DEPENDENCIES[i]["file"]
- end
- if (not fs.exists(libName)) then
- -- if the file did not download then log this
- logFailed(DEPENDENCIES[i]["file"], fileStatus[1][1])
- end
- end
- apiExist = false
- end
- end
- -- Dynamically initializes DEPENDENCIES globally, only if one with the same name doesnt already exist, logs successes to fileStatus{}, failures to logFailed()
- function initializeDependencies()
- local fileStatusIndexAlready = 0 -- needs to be logged locally for each IndexStatus
- local fileStatusIndexLoaded = 0
- for keyLibIndex, valueLibName in ipairs(DEPENDENCIES) do
- local libraryName = DEPENDENCIES[keyLibIndex]["file"]
- local libraryPath = DEPENDENCIES[keyLibIndex]["path"] .. DEPENDENCIES[keyLibIndex]["file"]
- if (_G[libraryName]) then
- fileStatusIndexAlready = fileStatusIndexAlready + 1
- fileStatus[1][3][fileStatusIndexAlready] = libraryName
- end
- if (not _G[libraryName]) then
- _G[libraryName] = require(libraryPath)
- fileStatusIndexLoaded = fileStatusIndexLoaded + 1
- fileStatus[1][2][fileStatusIndexLoaded] = libraryName
- if (not _G[libraryName]) then
- -- if the file still isn't loaded then log it didnt load, it should have loaded by now
- logFailed(libraryName, fileStatus[1][2])
- end
- end
- end
- end
- -- Checks label of computer and downloads appropriate program/s, logs successes to fileStatus{}, logs failures to logFailed()
- function checkPrograms()
- local computerType = os.getComputerLabel()
- computerType = string.lower(computerType)
- local programList = {}
- local programListIndex = 0 -- need to manually index this since our loops are inside loops and the numbers would get funky if we used their iterator
- local programExist = false
- local fileStatusIndexUpdate = 1 -- needs to start at 1 as checkVersion() parses this, only update if true is received back
- local fileStatusIndexDownload = 0
- for iOne, vOne in ipairs(COMPUTER_PROGRAMS) do
- local computerLabel = COMPUTER_PROGRAMS[iOne]["label"]
- computerLabel = string.lower(computerLabel)
- for iTwo, vTwo in ipairs(COMPUTER_PROGRAMS[iOne]) do
- programListIndex = programListIndex + 1
- local programName = COMPUTER_PROGRAMS[iOne][iTwo]["file"]
- local programLink = COMPUTER_PROGRAMS[iOne][iTwo]["link"]
- programList[programListIndex] = shell.resolveProgram(programName)
- if (string.find(computerType, computerLabel)) then -- only download programs if the computer label matches the table label
- if (programList[programListIndex] == programName) then -- checks if file already exists
- programExist = true
- if checkVersion(programName, programLink, 2, fileStatusIndexUpdate) then
- fileStatusIndexUpdate = fileStatusIndexUpdate + 1
- end
- end
- if (programExist == false) then -- if file doesnt exist, download
- shell.run("pastebin", "get", programLink, programName)
- if (fs.exists(programName)) then
- fileStatusIndexDownload = fileStatusIndexDownload + 1
- fileStatus[2][1][fileStatusIndexDownload] = programName
- end
- if (not fs.exists(programName)) then
- logFailed(programName, fileStatus[2][1])
- end
- end
- end
- programExist = false
- end
- end
- end
- -- cleans the screen then prints how each file was handled, ie Downloaded, Loaded, Already Loaded, Updated, also informs startup version
- function verboseFileStatus()
- -- need 3 loops? Type loop, Status loop, filename loop
- shell.run("clear")
- for iType, vType in ipairs(fileStatus) do
- print(fileStatus[iType]["type"])
- for iStatus, vStatus in ipairs(fileStatus[iType]) do
- write(fileStatus[iType][iStatus]["status"])
- for iFilename, vFilename in ipairs(fileStatus[iType][iStatus]) do
- write(vFilename .. " ")
- end
- write("\n")
- end
- end
- print("Startup File Version: " .. PROGRAM_VERSION)
- end
- -- returns the program name to run, or false if none.
- -- only returns program name if ONLY 1 program is set to autorun, if more than 1 progam should be run automatically than handle within THAT program
- function shouldInitializeProgram()
- local computerLabel = os.getComputerLabel()
- local programName
- local isAutorun = false
- local autorunCount = 0
- for i, v in pairs(COMPUTER_PROGRAMS) do
- if (computerLabel == COMPUTER_PROGRAMS[i]["label"]) then
- for ia, va in pairs(COMPUTER_PROGRAMS[i]) do
- if (COMPUTER_PROGRAMS[i][ia]["autorun"]) then
- programName = COMPUTER_PROGRAMS[i][ia]["file"]
- isAutorun = true
- autorunCount = autorunCount + 1
- end
- end
- end
- end
- if (isAutorun) and (autorunCount == 1) then
- return programName
- end
- if (autorunCount > 1) then
- isAutorun = false
- return isAutorun
- end
- if (not isAutorun) then
- return isAutorun
- end
- end
- -- Main function, first checks if it needs to update itself, then updates dependencies, initializes dependencies, updates programs, verboses what happened to all prior, then initializes autorun program if there is ONE
- function start()
- local fileCurrent = "startup"
- local fileUpdater = fileCurrent .. "Updater"
- local fileRemote = fileCurrent .. "VerCheck"
- -- state list: 0=start of file, 1=open copy to update self, 2=close original update original,3=open original and close updater and delete files, 4=Check/Init Dependencies - Check programs - verbose - autorun
- if (getStartupState() == 0) then -- if just booted
- checkSelf()
- if (getStartupUpdate() ~= 2) then
- -- if startup is upToDate OR failed to check properly, then do everything else
- setStartupState(4)
- end
- if (getStartupUpdate() == 2) then
- -- if startup needs updating then begin that process
- setStartupState(1)
- shell.run(fileUpdater)
- return
- end
- end
- if (getStartupState() == 1) then -- if needs updating then
- --rename updated file to startup, delete original startup, launch startup again
- fs.delete(fileCurrent)
- if (not fs.exists(fileCurrent)) then fs.move(fileRemote, fileCurrent) end
- setStartupState(2)
- shell.run(fileCurrent)
- return
- end
- if (getStartupState() == 2) then --if updated then
- -- delete updater, then continue with normal startup
- fs.delete(fileUpdater)
- setStartupState(3)
- os.reboot()
- end
- if (getStartupState() == 3) then -- if finished updating & rebooted then set that value and finish remaining startup processes
- setStartupUpdate(4)
- setStartupState(4)
- end
- if (getStartupState() == 4) then -- normal startup stuff
- checkDependencies()
- initializeDependencies()
- checkPrograms()
- verboseFileStatus()
- if (getStartupUpdate() == 4) then print("Startup was updated!") end
- if (getStartupUpdate() == 3) then -- if self-update failed, log to logFailed()
- logFailed("Startup", "Updated: ")
- end
- if (fileStatusFailed) then
- print("Something went wrong, check log for details")
- end
- end
- setStartupState(0) -- so the next boot sequence or run of startup will continue from the top of start()
- fs.delete("wisher/_states/_startupUpdate") -- regenerate startupUpdate information each completed boot sequence
- if (shouldInitializeProgram() ~= false) then
- -- if shouldInitializeProgram returns any value that ISNT false
- sleep(5) -- time to read screen verbose before executing autorun
- shell.run(shouldInitializeProgram())
- return
- end
- end
- start()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement