335 lines
9.4 KiB
Lua
335 lines
9.4 KiB
Lua
print("Tiny Package Manager (TPM)")
|
|
print("Author: Kiritow")
|
|
|
|
local component=require("component")
|
|
local shell=require("shell")
|
|
local serialization=require("serialization")
|
|
local uuid=require("uuid")
|
|
local filesystem=require("filesystem")
|
|
|
|
local function showcmd(cmdstr,infostr)
|
|
local old=component.gpu.setForeground(0xFFFF00)
|
|
io.write(cmdstr)
|
|
component.gpu.setForeground(0xFFFFFF)
|
|
print(" " .. infostr)
|
|
component.gpu.setForeground(old)
|
|
end
|
|
local function showerr(infostr)
|
|
local old=component.gpu.setForeground(0xFF0000)
|
|
print(infostr)
|
|
component.gpu.setForeground(old)
|
|
end
|
|
local function cwrite(color,infostr)
|
|
local old=component.gpu.setForeground(color)
|
|
io.write(infostr)
|
|
component.gpu.setForeground(old)
|
|
end
|
|
|
|
local function resolve_github(reponame,fileaddr,branch)
|
|
if(branch==nil) then branch="master" end
|
|
return "https://raw.githubusercontent.com/" .. reponame .. "/" .. branch .. "/" .. fileaddr
|
|
end
|
|
local function resolve_cngit(reponame,fileaddr,branch)
|
|
return "http://kiritow.com:3000/" .. reponame .. "/raw/" .. branch .. "/" .. fileaddr
|
|
end
|
|
|
|
-- For Test Purpose only
|
|
resolve_github=resolve_cngit
|
|
|
|
local function beginWith(str,target)
|
|
local a,b=string.find(str,target)
|
|
if(a==nil) then return false
|
|
else return (a==1) end
|
|
end
|
|
|
|
local args,ops=shell.parse(...)
|
|
local argc=#args
|
|
|
|
if(argc<1) then
|
|
print("Usage:")
|
|
showcmd("tpm install <package>",
|
|
"Install package" ..
|
|
"\n\tInstall via github: github+Author/Repo[/branch]. Branch is 'master' by default" ..
|
|
"\n\tInstall via http: http+URL"
|
|
)
|
|
showcmd("tpm remove <package>","Remove package")
|
|
showcmd("tpm list [-in] [<package>]",
|
|
"Search package" ..
|
|
"\n\t-i Only search installed package" ..
|
|
"\n\t-n Only search not installed package"
|
|
)
|
|
showcmd("tpm update","Update software info")
|
|
return
|
|
end
|
|
|
|
-- Hardware check
|
|
if(component.internet==nil) then
|
|
showerr("No internet device found. tpm requires internet card to function normally.")
|
|
return
|
|
end
|
|
|
|
-- Functions
|
|
local function doRealDownload(url)
|
|
if(component.internet==nil) then
|
|
error("The downloader requires an Internet card.")
|
|
end
|
|
local handle=component.internet.request(url)
|
|
while true do
|
|
local ret,err=handle.finishConnect()
|
|
if(ret==nil) then
|
|
return false,err
|
|
elseif(ret==true) then
|
|
break
|
|
end
|
|
--elseif(ret==false)
|
|
--os.sleep(0.1)
|
|
end
|
|
local response_code=handle.response()
|
|
local ans=""
|
|
while true do
|
|
local tmp=handle.read()
|
|
if(tmp==nil) then break end
|
|
ans=ans .. tmp
|
|
end
|
|
handle.close()
|
|
return true,ans,response_code
|
|
end
|
|
function WriteStringToFile(StringValue,FileName,IsAppend)
|
|
if(IsAppend==nil) then IsAppend=false end
|
|
local handle,err
|
|
if(IsAppend) then
|
|
handle,err=io.open(FileName,"a")
|
|
else
|
|
handle,err=io.open(FileName,"w")
|
|
end
|
|
if(handle==nil) then return false,err end
|
|
|
|
handle:write(StringValue)
|
|
handle:close()
|
|
|
|
return true
|
|
end
|
|
|
|
-- TPM Main Programs
|
|
-- Installer
|
|
local function tpm_set_installed_list(tb)
|
|
local f=io.open("/etc/tpm/list.bin","w")
|
|
if(f==nil) then return false,"Unable to open file" end
|
|
local content=serialization.serialize(tb)
|
|
f:write(content)
|
|
f:close()
|
|
return true
|
|
end
|
|
|
|
local function tpm_get_installed_list()
|
|
local f=io.open("/etc/tpm/list.bin","r")
|
|
if(f==nil) then
|
|
f=io.open("/etc/tpm/list.bin","w")
|
|
if(f==nil) then
|
|
return false,"Unable to open file"
|
|
else
|
|
f:close()
|
|
tpm_set_installed_list({})
|
|
return true,{}
|
|
end
|
|
end
|
|
local content=f:read("a")
|
|
f:close()
|
|
return true,serialization.unserialize(content)
|
|
end
|
|
|
|
local function tpm_is_installed(libname)
|
|
local flg,tb=tpm_get_installed_list()
|
|
if(not flg) then
|
|
print("[tpm error] " .. tb)
|
|
return false
|
|
else
|
|
for k,v in pairs(tb) do
|
|
if(v.libname==libname) then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
end
|
|
local function tpm_mainfest_loader(data)
|
|
local f,err=load("return " .. data,"Mainfest","t",{})
|
|
if(f==nil) then
|
|
return false,err
|
|
end
|
|
local tb=f()
|
|
-- Check returned table
|
|
if(tb.libname==nil or tb.name==nil or tb.files==nil) then
|
|
return false
|
|
else
|
|
return true,tb
|
|
end
|
|
end
|
|
local function tpm_mainfest_show(mtb)
|
|
print("Library Name: " .. mtb.name)
|
|
print("libname: " .. mtb.libname)
|
|
print("Info: " .. (mtb.info or "Not provided"))
|
|
print("Author: " .. (mtb.author or "Not provided"))
|
|
print("Version: " .. (mtb.version or "Not provided"))
|
|
print("Setup: " .. (mtb.setup or "Not provided"))
|
|
print("Uninst: " .. (mtb.uninst or "Not provided"))
|
|
print("Required Directories: ")
|
|
if(mtb.dirs==nil) then
|
|
print("None")
|
|
else
|
|
for k,v in pairs(mtb.dirs) do
|
|
print(v)
|
|
end
|
|
end
|
|
print("Files:")
|
|
for k,v in pairs(mtb.files) do
|
|
print(k," -> ",v)
|
|
end
|
|
print("Dependency: ")
|
|
if(mtb.depends==nil) then
|
|
print("None")
|
|
else
|
|
for k,v in pairs(mtb.depends) do
|
|
print(v)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function tpm_install_github_real(repo,branch)
|
|
local config_url=resolve_github(repo,"mainfest.txt",branch)
|
|
local ret,data,code=doRealDownload(config_url)
|
|
if(not ret) then
|
|
return false,"Failed to download mainfest from repo " .. repo .. ". Error: " .. data
|
|
end
|
|
if(code~=200) then
|
|
return false,"Got response code " .. code .. " while downloading mainfest from repo " .. repo
|
|
end
|
|
local flg,tb=tpm_mainfest_loader(data)
|
|
if(not flg) then
|
|
return false,"Invalid mainfest in repo " .. repo .. " Error: " .. tb
|
|
end
|
|
|
|
-- Debug
|
|
tpm_mainfest_show(tb)
|
|
|
|
-- Check
|
|
if(tpm_is_installed(tb.libname)) then
|
|
print("Package " .. tb.libname .. " is already installed.")
|
|
return true
|
|
end
|
|
|
|
-- Depends
|
|
if(tb.depends~=nil) then
|
|
print("Analyzing dependency...")
|
|
local dependsz=#tb.depends
|
|
local cnt_now=1
|
|
for k,v in pairs(tb.depends) do
|
|
print("[" .. cnt_now .. "/" .. dependsz .. "] Checking " .. v .. "...")
|
|
local ret,msg=tpm_install(v)
|
|
if(not ret) then
|
|
return false,"An error occurs while analyzing dependency: " .. v .. ". Error: " .. msg
|
|
end
|
|
cnt_now=cnt_now+1
|
|
end
|
|
end
|
|
|
|
-- Make directories
|
|
if(tb.dirs~=nil) then
|
|
for k,v in pairs(tb.dirs) do
|
|
print("Making directory " .. v)
|
|
filesystem.makeDirectory(v)
|
|
end
|
|
end
|
|
|
|
-- Download
|
|
for k,v in pairs(tb.files) do
|
|
io.write("Downloading file " .. k .. "...")
|
|
local xret,xdata,xcode=doRealDownload(resolve_github(repo,k,branch))
|
|
if(not xret) then
|
|
print("[Failed]")
|
|
return false,"Failed to download " .. k
|
|
elseif(xcode~=200) then
|
|
print("[Failed]")
|
|
return false,"Response code is " .. xcode .. " while downloading " .. k
|
|
else
|
|
local xret,xmsg=WriteStringToFile(xdata,v)
|
|
if(not xret) then
|
|
print("[Write Failed]")
|
|
return false,"Failed to write to file " .. v .. " while downloading " .. k
|
|
end
|
|
|
|
-- OK here
|
|
print("[OK]")
|
|
end
|
|
end
|
|
|
|
-- Run Setup
|
|
if(tb.setup~=nil) then
|
|
print("Running setup...")
|
|
local setup_file=tb.files[tb.setup]
|
|
local setup_fn,err=loadfile(setup_file)
|
|
if(setup_fn==nil) then
|
|
print("Failed to start setup program. Error: " .. err)
|
|
end
|
|
local ret,msg=pcall(setup_fn)
|
|
if(not ret) then
|
|
printf("Failed to run setup program. Error: " .. msg)
|
|
end
|
|
end
|
|
|
|
-- Update software list
|
|
print("Updating software info...")
|
|
local flg,installed_lst=tpm_get_installed_list()
|
|
table.insert(installed_lst,tb)
|
|
tpm_set_installed_list(installed_lst)
|
|
print("Software info updated.")
|
|
return true
|
|
end
|
|
local function tpm_install_github(url)
|
|
local a=string.find(url,"/")
|
|
if(a==nil) then
|
|
return false,"Unknown format of github url"
|
|
end
|
|
|
|
local author=string.sub(url,1,a-1)
|
|
local reponame=''
|
|
local b=string.find(url,"/",a+1)
|
|
|
|
-- Branch set to master by default
|
|
local branch="master"
|
|
if(b~=nil) then
|
|
reponame=string.sub(url,a+1,b-1)
|
|
branch=string.sub(url,b+1)
|
|
else
|
|
reponame=string.sub(url,a+1)
|
|
end
|
|
|
|
local repo_fullname=author .. "/" .. reponame
|
|
print("Checking github repo " .. repo_fullname .. " at branch " .. branch .." ...")
|
|
|
|
return tpm_install_github_real(repo_fullname,branch)
|
|
end
|
|
local function tpm_install(install_url)
|
|
print("tpm_install: ",install_url)
|
|
if(beginWith(install_url,"github+")) then
|
|
return tpm_install_github(string.sub(install_url,string.len("github+")+1))
|
|
elseif(beginWith(install_url,"http+")) then
|
|
return tpm_install_http(string.sub(install_url,string.len("http+")+1))
|
|
else
|
|
return tpm_install_package(install_url)
|
|
end
|
|
end
|
|
|
|
if(args[1]=="install") then
|
|
if(argc<2) then
|
|
showerr("Package name or url is required.")
|
|
return
|
|
end
|
|
for i=2,argc,1 do
|
|
local ret,msg=tpm_install(args[i])
|
|
if(not ret) then
|
|
print("Failed to install task " .. (i-1) .. ". Error: " .. msg)
|
|
break
|
|
end
|
|
end
|
|
end |