2020-06-06 00:58:15 -04:00
local serial = require " serialization "
local dl = require " download "
2020-06-07 08:43:19 -04:00
local mtar = require " libmtar "
2020-06-06 00:58:15 -04:00
local pkg = { }
pkg.cfgPath = " /boot/cfg/pkg "
pkg.sourcePath = pkg.cfgPath .. " /sources.cfg "
pkg.installedPath = pkg.cfgPath .. " /installed.cfg "
2020-06-07 08:43:19 -04:00
local w , lz16 = pcall ( require , " liblz16 " )
if not w then lz16 = nil end
2023-08-01 06:48:19 -04:00
fs.makeDirectory ( " /boot/pkg " )
fs.makeDirectory ( " /boot/cfg/pkg " )
2020-06-07 08:43:19 -04:00
require " pkgfs "
2023-08-05 02:22:59 -04:00
local kver , kvar = _OSVERSION : match ( " (%x+)%-([^-]-)$ " )
kver , kvar = kver or " unknown " , kvar or " base "
2020-06-06 00:58:15 -04:00
local function getSources ( )
local f = io.open ( pkg.sourcePath , " rb " )
2020-06-07 20:36:36 -04:00
if not f then return { main = { path = " https://oc.shadowkat.net/psychos/pkg " , cache = true , name = " main " } } end
2020-06-06 00:58:15 -04:00
local c = f : read ( " *a " )
f : close ( )
return serial.unserialize ( c )
end
local function saveSources ( t )
fs.makeDirectory ( pkg.cfgPath )
local f = io.open ( pkg.sourcePath , " wb " )
f : write ( serial.serialize ( t ) )
f : close ( )
end
local function getInstalled ( )
local f = io.open ( pkg.installedPath , " rb " )
2023-08-05 02:22:59 -04:00
if not f then return { psychos = { version = kver } , [ " kernel- " .. kvar ] = { version = kver } } end
2020-06-06 00:58:15 -04:00
local c = f : read ( " *a " )
f : close ( )
return serial.unserialize ( c )
end
local function saveInstalled ( t )
fs.makeDirectory ( pkg.cfgPath )
local f = io.open ( pkg.installedPath , " wb " )
if not f then return false end
f : write ( serial.serialize ( t ) )
f : close ( )
end
local function getRepoMeta ( repo )
if not getSources ( ) [ repo ] . cache or not fs.exists ( " /boot/cfg/pkg/repo- " .. repo .. " .cfg " ) then
dl ( getSources ( ) [ repo ] . path .. " /packages.cfg " , " /boot/cfg/pkg/repo- " .. repo .. " .cfg " )
end
local f = io.open ( " /boot/cfg/pkg/repo- " .. repo .. " .cfg " , " rb " )
local rt = serial.unserialize ( f : read ( " *a " ) )
f : close ( )
if not getSources ( ) [ repo ] . cache then
fs.remove ( " /boot/cfg/pkg/repo- " .. repo .. " .cfg " )
end
return rt
end
local function activatePackage ( path , compressed )
require ( " pkgfs " ) . add ( path , compressed )
end
local function deactivatePackage ( path )
require ( " pkgfs " ) . remove ( path )
end
2020-06-07 08:43:19 -04:00
local function fnormalize ( s )
return table.concat ( fs.segments ( s ) , " / " )
end
local function installSystemPackage ( path , comp )
local f
if comp and lz16 then
f = lz16.open ( path , " rb " )
else
f = io.open ( path , " rb " )
end
for fname , read , size in mtar.iter ( f ) do
local opath = " /boot/ " .. fnormalize ( fname )
print ( opath .. " : " .. tostring ( size ) )
fs.makeDirectory ( opath : match ( " (.+)/[^/]+ " ) )
local of = io.open ( opath , " wb " )
if not of then error ( " unable to open " .. opath .. " for writing " ) end
local tmp
repeat
tmp = read ( 2048 ) or " "
of : write ( tmp )
until not tmp or tmp : len ( ) < 1
of : close ( )
end
return true
end
2020-06-06 00:58:15 -04:00
function pkg . addRepo ( name , path , cache ) -- string string boolean -- boolean -- Adds a repository, referred to as *name*, to the list of package sources, with the remote path *path*. If *cache* is set, keep a local copy of the repository index.
local sources = getSources ( )
sources [ name ] = { path = path , cache = cache , name = name }
saveSources ( sources )
end
function pkg . delRepo ( name ) -- string -- boolean -- Removes a repository from the list of repositories.
local sources = getSources ( )
sources [ name ] = nil
saveSources ( sources )
end
function pkg . update ( ) -- Re-download cached repository indexes.
for repo , meta in pairs ( getSources ( ) ) do
fs.remove ( " /boot/cfg/pkg/repo- " .. repo .. " .cfg " )
if meta.cache then
getRepoMeta ( repo )
end
end
end
2020-06-07 08:43:19 -04:00
function pkg . list ( filter , installed ) -- string boolean -- -- Print a list of available packages matching *filter*, optionally filtering to only installed packages if *installed* is set.
2020-06-06 00:58:15 -04:00
filter = filter or " "
local pkglist = { }
for repo , _ in pairs ( getSources ( ) ) do
for pkg , meta in pairs ( getRepoMeta ( repo ) ) do
if pkg : find ( filter ) or ( pkg.meta or " " ) : find ( filter ) then
meta.repo = repo
pkglist [ pkg ] = meta
end
end
end
for k , v in pairs ( pkglist ) do
2020-06-07 08:43:19 -04:00
if v.system then io.write ( " \27 [31m " ) end
print ( string.format ( " %s/%s: %s \27 [0m \n %s \n Authors: %s " , v.repo , k , v.name , v.description , v.authors ) )
2020-06-06 00:58:15 -04:00
end
end
function pkg . getMeta ( pkgname ) -- string -- table -- Returns the metadata for a the package specified in *pkgname*.
print ( " Finding package " .. pkgname )
for repo , info in pairs ( getSources ( ) ) do
local pkg = getRepoMeta ( repo ) [ pkgname ]
if pkg then
print ( " Package " .. pkgname .. " located in repo " .. repo .. " at " .. info.path )
pkg.repository = info
return pkg
end
end
end
2020-06-07 08:43:19 -04:00
function pkg . get ( pkgname , auto ) -- string boolean -- boolean -- Downloads and mounts a package, identified as *pkgname,* onto the pkgfs. Setting *auto* will flag the package as automatically installed; this is used for dependencies.
2020-06-06 00:58:15 -04:00
local pkginfo = pkg.getMeta ( pkgname )
if not pkginfo then error ( " unable to locate package " .. pkgname ) end
pkginfo.manual = not auto
fs.makeDirectory ( " /boot/pkg " )
for k , v in ipairs ( pkginfo.dependencies or { } ) do
if not getInstalled ( ) [ v ] then
2020-06-07 08:43:19 -04:00
pkg.get ( v , true )
2020-06-06 00:58:15 -04:00
end
end
dl ( pkginfo.repository . path .. " / " .. pkginfo.filename , " /boot/pkg/ " .. pkginfo.filename )
local installed = getInstalled ( )
installed [ pkgname ] = pkginfo
saveInstalled ( installed )
2020-06-07 08:43:19 -04:00
if pkginfo.system then
local rv = installSystemPackage ( " /boot/pkg/ " .. pkginfo.filename , pkginfo.compressed )
fs.remove ( " /boot/pkg/ " .. pkginfo.filename )
return rv
end
2020-06-06 00:58:15 -04:00
pcall ( activatePackage , " /boot/pkg/ " .. pkginfo.filename , pkginfo.compressed )
return true
end
2020-06-07 08:43:19 -04:00
function pkg . upgrade ( force ) -- boolean -- -- Upgrades all packages on the system to the current version stored in the relevant repository. If *force* is set, re-download all packages.
2020-06-06 00:58:15 -04:00
pkg.update ( )
fs.makeDirectory ( " /boot/pkg " )
local installed = getInstalled ( )
for repo , info in pairs ( getSources ( ) ) do
2020-06-06 06:24:15 -04:00
for pkgname , pkginfo in pairs ( getRepoMeta ( repo ) ) do
if installed [ pkgname ] and pkginfo.version ~= installed [ pkgname ] . version or force then
2020-06-06 05:48:21 -04:00
pkg.remove ( pkgname )
2020-06-07 08:43:19 -04:00
pkg.get ( pkgname , pkginfo.auto )
2020-06-06 00:58:15 -04:00
end
end
end
end
function pkg . remove ( pkgname ) -- string -- boolean -- Remove the package *pkgname* from the pkgfs and package directory.
local installed = getInstalled ( )
local pkginfo = installed [ pkgname ]
2020-06-06 06:24:15 -04:00
if not pkginfo then return true end
2020-06-06 00:58:15 -04:00
pcall ( deactivatePackage , " /boot/pkg/ " .. pkginfo.filename )
fs.remove ( " /boot/pkg/ " .. pkginfo.filename )
2020-06-07 08:43:19 -04:00
if pkginfo.system then
for k , v in pairs ( pkginfo.files ) do
fs.remove ( v )
end
end
2020-06-06 00:58:15 -04:00
installed [ pkgname ] = nil
saveInstalled ( installed )
return true
end
return pkg