v1.0.0 - Added Argentum as well as other major improvements and bugfixes.

This commit is contained in:
TheWahlolly
2025-05-18 19:16:30 +03:00
parent 521d52a26e
commit 95c235e65b
19 changed files with 951 additions and 42 deletions
+79
View File
@@ -0,0 +1,79 @@
local agcfg = {
["halyde"] = {
["maindir"] = "",
["version"] = "1.1.0",
["description"] = "A universal, customizable and feature-packed operating system for OpenComputers.",
["directories"] = {
"halyde/apps",
"halyde/apps/helpdb",
"halyde/config",
"halyde/core",
"halyde/lib"
},
["files"] = {
"init.lua",
"halyde/apps/helpdb/cat.txt",
"halyde/apps/helpdb/cd.txt",
"halyde/apps/helpdb/clear.txt",
"halyde/apps/helpdb/cp.txt",
"halyde/apps/helpdb/default.txt",
"halyde/apps/helpdb/echo.txt",
"halyde/apps/helpdb/fetch.txt",
"halyde/apps/helpdb/help.txt",
"halyde/apps/helpdb/ls.txt",
"halyde/apps/helpdb/lua.txt",
"halyde/apps/helpdb/mv.txt",
"halyde/apps/helpdb/rm.txt",
"halyde/apps/cat.lua",
"halyde/apps/cd.lua",
"halyde/apps/clear.lua",
"halyde/apps/cp.lua",
"halyde/apps/download.lua",
"halyde/apps/echo.lua",
"halyde/apps/fetch.lua",
"halyde/apps/help.lua",
"halyde/apps/ls.lua",
"halyde/apps/lua.lua",
"halyde/apps/mv.lua",
"halyde/apps/rm.lua",
"halyde/config/shell.cfg",
"halyde/config/startupapps.cfg",
"halyde/core/boot.lua",
"halyde/core/cormgr.lua",
"halyde/core/datatools.lua",
"halyde/core/evmgr.lua",
"halyde/core/fullkb.lua",
"halyde/core/shell.lua",
"halyde/core/termlib.lua",
"halyde/lib/component.lua",
"halyde/lib/event.lua",
"halyde/lib/filesystem.lua",
"halyde/lib/raster.lua"
}
},
["argentum"] = {
["maindir"] = "",
["version"] = "1.0.0",
["description"] = "The default package manager for Halyde.",
["directories"] = {
"argentum",
"argentum/store"
},
["files"] = {
"argentum/registry.cfg",
"halyde/apps/argentum.lua",
"halyde/apps/helpdb/argentum.txt"
}
},
["edit"] = {
["maindir"] = "",
["version"] = "1.1.0",
["description"] = "The default text editor for Halyde.",
["files"] = {
"halyde/apps/edit.lua",
"halyde/apps/helpdb/edit.txt"
}
}
}
return agcfg
+7
View File
@@ -0,0 +1,7 @@
local agregistry = {
["halyde"] = "https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/",
["edit"] = "https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/",
["argentum"] = "https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/"
}
return agregistry
+6
View File
@@ -0,0 +1,6 @@
Aargentum/registry.cfg
Ahalyde/apps/argentum.lua
Ahalyde/apps/helpdb/argentum.txt
V1.0.0
Aargentum/
Aargentum/store/
+3
View File
@@ -0,0 +1,3 @@
Ahalyde/apps/edit.lua
Ahalyde/apps/helpdb/edit.txt
V1.1.0
+45
View File
@@ -0,0 +1,45 @@
Ainit.lua
Ahalyde/apps/helpdb/cat.txt
Ahalyde/apps/helpdb/cd.txt
Ahalyde/apps/helpdb/clear.txt
Ahalyde/apps/helpdb/cp.txt
Ahalyde/apps/helpdb/default.txt
Ahalyde/apps/helpdb/echo.txt
Ahalyde/apps/helpdb/fetch.txt
Ahalyde/apps/helpdb/help.txt
Ahalyde/apps/helpdb/ls.txt
Ahalyde/apps/helpdb/lua.txt
Ahalyde/apps/helpdb/mv.txt
Ahalyde/apps/helpdb/rm.txt
Ahalyde/apps/cat.lua
Ahalyde/apps/cd.lua
Ahalyde/apps/clear.lua
Ahalyde/apps/cp.lua
Ahalyde/apps/download.lua
Ahalyde/apps/echo.lua
Ahalyde/apps/fetch.lua
Ahalyde/apps/help.lua
Ahalyde/apps/ls.lua
Ahalyde/apps/lua.lua
Ahalyde/apps/mv.lua
Ahalyde/apps/rm.lua
Ahalyde/config/shell.cfg
Ahalyde/config/startupapps.cfg
Ahalyde/core/boot.lua
Ahalyde/core/cormgr.lua
Ahalyde/core/datatools.lua
Ahalyde/core/evmgr.lua
Ahalyde/core/fullkb.lua
Ahalyde/core/shell.lua
Ahalyde/core/termlib.lua
Ahalyde/lib/component.lua
Ahalyde/lib/event.lua
Ahalyde/lib/filesystem.lua
Ahalyde/lib/raster.lua"
V1.0.0
Ahalyde/
Ahalyde/apps/
Ahalyde/apps/helpdb/
Ahalyde/config/
Ahalyde/core/
Ahalyde/lib/
+550
View File
@@ -0,0 +1,550 @@
local packages = {...}
local command = packages[1]
table.remove(packages, 1)
local fs = import("filesystem")
local agReg = import("/argentum/registry.cfg")
if not command then
shell.run("help argentum")
return
end
if not component.list("internet")() then
print("\27[91mThis program requires an internet card to run.")
return
end
local internet = component.proxy(component.list("internet")())
local source
if table.find(packages, "-s") then
source = table.remove(packages, table.find(packages, "-s") + 1)
table.remove(packages, table.find(packages, "-s"))
print("Using " .. source .. " as package source")
elseif table.find(packages, "--source") then
source = table.remove(packages, table.find(packages, "--source") + 1)
table.remove(packages, table.find(packages, "--source"))
print("Using " .. source .. " as package source")
else
print("Using main registry as package source")
end
if source and source:sub(1, 1) == "/" and source:sub(-1, -1) ~= "/" then
source = source .. "/"
end
local packageList = table.copy(packages)
local function getFile(path)
if path:sub(1,1) == "/" then
if not fs.exists(path) then
return false, "file does not exist"
end
local handle, data, tmpdata = fs.open(path, "r"), "", nil
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
return data
else
local request, data, tmpdata = nil, "", nil
local status, errorMessage = pcall(function()
request = internet.request(path)
request:finishConnect()
end)
if not status then
return false, errorMessage
end
local responseCode = request:response()
if responseCode and responseCode ~= 200 then
return false, responseCode
end
repeat
tmpdata = request.read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
return data
end
end
local i = 1
local function getAgConfig(package, source)
source = source or agReg[package]
local data, errorMessage = getFile(source .. "argentum.cfg")
if not data or data == "" then
print("\27[91mCould not fetch Ag config: " .. (errorMessage or "returned nil data"))
return false
end
local func, errorMessage = load(data, "=argentum.cfg", "bt", {})
if not func then
print("\27[91mCould not fetch Ag config: " .. errorMessage .. "\nPlease contact the package owner.")
return false
end
local agcfg
local status, errorMessage = pcall(function()
agcfg = func()
end)
if not status then
print("\27[91mCould not fetch Ag config: " .. errorMessage .. "\nPlease contact the package owner.")
return false
end
if not agcfg[package] or not agcfg[package].maindir or not agcfg[package].directories or not agcfg[package].files or not agcfg[package].version then
local response = ("\27[91mAg config of " .. package .. " is improperly configured.\nPlease contact the package owner.")
end
return agcfg
end
local function doChecks(package)
if not agReg[package] and not source then
print("\27[91mPackage " .. package .. " does not exist.")
return false
end
if fs.exists("/argentum/store/" .. package) then
print("\27[91mPackage " .. package .. " is already installed.")
return false
end
agcfg = getAgConfig(package, source)
if not agcfg then
return false
end
if agcfg[package].dependencies then
for _, dependency in ipairs(agcfg[package].dependencies) do
if not agReg[dependency] and not agcfg[dependency] then
local response = read(nil, "\27[91mPackage " .. package .. " requires dependency " .. dependency .. " that does not exist.\n[A - Abort/s - Skip]")
if response:lower() ~= "s" then
fs.remove("/argentum/store/" .. package)
return false
end
end
end
for _, dependency in pairs(agcfg[package].dependencies) do
print(package .. " depends on " .. dependency)
if not table.find(packages, dependency) and doChecks(dependency) then
table.insert(packages, table.find(packages, package), dependency)
table.insert(packageList, dependency)
i = i + 1
end
end
end
return true
end
local function installPackage(package)
print("Installing " .. package .. "...")
local agcfg = getAgConfig(package, source)
if not agcfg then
return false
end
local source = source or agReg[package]
local packageStore = "V" .. agcfg[package].version
if agcfg[package].dependencies then
for _, dependency in ipairs(agcfg[package].dependencies) do
if not agReg[dependency] and not agcfg[dependency] then
local response = read(nil, "\27[91mPackage " .. package .. " requires dependency " .. dependency .. " that does not exist.\n[A - Abort/s - Skip]")
if response:lower() ~= "s" then
fs.remove("/argentum/store/" .. package)
return false
end
end
end
for _, dependency in pairs(agcfg[package].dependencies) do
if agReg[dependency] or agcfg[dependency] then
--installPackage(dependency)
packageStore = packageStore .. "\nD" .. dependency
end
end
end
if agcfg[package].directories then
for _, directory in pairs(agcfg[package].directories) do
if directory:sub(-1, -1) ~= "/" then
directory = directory .. "/"
end
packageStore = "A" .. directory .. "\n" .. packageStore
if not fs.exists(directory) then
fs.makeDirectory(directory)
end
end
end
for _, file in ipairs(agcfg[package].files) do
::retry::
print(" Downloading " .. file .. "...")
local data, errorMessage = getFile(source .. agcfg[package].maindir .. file)
if not data then
local response = read(nil, "\27[91mCould not fetch " .. file .. ": " .. errorMessage .. "\n\27[0m[a - Abort/R - Retry/s - Skip]")
if response:lower() == "a" then
fs.remove("/argentum/store/" .. package)
return false
elseif response:lower() == "s" then
goto skip
else
goto retry
end
end
if fs.exists(file) then
if not fs.exists("/argentum/store/" .. package .. "/files/" .. file:match("(.*/)")) then
fs.makeDirectory("/argentum/store/" .. package .. "/files/" .. file:match("(.*/)"))
end
fs.copy(file, "/argentum/store/" .. package .. "/files/" .. file)
packageStore = packageStore .. "\nM" .. file
else
packageStore = packageStore .. "\nA" .. file
end
local handle = fs.open(file, "w")
handle:write(data)
handle:close()
::skip::
end
fs.makeDirectory("/argentum/store/" .. package)
local handle = fs.open("/argentum/store/" .. package .. "/package.cfg", "w")
handle:write(packageStore)
handle:close()
return true
end
local function removePackage(package)
print("Removing " .. package .. "...")
if not fs.exists("/argentum/store/" .. package .. "/package.cfg") then
print("\27[91mLocal Ag config of " .. package .. " does not exist.")
return false
end
local handle, data, tmpdata = fs.open("/argentum/store/" .. package .. "/package.cfg", "r"), "", nil
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
for line in (data.."\n"):gmatch("(.-)\n") do
if line:sub(1, 1) == "A" then
::retry::
print(" Removing " .. line:sub(2) .. "...")
if line:sub(-1, -1) == "/" and fs.list(line:sub(2))[1] then
print(" There are still files in " .. line:sub(2) .. ". Skipping.")
else
local result, errorMessage = fs.remove(line:sub(2))
if not result then
local response = read(nil, "\27[91mFailed to remove " .. line:sub(2) .. ": " .. errorMessage .. "\n\27[0m[a - Abort/r - Retry/S - Skip]")
if response:lower() == "a" then
return false
elseif response:lower() == "r" then
goto retry
end
end
end
elseif line:sub(1, 1) == "M" then
::retry::
print(" Reverting " .. line:sub(2) .. "...")
local handle, data, tmpdata = fs.open("/argentum/store/" .. package .. "/files/" .. line:sub(2), "r"), "", nil
if not handle then
local response = read(nil, "\27[91mFailed to revert " .. line:sub(2) .. ": " .. data .. "\n\27[0m[a - Abort/R - Retry/s - Skip]") -- this is pretty stupid but i think the error message would get pushed to data
if response:lower() == "a" then
return false
elseif response:lower() == "s" then
goto skip
else
goto retry
end
end
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
local handle = fs.open(line:sub(2), "w")
handle:write(data)
handle:close()
::skip::
end
end
fs.remove("/argentum/store/" .. package .. "/")
return true
end
-- Update registry
local fails = {}
if command == "install" then
if not packages or not packages[1] then
print("Please specify packages to install.")
return
end
while true do
if not doChecks(packages[i]) then
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
end
i = i + 1
if i > #packages then
break
end
end
local answer
if #fails == 0 then
print("Packages that will be installed: " .. table.concat(packageList, ", "))
if read(nil, "Would you like to proceed? [Y/n] "):lower() == "n" then
return
end
elseif #packageList == 0 then
print("None of the packages can be installed.")
return
else
print("Some packages cannot be installed.")
print("Packages that will be installed: " .. table.concat(packageList, ", "))
print("Packages that cannot be installed: " .. table.concat(fails, ", "))
if read(nil, "Would you like to proceed? [y/N] "):lower() ~= "y" then
return
end
end
for _, failedPackage in pairs(fails) do
table.remove(packages, table.find(packages, failedPackage))
end
fails = {}
for _, package in ipairs(packages) do
if not installPackage(package) then
table.insert(fails, package)
table.remove(packageList, table.find(packageList, package))
end
end
if #fails == 0 then
print("Installation completed successfully.")
print("Packages installed: " .. table.concat(packageList, ", "))
elseif #packageList == 0 then
print("All packages failed to install.")
print("Packages that could not be installed: " .. table.concat(fails, ", "))
else
print("Some packages failed to install.")
print("Packages installed: " .. table.concat(packageList, ", "))
print("Packages that could not be installed: " .. table.concat(fails, ", "))
end
elseif command == "remove" then
if not packages or not packages[1] then
print("Please specify packages to remove.")
return
end
while true do
if not fs.exists("/argentum/store/" .. packages[i]) then
print("\27[91mPackage " .. packages[i] .. " is not installed.")
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
i = i - 1
elseif packages[i] == "halyde" then -- yes, this stuff is hard-coded.
print("\27[91mFor obvious reasons, you can't uninstall Halyde.")
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
i = i - 1
elseif packages[i] == "argentum" then
print("\27[91mFor obvious reasons, you can't uninstall Argentum.")
print("\27[91mFor obvious reasons, you can't uninstall Halyde.")
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
i = i - 1
end
i = i + 1
if i > #packages then
break
end
end
-- do dependency checks
local packagesInstalled = fs.list("/argentum/store")
for _, currentPackage in pairs(packagesInstalled) do
if currentPackage:sub(-1, -1) == "/" and fs.exists("/argentum/store/" .. currentPackage .. "package.cfg") then
local handle, data, tmpdata = fs.open("/argentum/store/" .. currentPackage .. "package.cfg", "r"), "", nil
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
for line in (data.."\n"):gmatch("(.-)\n") do
for i = 1, #packages do
if line == "D" .. packages[i] then
print(packages[i] .. " depends on " .. currentPackage:sub(1, -2))
if not table.find(packages, currentPackage:sub(1, -2)) then
table.insert(packages, table.find(packages, packages[i]), currentPackage:sub(1, -2))
table.insert(packageList, currentPackage:sub(1, -2))
i = i + 1
end
end
end
end
end
end
local answer
if #fails == 0 then
print("Packages that will be removed: " .. table.concat(packageList, ", "))
if read(nil, "Would you like to proceed? [Y/n] "):lower() == "n" then
return
end
elseif #packageList == 0 then
print("None of the packages can be removed.")
return
else
print("Some packages cannot be removed.")
print("Packages that will be removed: " .. table.concat(packageList, ", "))
print("Packages that cannot be removed: " .. table.concat(fails, ", "))
if read(nil, "Would you like to proceed? [y/N] "):lower() ~= "y" then
return
end
end
for _, failedPackage in pairs(fails) do
table.remove(packages, table.find(packages, failedPackage))
end
fails = {}
for _, package in ipairs(packages) do
if not removePackage(package) then
table.insert(fails, package)
table.remove(packageList, table.find(packageList, package))
end
end
if #fails == 0 then
print("Removal completed successfully.")
print("Packages removed: " .. table.concat(packageList, ", "))
elseif #packageList == 0 then
print("All packages failed to be removed.")
print("Packages that could not be removed: " .. table.concat(fails, ", "))
else
print("Some packages failed to be removed.")
print("Packages removed: " .. table.concat(packageList, ", "))
print("Packages that could not be removed: " .. table.concat(fails, ", "))
end
elseif command == "update" then
if not packages[1] then
local packagesInstalled = fs.list("/argentum/store/")
for _, currentPackage in pairs(packagesInstalled) do
if currentPackage:sub(-1, -1) == "/" and fs.exists("/argentum/store/" .. currentPackage .. "package.cfg") then
table.insert(packages, currentPackage:sub(1, -2))
table.insert(packageList, currentPackage:sub(1, -2))
end
end
end
while true do
if not fs.exists("/argentum/store/" .. packages[i]) then
print("\27[91mPackage " .. packages[i] .. " is not installed.")
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
i = i - 1
end
i = i + 1
if i > #packages then
break
end
end
local answer
if #fails == 0 then
print("Packages that will be updated: " .. table.concat(packageList, ", "))
if read(nil, "Would you like to proceed? [Y/n] "):lower() == "n" then
return
end
elseif #packageList == 0 then
print("None of the packages can be updated.")
return
else
print("Some packages cannot be updated.")
print("Packages that will be updated: " .. table.concat(packageList, ", "))
print("Packages that cannot be updated: " .. table.concat(fails, ", "))
if read(nil, "Would you like to proceed? [y/N] "):lower() ~= "y" then
return
end
end
for _, failedPackage in pairs(fails) do
table.remove(packages, table.find(packages, failedPackage))
end
fails = {}
for _, package in pairs(packages) do
local agcfg = getAgConfig(package, source)
if not agcfg then
return false
end
local handle, data, tmpdata = fs.open("/argentum/store/" .. package .. "/package.cfg", "r"), "", nil
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
local version = "0.0.0"
for line in (data.."\n"):gmatch("(.-)\n") do
if line:sub(1, 1) == "V" then
version = line:sub(2)
break
end
end
local handle, data, tmpdata = fs.open("/argentum/store/" .. package .. "/package.cfg", "r"), "", nil
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
local version = "0.0.0"
for line in (data.."\n"):gmatch("(.-)\n") do
if line:sub(1, 1) == "V" then
version = line:sub(2)
break
end
end
if agcfg[package].version == version then
print(package .. " is up to date")
goto skip
end
if not removePackage(package) then
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
goto skip
end
if not installPackage(package) then
table.insert(fails, packages[i])
table.remove(packageList, table.find(packageList, packages[i]))
table.remove(packages, table.find(packages, packages[i]))
goto skip
end
::skip::
end
if #fails == 0 then
print("Update completed successfully.")
print("Packages updated: " .. table.concat(packageList, ", "))
elseif #packageList == 0 then
print("All packages failed to update.")
print("Packages that could not update: " .. table.concat(fails, ", "))
else
print("Some packages failed to update.")
print("Packages updated: " .. table.concat(packageList, ", "))
print("Packages that could not update: " .. table.concat(fails, ", "))
end
elseif command == "info" then
if not packages[1] then
print("Please specify a package to show information about.")
return
end
if not agReg[packages[1]] and not source then
print("\27[91mPackage " .. packages[1] .. " does not exist.")
return
end
local agcfg = getAgConfig(packages[1], source)
if not agcfg then
return false
end
print("\27[93m" .. packages[1] .. "\27[0m v" .. agcfg[packages[1]].version .. "\n " .. (agcfg[packages[1]].description or "No description."):gsub("\n", " \n"))
elseif command == "search" then
if not packages[1] then
print("Please specify a search term.")
return
end
local searchResults = {}
for packageName, _ in pairs(agReg) do
if packageName:find(packages[1], 1, true) then
table.insert(searchResults, packageName)
end
end
if not searchResults[1] then
print("No search results found for " .. packages[1] .. ".")
return
end
table.sort(searchResults)
print("Search results: \n " .. table.concat(searchResults, "\n "))
elseif command == "list" then
local sortedPackages = {}
for packageName, _ in pairs(agReg) do
table.insert(sortedPackages, packageName)
end
table.sort(sortedPackages)
print("List of available Ag packages: \n " .. table.concat(sortedPackages, "\n "))
else
shell.run("help ag")
end
+6 -2
View File
@@ -183,7 +183,7 @@ local function processEvent(args)
changesMade = true changesMade = true
cursorRenderFlag = true cursorRenderFlag = true
cursorWhite = true cursorWhite = true
if cursorPosY + scrollPosY - 1 > 1 then if cursorPosX == 1 and cursorPosY + scrollPosY - 1 > 1 then
cursorPosY = cursorPosY - 1 cursorPosY = cursorPosY - 1
if cursorPosY < 1 then if cursorPosY < 1 then
scrollPosY = scrollPosY - 1 scrollPosY = scrollPosY - 1
@@ -256,7 +256,11 @@ local function save()
end end
local handle, errorMessage = fs.open(savepath, "w") local handle, errorMessage = fs.open(savepath, "w")
if handle then if handle then
handle:write(table.concat(tmpdata, "\n")) if table.concat(tmpdata, "\n"):sub(-1, -1) == "\n" then
handle:write(table.concat(tmpdata, "\n"))
else
handle:write(table.concat(tmpdata, "\n") .. "\n") -- add a newline at the end to follow POSIX standards
end
handle:close() handle:close()
rawset(1, height - 1, "\27[107m\27[30m" .. filestring .. string.rep(" ", width)) rawset(1, height - 1, "\27[107m\27[30m" .. filestring .. string.rep(" ", width))
else else
+1 -1
View File
@@ -14,7 +14,7 @@ print("\27[92mComponents\27[0m: "..tostring(componentCounter))
termlib.cursorPosX = 17 termlib.cursorPosX = 17
print("\27[92mCoroutines\27[0m: "..tostring(#cormgr.corList)) print("\27[92mCoroutines\27[0m: "..tostring(#cormgr.corList))
termlib.cursorPosX = 17 termlib.cursorPosX = 17
print("\27[92mBattery\27[0m: "..tostring(math.floor(computer.maxEnergy() / computer.energy() * 1000 + 0.5) / 10).."%") print("\27[92mBattery\27[0m: "..tostring(math.floor(computer.energy() / computer.maxEnergy() * 1000 + 0.5) / 10).."%")
termlib.cursorPosX = 17 termlib.cursorPosX = 17
local totalMemory = computer.totalMemory() local totalMemory = computer.totalMemory()
local usedMemory = computer.totalMemory() - computer.freeMemory() local usedMemory = computer.totalMemory() - computer.freeMemory()
+18
View File
@@ -0,0 +1,18 @@
Usage: argentum [COMMAND] [PACKAGES]
Uses the Argentum package manager.
COMMAND Specifies the operation for Ag to do.
install Installs packages.
remove Removes packages.
update Updates packages.
list Lists all available packages.
search Searches all available packages.
info Shows information on a specific package.
PACKAGES* Packages to apply operations to.
Examples:
ag install hal-draw Installs the hal-draw package.
ag list Lists all packages.
ag info hal-draw Shows information about hal-draw.
ag update hal-draw Updates the hal-draw package if it's not at the newest version.
ag update Updates all packages.
+14 -13
View File
@@ -1,16 +1,17 @@
All current Halyde shell commands: All default Halyde shell commands:
cat Concatenates and prints a file. cat Concatenates and prints a file.
cd Changes directory. cd Changes directory.
clear Clears the screen. clear Clears the screen.
cp Copies a file. cp Copies a file.
echo Prints a message. echo Prints a message.
fetch Displays system information. fetch Displays system information.
help Shows this. help Shows this.
ls Lists files. ls Lists files.
lua Starts the Lua shell. lua Starts the Lua shell.
mv Moves/renames a file. mv Moves/renames a file.
rm Deletes a file. rm Deletes a file.
edit Opens the text editor. edit Opens the text editor.
argentum Uses the Argentum package manager.
You can get additional information on any app or command by running: You can get additional information on any app or command by running:
help [COMMAND] help [COMMAND]
+7
View File
@@ -0,0 +1,7 @@
Usage: mkdir [PATH]
Removes files and directories.
PATH Specifies the path to create the directory in.
Examples:
mkdir a Creates a directory named a in the current shell working directory.
+3 -6
View File
@@ -1,10 +1,7 @@
Usage: rm [FLAGS] [PATH] Usage: rm [PATH]
Removes files and directories. Removes files and directories.
-r, --recursive Removes directories and their contents recursively. PATH Specifies the file to be moved/renamed.
-f, --force Ignores nonexistent files or directories.
PATH Specifies the file to be moved/renamed.
Examples: Examples:
rm a.txt Removes a.txt in the current shell working directory. rm a.txt Removes a.txt in the current shell working directory.
rm -r -f /halyde/core/ Removes everything in /halyde/core/ forcedly and recursively.
+16
View File
@@ -0,0 +1,16 @@
local args = {...}
local directory = args[1]
args = nil
local fs = import("filesystem")
if not directory then
shell.run("help mkdir")
return
end
if directory:sub(1, 1) ~= "/" then
directory = shell.workingDirectory .. directory
end
if fs.exists(file) then
print("\27[91mAn object already exists at the specified path.")
end
fs.makeDirectory(file)
+24 -4
View File
@@ -1,6 +1,6 @@
local shellcfg = { local shellcfg = {
["startupMessage"] = "\n │\n │ ".._OSVERSION..'\n │ Welcome! Type "help" to get started.\n │\n ', -- message shown on startup ["startupMessage"] = "\n │\n │ ".._OSVERSION..'\n │ %s\n │\n ', -- message shown on startup. %s will be replaced with splash message.
["prompt"] = "\x1b[92m%s > \x1b[0m", -- shell prompt, %s will be replaced with working directory. example: "%s > " turns to "/current/working/directory > " ["prompt"] = "\x1b[92m%s > \x1b[0m", -- shell prompt. %s will be replaced with working directory.
["path"] = { -- default locations where programs will be run from ["path"] = { -- default locations where programs will be run from
"/halyde/apps/" "/halyde/apps/"
}, ["aliases"] = { -- shell command aliases }, ["aliases"] = { -- shell command aliases
@@ -14,8 +14,28 @@ local shellcfg = {
["del"] = "rm", ["del"] = "rm",
["delete"] = "rm", ["delete"] = "rm",
["remove"] = "rm", ["remove"] = "rm",
[".."] = "cd .." [".."] = "cd ..",
}, ["defaultWorkingDirectory"] = "/home/" -- the working directory that gets set when halyde starts ["wget"] = "download",
["ag"] = "argentum"
}, ["defaultWorkingDirectory"] = "/home/", -- the working directory that gets set when halyde starts
["splashMessages"] = { -- messages shown on startup
"Made by John Haly- I mean Cerulean Blue.",
'Welcome! Type "help" to get started.',
"Also try KOCOS!",
"Welcome back, Commander. We have no idea what we're doing.",
"99.9% bug-free. The remaining 0.1% are features.",
"0 days since last error.",
"Everything is fine. The fire is decorative.",
"Please don't feed the background processes.",
"Also has fetch!",
"Anything red is no man's land. Trust me.",
"Machine...",
"Abort, Retry, Fail?",
"What's the deal with /argentum/store?",
"So cutting-edge you can't hold it in your hand.",
"Americans are the reason you see colors on-screen. I'm talking about ANSI escape codes, not politics.",
"Shoutout to Ponali!"
}
} }
return shellcfg return shellcfg
+1 -1
View File
@@ -1,7 +1,7 @@
local loadfile = ... local loadfile = ...
local filesystem = loadfile("/halyde/lib/filesystem.lua")(loadfile) local filesystem = loadfile("/halyde/lib/filesystem.lua")(loadfile)
_G._OSVERSION = "Halyde 0.10.1" _G._OSVERSION = "Halyde 1.0.0"
function _G.import(module, ...) function _G.import(module, ...)
local args = table.pack(...) local args = table.pack(...)
+7 -7
View File
@@ -1,7 +1,7 @@
local shellcfg = import("/halyde/config/shell.cfg") local shellcfg = import("/halyde/config/shell.cfg")
import("/halyde/core/termlib.lua") import("/halyde/core/termlib.lua")
local event = import("event") local event = import("event")
--local ocelot = component.proxy(component.list("ocelot")()) local ocelot = component.proxy(component.list("ocelot")())
local filesystem = import("filesystem") local filesystem = import("filesystem")
local gpu = component.proxy(component.list("gpu")()) local gpu = component.proxy(component.list("gpu")())
@@ -55,14 +55,14 @@ function _G.shell.run(command)
if not args[1] then if not args[1] then
return return
end end
if filesystem.exists(args[1]) then if filesystem.exists(args[1]) and not filesystem.isDirectory(args[1]) then
foundfile = true foundfile = true
local path = args[1] local path = args[1]
table.remove(args, 1) table.remove(args, 1)
runAsCoroutine(path, table.unpack(args)) runAsCoroutine(path, table.unpack(args))
else else
for _, item in pairs(shellcfg["path"]) do for _, item in pairs(shellcfg["path"]) do
if filesystem.exists(item..args[1]) then if filesystem.exists(item..args[1]) and not filesystem.isDirectory(item .. args[1]) then
foundfile = true foundfile = true
local path = item..args[1] local path = item..args[1]
table.remove(args, 1) table.remove(args, 1)
@@ -71,10 +71,10 @@ function _G.shell.run(command)
else -- try to look for it without the file extension else -- try to look for it without the file extension
local files = filesystem.list(item) local files = filesystem.list(item)
for _, file in pairs(files) do for _, file in pairs(files) do
if args[1] == file:match("(.+)%.[^%.]+$") then if args[1] == file:match("(.+)%.[^%.]+$") and not filesystem.isDirectory(item .. file) then
foundfile = true foundfile = true
table.remove(args, 1) table.remove(args, 1)
runAsCoroutine(item..file, table.unpack(args)) runAsCoroutine(item .. file, table.unpack(args))
break break
end end
end end
@@ -86,14 +86,14 @@ function _G.shell.run(command)
end end
end end
print(shellcfg["startupMessage"]) print(shellcfg["startupMessage"]:format(shellcfg.splashMessages[math.random(1, #shellcfg.splashMessages)]))
while true do while true do
coroutine.yield() coroutine.yield()
-- print(shell.workingDirectory .. " >") -- print(shell.workingDirectory .. " >")
--print(shellcfg["prompt"]:format(shell.workingDirectory),false) --print(shellcfg["prompt"]:format(shell.workingDirectory),false)
-- termlib.cursorPosX = #(shell.workingDirectory .. " > ") -- termlib.cursorPosX = #(shell.workingDirectory .. " > ")
-- termlib.cursorPosY = termlib.cursorPosY - 1 -- termlib.cursorPosY = termlib.cursorPosY - 1
local shellCommand = read("shell", shellcfg["prompt"]:format(shell.workingDirectory)) local shellCommand = read("shell", shellcfg.prompt:format(shell.workingDirectory))
shell.run(shellCommand) shell.run(shellCommand)
gpu.freeAllBuffers() gpu.freeAllBuffers()
end end
+16 -8
View File
@@ -70,20 +70,23 @@ local function parseCodeNumbers(code)
return o return o
end end
function _G.print(text, endNewLine, wordWrap) function _G.print(text, endNewLine, textWrap)
-- you don't know how tiring this was just for ANSI escape code support -- you don't know how tiring this was just for ANSI escape code support
if endNewLine == nil then if endNewLine == nil then
endNewLine = true endNewLine = true
end end
if wordWrap == nil then if textWrap == nil then
wordWrap = true textWrap = true
end end
if not text or not tostring(text) then if not text or not tostring(text) then
return return
end end
if text:find("\a") then
computer.beep()
end
text = "\27[0m" .. text:gsub("\t", " ") text = "\27[0m" .. text:gsub("\t", " ")
text = tostring(text) text = tostring(text)
readBreak = 0 readBreak = 0
@@ -95,12 +98,17 @@ function _G.print(text, endNewLine, wordWrap)
if #section==0 then if #section==0 then
return return
end end
gpu.set(termlib.cursorPosX,termlib.cursorPosY,section) while true do
termlib.cursorPosX = termlib.cursorPosX+unicode.wlen(section) gpu.set(termlib.cursorPosX,termlib.cursorPosY,section)
if termlib.cursorPosX>width and wordWrap then termlib.cursorPosX = termlib.cursorPosX+unicode.wlen(section)
newLine() if unicode.wlen(section) > width and textWrap then
newLine()
else
break
end
section = section:sub(width + 1)
end end
section="" section = ""
end end
for i=1,#text do for i=1,#text do
+9
View File
@@ -170,4 +170,13 @@ function filesystem.remove(path)
return component.invoke(address, "remove", absPath) return component.invoke(address, "remove", absPath)
end end
function filesystem.makeDirectory(path)
checkArg(1, path, "string")
local address, absPath = filesystem.processPath(path)
if not address then
return false
end
return component.invoke(address, "makeDirectory", absPath)
end
return(filesystem) return(filesystem)
+139
View File
@@ -0,0 +1,139 @@
local component = require("component")
if not component.isAvailable("internet") then
io.stderr.write("This program requires an internet card to run.")
return
end
local internet = component.internet
local computer = require("computer")
local fs = require("filesystem")
local installLocation
local drives = {}
for drive in fs.list("/mnt/") do
table.insert(drives, drive)
end
if #drives == 1 and not component.invoke(component.get(drives[1]:sub(1, 3), "filesystem"), "isReadOnly") then
installLocation = drives[1]
elseif #drives == 1 then
io.stderr.write("All drives are read-only.\nHalyde cannot be installed.")
else
local installDrivesText = "Possible drives to install to:"
for i = 1, #drives do
local address = component.get(drives[i]:sub(1, 3), "filesystem")
local fsComponent = component.proxy(address)
if not fsComponent.isReadOnly() then
local label = fsComponent.getLabel()
if label then
installDrivesText = installDrivesText .. "\n " .. tostring(i) .. ". - " .. label .. "(" .. address:sub(1, 5) .. "...)"
else
installDrivesText = installDrivesText .. "\n " .. tostring(i) .. ". - " .. address:sub(1, 5) .. "..."
end
end
end
io.write(installDrivesText .. "\nPlease select a drive by entering its number or \"q\" to quit. ")
local answer
while true do
answer = io.read()
if tonumber(answer) and tonumber(answer) >= 1 and tonumber(answer) <= #drives then
break
elseif answer == "q" then
return
else
print("Answer invalid, try again.")
end
end
installLocation = "/mnt/" .. drives[tonumber(answer)]
end
if not installLocation then
print("All drives are read-only.\nHalyde cannot be installed.")
return
end
io.write("Are you sure you would like to install Halyde to " .. installLocation .. "? This will erase all data on this disk. [Y/n] ")
if io.read():lower() == "n" then
return
end
-- installation
local computer = require("computer")
local oldFiles = {}
for oldFile in fs.list(installLocation) do
if oldFile ~= "home/" then
table.insert(oldFiles, oldFile)
end
end
local function getFile(url)
local request, data, tmpdata = nil, "", nil
local status, errorMessage = pcall(function()
request = internet.request(url)
request:finishConnect()
end)
if not status then
return false, errorMessage
end
local responseCode = request:response()
if responseCode and responseCode ~= 200 then
return false, responseCode
end
repeat
tmpdata = request.read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
return data
end
local function getFile(path)
if path:sub(1,1) == "/" then
if not fs.exists(path) then
return false, "file does not exist"
end
local handle, data, tmpdata = fs.open(path, "r"), "", nil
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
handle:close()
return data
else
local request, data, tmpdata = nil, "", nil
local status, errorMessage = pcall(function()
request = internet.request(path)
request:finishConnect()
end)
if not status then
return false, errorMessage
end
local responseCode = request:response()
if responseCode and responseCode ~= 200 then
return false, responseCode
end
repeat
tmpdata = request.read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
return data
end
end
print("a")
local webInstallConfig = getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/argentum.cfg")
print("a")
webInstallConfig = load(webInstallConfig)
print("a")
webInstallConfig = webInstallConfig()
print("a")
installationOrder = {"halyde", "edit", "argentum"}
for i = 1, 3 do
local webInstallConfig = webInstallConfig[installationOrder[i]]
print("a")
if webInstallConfig.directories then
for _, directory in pairs(webInstallConfig.directories) do
print("Creating " .. directory .. "...")
fs.makeDirectory(installLocation .. directory)
end
end
for _, file in pairs(webInstallConfig.files) do
print("Downloading " .. file .. "...")
local handle = fs.open(installLocation .. file, "w")
handle:write(getFile("https://raw.githubusercontent.com/Team-Cerulean-Blue/Halyde/refs/heads/main/" .. file))
handle:close()
end
end
computer.shutdown(true)