2018-11-24 00:49:01 +08:00
-- Grab : Official OpenComputerScripts Installer
2018-11-17 17:26:07 +08:00
-- Created By Kiritow
2018-11-21 12:14:03 +08:00
local computer = require ( ' computer ' )
2018-11-17 17:26:07 +08:00
local component = require ( ' component ' )
local shell = require ( ' shell ' )
2018-11-21 11:55:45 +08:00
local filesystem = require ( ' filesystem ' )
local serialization = require ( ' serialization ' )
2018-11-24 16:04:29 +08:00
local event = require ( ' event ' )
2018-11-30 17:48:05 +08:00
local term = require ( ' term ' )
2018-11-17 17:26:07 +08:00
local args , options = shell.parse ( ... )
2018-11-24 00:49:01 +08:00
2019-03-13 00:52:20 +08:00
local grab_version = " Grab v2.5.1.2-alpha "
2019-01-17 20:13:10 +08:00
local grab_infos = {
version = grab_version ,
grab_options = options
2018-12-07 20:08:56 +08:00
}
2018-11-30 17:48:05 +08:00
local usage_text = [ === [ Grab - Official OpenComputerScripts Installer
Usage :
grab [ < options > ] < command > ...
Options :
2019-01-17 23:39:31 +08:00
--cn Skip link check and use mirror site in China. See Link check in Notice for more information.
2018-11-30 17:48:05 +08:00
--help Display this help page.
--version Display version and exit.
2019-01-17 23:39:31 +08:00
--router=<Router File> [Deprecated] Given a file which will be loaded and returns a route function like:
2018-11-30 17:48:05 +08:00
function ( RepoName : string , Branch : string , FileAddress : string ) : string
2018-12-03 15:24:35 +08:00
--proxy=<Proxy File> Given a file which will be loaded and returns a proxy function like:
function ( Url : string ) : boolean , string
2019-01-07 19:34:59 +08:00
--bin=<path> Set binary install root path.
--lib=<path> Set library install root path.
2019-01-07 20:18:34 +08:00
- f , --force Force overwrite existing files.
2019-01-10 16:38:46 +08:00
- y , --yes Skip interactive confirm.
2018-11-30 17:48:05 +08:00
--skip-install Library installers will not be executed.
--refuse-license <License> Set refused license. Separate multiple values with ','
--accept-license <License> Set accepted license. Separate multiple values with ','
Command :
2019-01-10 11:35:06 +08:00
install < Project > ... : Install projects . Dependency will be installed automatically .
2019-01-14 17:39:49 +08:00
uninstall < Project > ... : Uninstall projects . Dependency will NOT be removed automatically .
2018-12-03 14:16:35 +08:00
verify < Provider > ... : Verify program provider info .
2018-11-30 17:48:05 +08:00
add < Provider > ... : Add program provider info .
update : Update program info .
clear : Clear program info .
list : List available projects .
search < Name or Pattern > : Search projects by name
show < Project > : Show more info about project .
download < Filename > ... : Directly download files . ( Just like the old ` update ` ! )
Notice :
License
By downloading and using Grab , you are indicating your agreement to MIT license . ( https : // github.com / Kiritow / OpenComputerScripts / blob / master / LICENSE )
All scripts in official OpenComputerScript repository are under MIT license .
Before downloading any package under other licenses , Grab will ask you to agree with it .
This confirmation can be skipped by calling Grab with --accept-license.
Example :
--accept-license=mit means MIT License is accepted.
--refuse-license=mit means MIT License is refused.
--accept-license means all licenses are accepted.
--refuse-license means all licenses are refused. (Official packages are not affected.)
If a license is both accepted and refused , it will be refused .
Program Provider
A package is considered to be official only if it does not specified repo and proxy . Official packages usually only depend on official packages .
You can also install packages from unofficial program provider with Grab , but Grab will not check its security .
Notice that override of official packages is not allowed .
2018-12-03 15:24:35 +08:00
Router and Proxy
2019-01-17 23:39:31 +08:00
[ Deprecated ] route_func ( RepoName : string , Branch : string , FileAddress : string ) : string
2018-12-03 15:24:35 +08:00
A route function takes repo , branch and file address as arguments , and returns a resolved url .
It can be used to boost downloading by redirecting requests to mirror site .
As router functions can be used to redirect requests , Grab will give an warning if --router option presents.
2019-01-17 23:39:31 +08:00
[ Warning ] --router option is deprecated and will be removed in future.
2018-12-03 15:24:35 +08:00
proxy_func ( Url : string ) : boolean , string
A proxy function takes url as argument , and returns at least 2 values .
It can be used to handle different protocols or low - level network operations like downloading files via SOCKS5 proxy or in - game modem network .
The first returned value is true if content is downloaded successfully . Thus , the second value will be the downloaded content .
If the first value is false , the downloading is failed . The second value will then be the error message .
If proxy functions throw an error , Grab will try the default downloader .
2018-12-08 10:57:05 +08:00
Installer
A package can provide an installer for Grab . It will be loaded and executed after the package is ready .
Thus require ( ... ) calls on depended libraries is ok .
2019-01-17 20:13:10 +08:00
From Grab v2 .4 .6 , installer should return a function , which will be later called with a table filled with some information .
2018-12-08 10:57:05 +08:00
If nothing is returned , Grab will give an warning and ignore it .
2019-01-07 19:34:59 +08:00
From Grab v2 .4 .8 , option ` installer ` is deprecated . Use __installer__ instead .
2019-01-17 23:39:31 +08:00
Link Check
Grab will perform a link check before downloading anything . The link check will choose to download from Github or mirror site in China .
This might only be useful for official packages .
2018-11-30 17:48:05 +08:00
] === ]
2019-01-10 11:35:06 +08:00
-- Install man document.
local function _local_install ( )
2018-11-30 18:19:58 +08:00
local f = io.open ( " /etc/grab/grab.version " , " w " )
if ( f ) then
f : write ( grab_version )
f : close ( )
end
f = io.open ( " /usr/man/grab " , " w " )
2018-11-30 17:48:05 +08:00
if ( f ) then
f : write ( usage_text )
f : close ( )
end
2018-12-03 15:24:35 +08:00
end
if ( not filesystem.exists ( " /etc/grab/grab.version " ) ) then
2019-01-10 11:35:06 +08:00
_local_install ( )
2018-11-30 18:19:58 +08:00
else
local f = io.open ( " /etc/grab/grab.version " , " r " )
if ( f ) then
local installed_version = f : read ( " a " )
f : close ( )
if ( installed_version ~= grab_version ) then
2019-01-10 11:35:06 +08:00
_local_install ( )
2018-11-30 18:19:58 +08:00
end
end
2018-11-30 17:48:05 +08:00
end
local function show_usage ( )
if ( filesystem.exists ( " /usr/man/grab " ) ) then
os.execute ( " less /usr/man/grab " )
else
local temp_name = os.tmpname ( )
local f = io.open ( temp_name , " w " )
f : write ( usage_text )
f : close ( )
os.execute ( " less " .. temp_name )
os.execute ( " rm " .. temp_name )
end
end
2018-11-24 00:49:01 +08:00
local valid_options = {
2018-11-30 17:48:05 +08:00
[ " cn " ] = true ,
[ " help " ] = true ,
[ " version " ] = true ,
2018-12-03 15:24:35 +08:00
[ " router " ] = " string " ,
[ " proxy " ] = " string " ,
2019-01-07 19:34:59 +08:00
[ " bin " ] = " string " ,
[ " lib " ] = " string " ,
2019-01-07 20:18:34 +08:00
[ " f " ] = true ,
[ " force " ] = true ,
2019-01-10 16:38:46 +08:00
[ " y " ] = true ,
[ " yes " ] = true ,
2018-11-30 17:48:05 +08:00
[ " skip-install " ] = true ,
[ " refuse-license " ] = true ,
2019-01-07 19:34:59 +08:00
[ " accept-license " ] = true ,
2018-11-24 00:49:01 +08:00
}
local valid_command = {
2018-11-26 00:49:18 +08:00
[ " install " ] = true ,
2019-01-10 11:35:06 +08:00
[ " uninstall " ] = true ,
2018-12-03 14:16:35 +08:00
[ " verify " ] = true ,
2018-11-30 17:48:05 +08:00
[ " add " ] = true ,
[ " update " ] = true ,
[ " clear " ] = true ,
[ " list " ] = true ,
[ " search " ] = true ,
[ " show " ] = true ,
2018-11-26 00:49:18 +08:00
[ " download " ] = true
2018-11-24 00:49:01 +08:00
}
for k , v in pairs ( options ) do
if ( not valid_options [ k ] ) then
2018-12-03 15:24:35 +08:00
if ( string.len ( k ) > 1 ) then
print ( " Unknown option: -- " .. k )
else
print ( " Unknown option: - " .. k )
end
2018-11-24 00:49:01 +08:00
return
2018-12-03 15:24:35 +08:00
elseif ( type ( valid_options [ k ] ) == " string " ) then
if ( type ( options [ k ] ) ~= valid_options [ k ] ) then
print ( " Invalid option type: Option type of -- " .. k .. " should be " .. valid_options [ k ] )
return
end
2018-11-24 00:49:01 +08:00
end
end
2019-01-10 16:38:46 +08:00
if ( # args < 1 and not next ( options ) ) then
print ( " grab: try 'grab --help' for more information. " )
return
end
if ( options [ " help " ] ) then
2018-11-24 00:49:01 +08:00
show_usage ( )
return
2018-11-17 17:26:07 +08:00
end
2018-11-24 00:49:01 +08:00
2018-11-17 19:21:26 +08:00
if ( options [ " version " ] ) then
2018-11-24 00:49:01 +08:00
print ( grab_version )
2018-11-17 19:21:26 +08:00
return
end
2018-11-24 00:49:01 +08:00
2019-01-10 16:38:46 +08:00
local function optionYes ( )
return options [ " y " ] or options [ " yes " ]
end
local function optionForce ( )
return options [ " f " ] or options [ " force " ]
end
2018-12-03 15:24:35 +08:00
local function check_internet ( )
2018-12-03 16:58:54 +08:00
if ( not options [ " proxy " ] and not component.list ( " internet " ) ( ) ) then
2018-12-03 15:24:35 +08:00
print ( " Error: An internet card is required to run this program. " )
return false
else
-- If proxy presents, internet card is not required. Programs may handle network requests via in-game modem network.
return true
end
end
local function default_downloader ( url )
2018-12-03 16:58:54 +08:00
if ( not component.list ( " internet " ) ( ) ) then
2018-12-03 15:24:35 +08:00
return false , " No internet card found. "
2018-11-17 17:26:07 +08:00
end
2018-12-03 15:24:35 +08:00
2018-11-17 17:26:07 +08:00
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
2018-11-24 01:29:56 +08:00
else
2018-11-30 03:14:49 +08:00
local ev = event.pull ( 0.05 , " interrupted " )
2018-11-24 01:29:56 +08:00
if ( ev ~= nil ) then
handle.close ( )
return false , " Interrupted from terminal. "
end
2018-11-17 17:26:07 +08:00
end
end
2018-12-03 15:24:35 +08:00
2018-11-17 17:26:07 +08:00
local code = handle.response ( )
2018-12-03 15:24:35 +08:00
if ( code ~= 200 ) then
handle.close ( )
return false , " Response code " .. code .. " is not 200. "
end
2018-11-17 17:26:07 +08:00
local result = ' '
while true do
local temp = handle.read ( )
if ( temp == nil ) then break end
result = result .. temp
end
2018-12-03 15:24:35 +08:00
2018-11-17 17:26:07 +08:00
handle.close ( )
2018-12-03 15:24:35 +08:00
return true , result
2018-11-17 17:26:07 +08:00
end
2018-12-03 15:24:35 +08:00
local download
if ( not options [ " proxy " ] ) then
download = default_downloader
2018-11-17 17:26:07 +08:00
else
2018-11-17 19:21:26 +08:00
local ok , err = pcall ( function ( )
2018-11-26 01:33:41 +08:00
local fn , xerr = loadfile ( options [ " proxy " ] )
2018-12-03 15:24:35 +08:00
if ( not fn ) then
error ( xerr )
else
2018-12-03 16:58:54 +08:00
tmp = fn ( )
if ( type ( tmp ) ~= " function " ) then
error ( " Loaded proxy returns " .. type ( tmp ) .. " instead of a function. " )
end
download = function ( url )
local pok , ok , data = pcall ( tmp , url )
if ( pok ) then
return ok , data
else
return default_downloader ( url )
end
2018-12-03 15:24:35 +08:00
end
end
2018-11-17 19:21:26 +08:00
end )
if ( not ok ) then
2018-11-26 01:33:41 +08:00
print ( " Unable to load proxy file: " .. err )
2018-11-17 19:21:26 +08:00
return
2018-11-17 17:26:07 +08:00
end
2018-12-03 15:24:35 +08:00
print ( " [WARN] Proxy presents. Be aware of security issues. " )
2018-11-17 17:26:07 +08:00
end
2018-11-21 11:55:45 +08:00
2019-01-17 23:39:31 +08:00
local function link_check ( )
local ok , data = download ( " http://registry.kiritow.com/gateway " )
if ( ok and data == " CN " ) then
2018-11-30 17:48:05 +08:00
return true
else
return false
end
end
2019-01-17 23:39:31 +08:00
local function _MirrorUrlGen ( RepoName , Branch , FileAddress )
return " http://kiritow.com:3000/ " .. RepoName .. " /raw/ " .. Branch .. " / " .. FileAddress
end
local function _GithubUrlGen ( RepoName , Branch , FileAddress )
return " https://raw.githubusercontent.com/ " .. RepoName .. " / " .. Branch .. " / " .. FileAddress
end
local UrlGenerator
if ( not options [ " router " ] ) then
if ( options [ " cn " ] or link_check ( ) ) then
UrlGenerator = _MirrorUrlGen
else
UrlGenerator = _GithubUrlGen
end
else
print ( " [WARN] --router option is deprecated and will be removed in future. " )
local ok , err = pcall ( function ( )
local fn , xerr = loadfile ( options [ " router " ] )
if ( not fn ) then
error ( xerr )
else
UrlGenerator = fn ( )
if ( type ( UrlGenerator ) ~= " function " ) then
error ( " Loaded router returns " .. type ( UrlGenerator ) .. " instead of a function. " )
end
end
end )
if ( not ok ) then
print ( " Unable to load router file: " .. err )
return
end
print ( " [WARN] Router presents. Be aware of security issues. " )
end
local function IsOfficial ( tb_package )
if ( tb_package.repo == nil and
tb_package.proxy == nil and
tb_package.provider == nil
) then
return true
2018-12-03 15:24:35 +08:00
else
return false
end
end
2019-01-25 22:50:41 +08:00
local grab_dir = ' '
local function CheckGrabDir ( )
local locations = { " /etc/grab " , " /home/.grab " , " /tmp/.grab " }
for idx , position in ipairs ( locations ) do
if ( filesystem.isDirectory ( position ) ) then
grab_dir = position
return true
else
local ok = filesystem.makeDirectory ( position )
if ( ok ) then grab_dir = position return true end
end
end
return false
end
if ( not CheckGrabDir ( ) ) then
print ( " [Error] Grab working directory not usable. " )
return
else
print ( " Grab directory: " .. grab_dir )
end
2018-11-21 11:55:45 +08:00
2018-11-30 17:48:05 +08:00
local function VerifyDB ( this_db )
for k , t in pairs ( this_db ) do
if ( type ( k ) ~= " string " ) then
return false , " Invalid key type: " .. type ( k )
elseif ( type ( t ) ~= " table " ) then
return false , " Invalid value type: " .. type ( t )
elseif ( not t.title ) then
return false , " Library " .. k .. " does not provide title. "
elseif ( not t.info ) then
return false , " Library " .. k .. " does not provide info. "
elseif ( not t.files ) then
return false , " Library " .. k .. " has no file. "
end
for kk , vv in pairs ( t.files ) do
if ( type ( kk ) == " number " ) then
if ( type ( vv ) ~= " string " ) then
return false , " Library " .. k .. " file " .. kk .. " has invalid value type " .. type ( vv )
end
elseif ( type ( kk ) == " string " ) then
2018-12-07 13:38:30 +08:00
if ( type ( vv ) == " table " ) then
for idx , val in pairs ( vv ) do
if ( type ( idx ) ~= " number " or type ( val ) ~= " string " ) then
return false , " Library " .. k .. " file " .. kk .. " table has invalid key,value type: " .. type ( idx ) .. " , " .. type ( val )
end
end
elseif ( type ( vv ) ~= " string " ) then
2018-11-30 17:48:05 +08:00
return false , " Library " .. k .. " file " .. kk .. " has invalid value type " .. type ( vv )
end
else
2018-12-03 16:58:54 +08:00
return false , " Library " .. k .. " file has invalid key type " .. type ( kk )
2018-11-30 17:48:05 +08:00
end
end
2018-12-07 13:38:30 +08:00
if ( t.author and type ( t.author ) ~= " string " ) then
return false , " Library " .. k .. " has invalid author type: " .. type ( t.author )
end
if ( t.contact and type ( t.contact ) ~= " string " ) then
return false , " Library " .. k .. " has invalid contact type: " .. type ( t.contact )
end
2018-11-30 17:48:05 +08:00
if ( t.requires ) then
for kk , vv in pairs ( t.requires ) do
2018-12-07 13:38:30 +08:00
if ( type ( kk ) ~= " number " or type ( vv ) ~= " string " ) then
2018-11-30 17:48:05 +08:00
return false , " Library " .. k .. " has invalid requires with key type " .. type ( kk ) .. " , value type " .. type ( vv )
end
end
end
if ( t.license ) then
if ( type ( t.license . name ) ~= " string " ) then
return false , " Library " .. k .. " has invalid license name type " .. type ( t.license . name )
elseif ( type ( t.license . url ) ~= " string " ) then
return false , " Library " .. k .. " has invalid license url type " .. type ( t.license . url )
end
end
2018-12-03 16:58:54 +08:00
if ( t.provider ) then
if ( type ( t.provider ) ~= " string " ) then
return false , " Library " .. k .. " has invalid provider type " .. type ( t.provider )
end
end
2018-12-07 13:38:30 +08:00
if ( t.hidden ~= nil ) then
if ( type ( t.hidden ) ~= " boolean " ) then
return false , " Library " .. k .. " has invalid hidden type " .. type ( t.hidden )
end
end
2018-11-30 17:48:05 +08:00
end
return true , " No error detected. "
end
2019-01-08 08:46:53 +08:00
local function CheckAndLoadEx ( raw_content , chunkname )
local fn , err = load ( raw_content , chunkname )
2018-11-21 11:55:45 +08:00
if ( fn ) then
local ok , result = pcall ( fn )
2018-11-30 17:48:05 +08:00
if ( ok ) then
return result
2018-11-21 11:55:45 +08:00
else return nil , result end
end
return nil , err
2018-11-17 17:26:07 +08:00
end
2018-11-21 11:55:45 +08:00
2019-01-08 08:46:53 +08:00
local function CheckAndLoad ( raw_content , chunkname )
local result , err = CheckAndLoadEx ( raw_content , chunkname )
2018-11-30 17:48:05 +08:00
if ( not result ) then
return result , err
end
local ok , err = VerifyDB ( result )
if ( not ok ) then
return nil , err
else
return result
end
end
2018-11-24 01:29:56 +08:00
local function ReadDB ( read_from_this )
if ( read_from_this ) then
local f = io.open ( read_from_this , " r " )
2018-11-21 11:55:45 +08:00
if ( f ) then
local result = serialization.unserialize ( f : read ( " *a " ) )
2018-11-17 17:26:07 +08:00
f : close ( )
2018-11-21 11:55:45 +08:00
return result , filename
2018-11-24 01:29:56 +08:00
else
return nil
2018-11-17 17:26:07 +08:00
end
2018-11-21 11:55:45 +08:00
end
2018-11-24 01:29:56 +08:00
2019-01-25 22:50:41 +08:00
local filename = grab_dir .. " /programs.info "
local a , b = ReadDB ( filename )
if ( a ) then return a , b end
2018-11-24 01:29:56 +08:00
2018-11-21 11:55:45 +08:00
return nil
end
2018-11-24 01:29:56 +08:00
local function WriteDB ( filename , tb )
2018-11-21 11:55:45 +08:00
local f = io.open ( filename , " w " )
if ( f ) then
2018-11-24 01:29:56 +08:00
f : write ( serialization.serialize ( tb ) )
2018-11-21 11:55:45 +08:00
f : close ( )
return true
end
return false
end
2018-11-30 17:48:05 +08:00
local function UpdateDB ( main_tb , new_tb , checked ) -- Change values with same key in main_tb to values in new_tb. Add new items to main_tb
2018-11-24 01:29:56 +08:00
for k , v in pairs ( new_tb ) do
2018-11-30 17:48:05 +08:00
if ( checked and main_tb [ k ] ) then
if ( IsOfficial ( main_tb [ k ] ) ) then
print ( " UpdateDB: Attempted to override official library: " .. k )
return false
else
print ( " UpdateDB: Override library: " .. k )
end
end
2018-11-24 01:29:56 +08:00
main_tb [ k ] = v
end
2018-11-30 17:48:05 +08:00
return true
2018-11-24 01:29:56 +08:00
end
2018-11-30 17:48:05 +08:00
local function CreateDB ( tb , checked ) -- If checked, merging is not allowed.
2019-01-25 22:50:41 +08:00
local filename = grab_dir .. " /programs.info "
local main_db = ReadDB ( filename )
if ( main_db ) then
if ( not UpdateDB ( main_db , tb , checked ) ) then
return nil
end
if ( WriteDB ( filename , main_db ) ) then
return filename
end
else
if ( WriteDB ( filename , tb ) ) then
return filename
2018-11-21 11:55:45 +08:00
end
end
end
2019-01-25 23:14:15 +08:00
local function GetDBVersion ( )
local f = io.open ( grab_dir .. " /list.version " , " rb " )
if ( not f ) then
return ' '
else
local s = f : read ( " *a " )
f : close ( )
return s
end
end
local function SaveDBVersion ( ver )
local f = io.open ( grab_dir .. " /list.version " , " wb " )
if ( not f ) then
return false
else
f : write ( ver )
f : close ( )
return true
end
end
2018-11-26 00:49:18 +08:00
if ( args [ 1 ] == " clear " ) then
print ( " Clearing programs info... " )
2019-01-25 22:50:41 +08:00
filesystem.remove ( grab_dir .. " /programs.info " )
2018-11-26 00:49:18 +08:00
print ( " Programs info cleaned. You may want to run `grab update` now. " )
return
end
2018-11-21 11:55:45 +08:00
if ( args [ 1 ] == " update " ) then
2018-11-24 00:49:01 +08:00
if ( not check_internet ( ) ) then return end
2019-01-25 23:14:15 +08:00
print ( " Checking package list version... " )
local ok , result = download ( " http://registry.kiritow.com/listver " )
2019-03-13 00:52:20 +08:00
local remoteURL
local remoteVer
2019-01-25 23:14:15 +08:00
if ( not ok ) then
2019-03-13 00:52:20 +08:00
print ( " [Skipped] Skipped package list version checking: " .. result )
remoteURL = UrlGenerator ( ' Kiritow/OpenComputerScripts ' , ' master ' , ' programs.info ' )
remoteVer = nil
else
if ( GetDBVersion ( ) == result ) then
print ( " Already up to date. " )
else
remoteURL = " http://registry.kiritow.com/list/ " .. result
remoteVer = result
end
2019-01-25 23:14:15 +08:00
end
print ( " Updating package list.... " )
2018-11-21 11:55:45 +08:00
io.write ( " Downloading... " )
2019-03-13 00:52:20 +08:00
ok , result = download ( remoteURL )
2018-11-17 17:26:07 +08:00
if ( not ok ) then
2018-11-21 11:55:45 +08:00
print ( " [Failed] " .. result )
2019-01-25 23:14:15 +08:00
return
2018-11-21 11:55:45 +08:00
else
print ( " [OK] " )
io.write ( " Validating... " )
2019-01-08 08:46:53 +08:00
local tb_data , validate_err = CheckAndLoad ( " return " .. result , " Remote ProgramDB " )
2018-11-21 11:55:45 +08:00
result = nil -- release memory
if ( tb_data ) then
print ( " [OK] " )
io.write ( " Saving files... " )
2018-11-30 17:48:05 +08:00
local dbfilename = CreateDB ( tb_data , false )
2018-11-21 11:55:45 +08:00
if ( dbfilename ) then
print ( " [OK] " )
2019-01-25 23:14:15 +08:00
print ( " Package list updated and saved to " .. dbfilename )
2018-11-21 11:55:45 +08:00
else
2019-01-25 23:14:15 +08:00
print ( " [Failed] Unable to save package list. " )
return
2018-11-21 11:55:45 +08:00
end
else
print ( " [Failed] " .. validate_err )
2019-01-25 23:14:15 +08:00
return
2018-11-21 11:55:45 +08:00
end
2018-11-17 17:26:07 +08:00
end
2018-11-21 11:55:45 +08:00
2019-01-25 23:14:15 +08:00
print ( " Updating package list version... " )
2019-03-13 00:52:20 +08:00
if ( remoteVer ) then
SaveDBVersion ( remoteVer )
else
print ( " [Skipped] Not update from registry. " )
end
2019-01-25 23:14:15 +08:00
2018-11-21 11:55:45 +08:00
return
end
local db , dbfilename = ReadDB ( )
2018-11-24 01:29:56 +08:00
local function check_db ( )
if ( db ) then return true
else
print ( " No programs info found on this computer. " )
print ( " Please run `grab update` first. " )
return false
end
end
2018-12-31 01:02:46 +08:00
local function pairsKey ( tb )
local tmp = { }
for k in pairs ( tb ) do table.insert ( tmp , k ) end
table.sort ( tmp )
local i = 0
return function ( )
i = i + 1
return tmp [ i ] , tb [ tmp [ i ] ]
end , tb , nil
end
2018-12-03 14:16:35 +08:00
if ( args [ 1 ] == " verify " ) then
if ( # args < 2 ) then
print ( " Nothing to verify. " )
return
end
for i = 2 , # args , 1 do
local url = string.match ( args [ i ] , " ^http[s]?://%S+ " )
if ( url == nil ) then
local filename = args [ i ]
local f = io.open ( filename , " r " )
if ( not f ) then
print ( " Unable to open local file: " .. filename )
else
local content = f : read ( " *a " )
f : close ( )
2019-01-08 08:46:53 +08:00
local t , err = CheckAndLoad ( " return " .. content , " Local ProgramDB " )
2018-12-03 14:16:35 +08:00
if ( t ) then
print ( " [Verified] Contains the following library: " )
2018-12-31 01:02:46 +08:00
for k in pairsKey ( t ) do
2018-12-03 14:16:35 +08:00
print ( k )
end
else
print ( " Failed to load local file: " .. filename .. " . Error: " .. err )
end
end
else
print ( " Downloading from " .. url )
2018-12-03 15:24:35 +08:00
local ok , result = download ( url )
2018-12-03 14:16:35 +08:00
if ( not ok ) then
print ( " [Download Failed] " .. result )
else
2019-01-08 08:46:53 +08:00
local t , err = CheckAndLoad ( " return " .. result , " Remote ProgramDB " )
2018-12-03 14:16:35 +08:00
if ( t ) then
print ( " [Verified] Contains the following library: " )
for k in pairs ( t ) do
print ( k )
end
else
print ( " Failed to load downloaded content. Error: " .. err )
end
end
end
end
return
end
2018-11-26 00:49:18 +08:00
if ( args [ 1 ] == " add " ) then
if ( # args < 2 ) then
print ( " Nothing to add. " )
2018-11-30 03:14:49 +08:00
return
2018-11-26 00:49:18 +08:00
end
if ( not check_db ( ) ) then
return
end
2018-11-26 01:33:41 +08:00
print ( " [WARN] Adding unofficial program providers may have security issues. " )
2018-11-26 00:49:18 +08:00
for i = 2 , # args , 1 do
local url = string.match ( args [ i ] , " ^http[s]?://%S+ " )
if ( url == nil ) then
local filename = args [ i ]
local f = io.open ( filename , " r " )
if ( not f ) then
print ( " Unable to open local file: " .. filename )
else
local content = f : read ( " *a " )
f : close ( )
2019-01-08 08:46:53 +08:00
local t , err = CheckAndLoad ( " return " .. content , " Local ProgramDB " )
2018-11-26 00:49:18 +08:00
if ( t ) then
print ( " Updating with local file: " .. filename )
2018-11-30 17:48:05 +08:00
local fname = CreateDB ( t , true )
2018-11-26 00:49:18 +08:00
if ( fname ) then
print ( " Programs info updated and saved to " .. fname )
else
print ( " Unable to update programs info. " )
end
else
print ( " Failed to load local file: " .. filename .. " . Error: " .. err )
end
end
else
print ( " Downloading from " .. url )
2018-12-03 15:24:35 +08:00
local ok , result = download ( url )
2018-11-26 00:49:18 +08:00
if ( not ok ) then
print ( " [Download Failed] " .. result )
else
2019-01-08 08:46:53 +08:00
local t , err = CheckAndLoad ( " return " .. result , " Remote ProgramDB " )
2018-11-26 00:49:18 +08:00
if ( t ) then
print ( " Updating with downloaded content... " )
2018-11-30 17:48:05 +08:00
local fname = CreateDB ( t , true )
2018-11-26 00:49:18 +08:00
if ( fname ) then
print ( " Programs info updated and saved to " .. fname )
else
print ( " Unable to update programs info. " )
end
else
print ( " Failed to load downloaded content. Error: " .. err )
end
end
end
end
return
end
2018-11-30 11:10:08 +08:00
local function getshowbyte ( n )
if ( n < 1024 ) then
return string.format ( " %.1f B " , n + 0.0 )
elseif ( n < 1024 * 1024 ) then
return string.format ( " %.1f KB " , n / 1024 )
else
return string.format ( " %.1f MB " , n / 1024 / 1024 )
end
end
local function getshowtime ( n )
if ( n < 60 ) then
return string.format ( " %.1fs " , n + 0.0 )
else
return string.format ( " %.0fm%.0fs " , n / 3600 , n % 3600 )
end
end
2018-12-07 20:08:56 +08:00
local function getshowspeed ( n )
if ( n < 1024 ) then
return string.format ( " %.1f B/s " , n + 0.0 )
elseif ( n < 1024 * 1024 ) then
return string.format ( " %.1f KB/s " , n / 1024 )
else
return string.format ( " %.1f MB/s " , n / 1024 / 1024 )
end
end
2019-01-10 16:02:50 +08:00
local function try_resolve_path ( src , dst , only_parse )
2018-12-07 20:08:56 +08:00
-- TIPS:
-- filesystem.makeDirectory(...) can throw error because it does not check arguments.
2019-01-10 16:02:50 +08:00
local fsMakeDir
if ( not only_parse ) then
fsMakeDir = filesystem.makeDirectory
else
fsMakeDir = function ( ) return true end
end
2019-01-07 19:34:59 +08:00
if ( type ( src ) ~= " string " ) then -- Only source path is specified in programs.info
2019-01-07 14:27:51 +08:00
local segs = filesystem.segments ( dst )
return true , segs [ # segs ]
end
2018-12-07 20:08:56 +08:00
2019-01-07 19:34:59 +08:00
dst = string.gsub (
string.gsub (
dst ,
" __bin__ " ,
options [ " bin " ] or " /usr/bin "
) ,
" __lib__ " ,
options [ " lib " ] or " /usr/lib "
)
if ( dst : sub ( dst : len ( ) ) == ' / ' ) then -- dst is a directory. prepare it and build the filename.
2019-01-10 16:02:50 +08:00
if ( not fsMakeDir ( dst ) and not filesystem.exists ( dst ) ) then
2018-12-07 20:08:56 +08:00
return false , " Failed to create directory: " .. dst
else
local tb_segsrc = filesystem.segments ( src )
2019-01-07 19:34:59 +08:00
return true , dst .. tb_segsrc [ # tb_segsrc ]
2018-12-07 20:08:56 +08:00
end
2019-01-07 19:34:59 +08:00
else -- dst is the filename. Prepare directories.
2018-12-31 01:42:46 +08:00
local tb_segdst = filesystem.segments ( dst )
2018-12-07 20:08:56 +08:00
if ( # tb_segdst > 1 ) then
local name = table.concat ( tb_segdst , " / " , 1 , # tb_segdst - 1 )
2019-01-10 16:02:50 +08:00
if ( not fsMakeDir ( name ) and not filesystem.exists ( name ) ) then
2018-12-07 20:08:56 +08:00
return false , " Failed to create directory: " .. name
end
end
return true , dst
end
end
2018-12-07 13:38:30 +08:00
local function string_similar_value ( a , b )
local x , y = a : len ( ) , b : len ( )
local min = ( ( x > y ) and y or x )
local c = 0
for i = 1 , min do
if ( a : sub ( i , i ) == b : sub ( i , i ) ) then
c = c + 1
end
end
return c
end
local function miss_suggestion ( wrong_name , ktb )
local max = 0
local maxname = nil
for this_lib in pairs ( ktb ) do
local a = string_similar_value ( wrong_name , this_lib )
if ( a > max ) then
max = a
maxname = this_lib
end
end
return maxname , max
end
2019-01-07 20:18:34 +08:00
local function will_overwrite ( filename )
2019-01-10 16:38:46 +08:00
if ( optionForce ( ) ) then
2019-01-07 20:18:34 +08:00
return false
else
local f = io.open ( filename , " rb " )
if ( f ) then
f : close ( )
print ( " [Error] Stop before overwrite regular file: " .. filename )
return true
else
return false
end
end
end
2018-11-21 11:55:45 +08:00
if ( args [ 1 ] == " install " ) then
if ( # args < 2 ) then
print ( " Nothing to install. " )
return
else
2018-11-24 00:49:01 +08:00
if ( not check_internet ( ) ) then return end
2018-11-21 11:55:45 +08:00
print ( " Checking programs info... " )
end
2018-11-24 01:29:56 +08:00
if ( not check_db ( ) ) then return end
2019-01-10 16:38:46 +08:00
if ( optionForce ( ) ) then
2019-01-08 08:46:53 +08:00
print ( " [WARN] Using force mode. I sure hope you know what you are doing. " )
end
2018-11-21 11:55:45 +08:00
local to_install = { }
for i = 2 , # args , 1 do
to_install [ args [ i ] ] = true
end
local newly_added = 0
while true do
local to_add = { }
for this_lib in pairs ( to_install ) do
if ( not db [ this_lib ] ) then
2018-11-21 12:08:25 +08:00
print ( " Library ' " .. this_lib .. " ' not found. " )
2018-12-07 13:38:30 +08:00
local maybe_this = miss_suggestion ( this_lib , db )
if ( maybe_this ) then
2018-12-07 20:08:56 +08:00
print ( " You might want library ' " .. maybe_this .. " '. " )
2018-12-07 13:38:30 +08:00
end
2018-11-21 11:55:45 +08:00
return
else
if ( db [ this_lib ] . requires ) then
for idx , this_req in ipairs ( db [ this_lib ] . requires ) do
if ( not to_install [ this_req ] and not to_add [ this_req ] ) then
newly_added = newly_added + 1
to_add [ this_req ] = true
end
end
end
end
end
for this_lib in pairs ( to_add ) do
to_install [ this_lib ] = true
end
if ( newly_added == 0 ) then break
else
newly_added = 0
end
end
2019-01-10 11:35:06 +08:00
print ( " About to install the following libraries: " )
2018-11-21 11:55:45 +08:00
local count_libs = 0
local count_files = 0
2018-11-21 12:24:10 +08:00
io.write ( " \t " )
2018-12-31 01:02:46 +08:00
for this_lib in pairsKey ( to_install ) do
2018-11-21 11:55:45 +08:00
io.write ( this_lib .. " " )
count_libs = count_libs + 1
2018-11-24 16:16:54 +08:00
for k in pairs ( db [ this_lib ] . files ) do
2018-11-21 11:55:45 +08:00
count_files = count_files + 1
end
end
2018-11-21 12:24:10 +08:00
print ( " \n " .. count_libs .. " libraries will be installed. " .. count_files .. " files will be downloaded. " )
2018-11-21 11:55:45 +08:00
2018-11-30 17:48:05 +08:00
local warn_libs_unofficial = { }
for this_lib in pairs ( to_install ) do
if ( not IsOfficial ( db [ this_lib ] ) ) then
table.insert ( warn_libs_unofficial , this_lib )
end
end
if ( next ( warn_libs_unofficial ) ) then
print ( " [WARN] The following libraries are unofficial. Install at your own risk. " )
print ( " \t " .. table.concat ( warn_libs_unofficial , " " ) )
end
2019-01-14 17:39:49 +08:00
-- If more libraries will be installed or unofficial libraries present, pop up a confirm.
if ( not optionYes ( ) and ( count_libs ># args - 1 or next ( warn_libs_unofficial ) ) ) then
io.write ( " Do you want to continue? [Y/n]: " )
2019-01-10 16:38:46 +08:00
local line = io.read ( " l " )
2019-01-14 17:39:49 +08:00
if ( not ( line : len ( ) < 1 or line : sub ( 1 , 1 ) == " Y " or line : sub ( 1 , 1 ) == " y " ) ) then
2019-01-10 16:38:46 +08:00
print ( " Aborted. " )
return
end
end
2018-11-30 17:48:05 +08:00
-- Third-Party programs or unofficial programs may have license.
print ( " Checking License... " )
local accepted_license = { }
local refused_license = { }
if ( options [ " accept-license " ] ) then
if ( type ( options [ " accept-license " ] ) == " boolean " ) then
accepted_license [ " __ALL__ " ] = true
else
local next_license = string.gmatch ( options [ " accept-license " ] .. ' , ' , " [A-Za-z0-9]+, " )
while true do
local this_license = next_license ( )
if ( not this_license ) then break end
this_license = string.lower ( string.gsub ( this_license , ' , ' , ' ' ) )
accepted_license [ this_license ] = true
end
end
end
if ( options [ " refuse-license " ] ) then
if ( type ( options [ " refuse-license " ] ) == " boolean " ) then
refused_license [ " __ALL__ " ] = true
else
local next_license = string.gmatch ( options [ " refuse-license " ] .. ' , ' , " [A-Za-z0-9]+, " )
while true do
local this_license = next_license ( )
if ( not this_license ) then break end
this_license = string.lower ( string.gsub ( this_license , ' , ' , ' ' ) )
refused_license [ this_license ] = true
end
end
end
for this_lib in pairs ( to_install ) do
if ( not IsOfficial ( db [ this_lib ] ) and db [ this_lib ] . license ) then
if ( refused_license [ " __ALL__ " ] or refused_license [ string.lower ( db [ this_lib ] . license.name ) ] ) then
print ( " [License Refused] License " .. db [ this_lib ] . license.name .. " for library " .. this_lib .. " is refused. " )
return
elseif ( accepted_license [ " __ALL__ " ] or accepted_license [ string.lower ( db [ this_lib ] . license.name ) ] ) then
print ( " Accepted license " .. db [ this_lib ] . license.name .. " for library " .. this_lib )
else
-- Download the license and show it to user.
print ( " Downloading license " .. db [ this_lib ] . license.name .. " for library " .. this_lib .. " from: " .. db [ this_lib ] . license.url )
2018-12-03 15:24:35 +08:00
local ok , result = download ( db [ this_lib ] . license.url )
if ( not ok ) then
2019-01-07 19:34:59 +08:00
print ( " [Download Failed] Failed to download license. " )
2018-11-30 17:48:05 +08:00
return
end
local temp_name = os.tmpname ( )
local f = io.open ( temp_name , " w " )
f : write ( " ----------Grab---------- \n You have to agree with this license for library " .. this_lib .. " \n ------------------------ \n \n " )
f : write ( result )
f : close ( )
local confirmed = false
while not confirmed do
os.execute ( " less " .. temp_name )
print ( " Do you agree with that license? " )
print ( " (Y) - Yes. (N) - No. (A) - View it again. " )
while true do
local x = io.read ( )
if ( x ~= nil ) then
if ( x == ' y ' or x == ' Y ' ) then
confirmed = 1
break
elseif ( x == ' n ' or x == ' N ' ) then
confirmed = 2
break
elseif ( x == ' a ' or x == ' A ' ) then
break
end
end
end
end
2018-12-07 20:08:56 +08:00
filesystem.remove ( temp_name )
2018-11-30 17:48:05 +08:00
if ( confirmed == 2 ) then
print ( " [License Refused] License " .. db [ this_lib ] . license.name .. " for library " .. this_lib .. " is refused by user. " )
return
else
print ( " Accepted license " .. db [ this_lib ] . license.name .. " for library " .. this_lib )
end
end
end
end
2018-11-21 11:55:45 +08:00
print ( " Downloading... " )
2018-11-30 11:10:08 +08:00
local count_byte = 0
2018-11-21 12:24:10 +08:00
local id_installing = 0
2018-12-07 20:08:56 +08:00
local time_before = computer.uptime ( )
2018-11-21 11:55:45 +08:00
for this_lib in pairs ( to_install ) do
2018-11-24 16:04:29 +08:00
for k , v in pairs ( db [ this_lib ] . files ) do
2018-11-21 12:24:10 +08:00
id_installing = id_installing + 1
2018-11-21 11:55:45 +08:00
local toDownload
if ( type ( k ) == " number " and type ( v ) == " string " ) then
toDownload = v
elseif ( type ( k ) == " string " ) then
toDownload = k
else
print ( " Invalid programs info: key type: " .. type ( k ) .. " . value type: " .. type ( v ) )
return
end
io.write ( " [ " .. id_installing .. " / " .. count_files .. " ] Downloading " .. toDownload .. " for " .. this_lib .. " ... " )
2018-11-26 01:33:41 +08:00
local this_url
if ( db [ this_lib ] . proxy ) then
this_url = string.gsub (
string.gsub (
string.gsub (
db [ this_lib ] . proxy ,
" __repo__ " ,
db [ this_lib ] . repo or " Kiritow/OpenComputerScripts "
) ,
" __branch__ " ,
db [ this_lib ] . branch or " master "
) ,
" __file__ " ,
toDownload
)
else
this_url = UrlGenerator ( db [ this_lib ] . repo or " Kiritow/OpenComputerScripts " , db [ this_lib ] . branch or " master " , toDownload )
end
2018-12-03 15:24:35 +08:00
local ok , result = download ( this_url )
2018-11-21 11:55:45 +08:00
if ( not ok ) then
print ( " [Download Failed] " .. result )
2018-11-21 12:08:25 +08:00
return
2018-11-21 11:55:45 +08:00
else
2018-11-30 11:10:08 +08:00
count_byte = count_byte + string.len ( result )
2018-12-07 20:08:56 +08:00
2018-11-21 11:55:45 +08:00
if ( type ( v ) == " string " ) then
2018-12-07 20:08:56 +08:00
local toSave
if ( v == " __installer__ " ) then
toSave = os.tmpname ( )
to_install [ this_lib ] = toSave
else
toSave = v
end
2019-01-07 19:34:59 +08:00
local ok , fname = try_resolve_path ( k , toSave )
2018-12-07 20:08:56 +08:00
if ( not ok ) then
print ( " [Error] " .. fname )
return
end
2019-01-07 20:18:34 +08:00
if ( will_overwrite ( fname ) ) then
return
end
2018-12-08 10:57:05 +08:00
local f = io.open ( fname , " wb " )
2018-12-07 20:08:56 +08:00
if ( not f ) then
print ( " [Error] Failed to open file " .. fname .. " for writing. " )
2018-11-21 11:55:45 +08:00
return
else
2018-12-07 20:08:56 +08:00
local ok , err = f : write ( result )
2018-11-21 11:55:45 +08:00
f : close ( )
2018-12-07 20:08:56 +08:00
if ( not ok ) then
print ( " [Error] Failed while writing to file: " .. fname .. " : " .. err )
return
end
2018-11-21 11:55:45 +08:00
end
elseif ( type ( v ) == " table " ) then
2018-12-07 20:08:56 +08:00
local done = false
for idx , this_name in ipairs ( v ) do
2019-01-07 19:34:59 +08:00
local ok , fname = try_resolve_path ( k , this_name )
2018-12-07 20:08:56 +08:00
if ( ok ) then
2019-01-07 20:18:34 +08:00
if ( will_overwrite ( fname ) ) then
return
end
2018-12-08 10:57:05 +08:00
local f = io.open ( fname , " wb " )
2018-12-07 20:08:56 +08:00
if ( f ) then
local ok , err = f : write ( result )
f : close ( )
if ( not ok ) then
print ( " [Error] Failed while writing to file: " .. fname .. " : " .. err )
return
end
done = true
break
end
2018-11-21 11:55:45 +08:00
end
end
2018-12-07 20:08:56 +08:00
if ( not done ) then
print ( " [Error] Unable to save file: " .. toDownload )
2018-12-03 14:16:35 +08:00
return
2018-11-21 11:55:45 +08:00
end
2018-12-07 20:08:56 +08:00
else
print ( " [Error] Invalid program info value type: " .. type ( v ) )
return
2018-11-21 11:55:45 +08:00
end
2018-12-07 20:08:56 +08:00
-- [OK]
print ( " [ " .. getshowbyte ( string.len ( result ) ) .. " ] " )
2018-11-21 11:55:45 +08:00
end
end
end
2018-12-07 20:08:56 +08:00
local time_diff = computer.uptime ( ) - time_before
print ( " Fetched " .. count_files .. " files ( "
.. getshowbyte ( count_byte ) .. " ) in "
.. getshowtime ( time_diff )
.. " ( " .. getshowspeed ( count_byte / time_diff ) .. " ) "
)
2018-11-30 17:48:05 +08:00
if ( not options [ " skip-install " ] ) then
2018-11-26 00:49:18 +08:00
print ( " Installing... " )
2018-12-08 10:57:05 +08:00
local has_installed = { }
local recursion_detect = { }
2018-12-31 02:06:15 +08:00
local function do_install_dfs ( this_lib )
2018-12-08 10:57:05 +08:00
if ( recursion_detect [ this_lib ] or has_installed [ this_lib ] ) then
return true
end
recursion_detect [ this_lib ] = true
if ( db [ this_lib ] . requires ) then
2018-12-31 02:06:15 +08:00
for idx , req_lib in ipairs ( db [ this_lib ] . requires ) do
2018-12-08 10:57:05 +08:00
if ( not do_install_dfs ( req_lib ) ) then -- Deeper Failure
return false
end
end
end
2018-12-07 20:08:56 +08:00
local this_installer
2018-12-08 10:57:05 +08:00
if ( type ( to_install [ this_lib ] ) == " string " ) then
this_installer = to_install [ this_lib ]
2018-12-07 20:08:56 +08:00
elseif ( db [ this_lib ] . installer ) then
2019-01-07 19:34:59 +08:00
print ( " [WARN] From Grab v2.4.8, option `installer` is deprecated. Use __installer__ instead. " )
2018-12-07 20:08:56 +08:00
this_installer = db [ this_lib ] . installer
2018-12-08 10:57:05 +08:00
else
-- No Installer: Mark as installed.
has_installed [ this_lib ] = true
recursion_detect [ this_lib ] = nil
return true
2018-12-07 20:08:56 +08:00
end
2018-12-08 10:57:05 +08:00
print ( " Running installer for " .. this_lib .. " ... " )
local fn , err = loadfile ( this_installer )
if ( not fn ) then
print ( " [Installer Error]: " .. err )
else
local ok , xerr = pcall ( fn )
if ( not ok ) then
print ( " [Installer Error]: " .. xerr )
elseif ( type ( xerr ) == " function " ) then
2019-01-17 20:13:10 +08:00
if ( not pcall ( xerr , grab_infos ) ) then
2018-11-26 00:49:18 +08:00
print ( " [Installer Error]: " .. xerr )
2018-12-07 20:08:56 +08:00
else
2018-12-08 10:57:05 +08:00
has_installed [ this_lib ] = true
2018-12-07 20:08:56 +08:00
done = true
2018-11-26 00:49:18 +08:00
end
2018-12-08 10:57:05 +08:00
else
print ( " [Warn]: From Grab v2.4.6, installers should return functions. " )
done = true
2018-11-24 16:16:54 +08:00
end
2018-12-08 10:57:05 +08:00
end
2018-12-07 20:08:56 +08:00
2018-12-08 10:57:05 +08:00
if ( type ( this_value ) == " string " ) then -- This might be skipped?
filesystem.remove ( this_installer )
end
2018-12-07 20:08:56 +08:00
2018-12-08 10:57:05 +08:00
recursion_detect [ this_lib ] = nil
return done
end -- end of local function do_install_dfs(...)
for this_lib in pairs ( to_install ) do
if ( not do_install_dfs ( this_lib ) ) then
print ( " Failed to install some library. Installation aborted. " )
return
2018-11-24 16:16:54 +08:00
end
2018-11-24 01:29:56 +08:00
end
2018-11-26 00:49:18 +08:00
else
2018-11-30 17:48:05 +08:00
print ( " Installation is skipped. " )
2018-11-24 01:29:56 +08:00
end
2018-11-21 12:24:10 +08:00
print ( " Installed " .. count_libs .. " libraies with " .. count_files .. " files. " )
2018-11-21 11:55:45 +08:00
return
end
2019-01-10 11:35:06 +08:00
if ( args [ 1 ] == " uninstall " ) then
if ( not check_db ( ) ) then return end
if ( # args < 2 ) then
print ( " Nothing to uninstall. " )
return
end
2019-01-10 16:02:50 +08:00
print ( " Checking programs info... " )
2019-01-10 16:38:46 +08:00
if ( optionForce ( ) ) then
2019-01-10 16:02:50 +08:00
print ( " [WARN] Using force mode. I sure hope you know what you are doing. " )
end
2019-01-10 11:35:06 +08:00
local to_uninstall = { }
for i = 2 , # args do
2019-01-10 16:02:50 +08:00
to_uninstall [ args [ i ] ] = { }
2019-01-10 11:35:06 +08:00
end
2019-01-10 16:02:50 +08:00
local count_byte = 0
for this_lib , this_files in pairs ( to_uninstall ) do
2019-01-10 12:55:02 +08:00
if ( not db [ this_lib ] ) then
print ( " Library ' " .. this_lib .. " ' not found. " )
local maybe_this = miss_suggestion ( this_lib , db )
if ( maybe_this ) then
print ( " Do you mean ' " .. maybe_this .. " ' " )
end
return
2019-01-10 16:02:50 +08:00
else
for k , v in pairs ( db [ this_lib ] . files ) do
2019-01-10 16:38:46 +08:00
if ( v ~= " __installer__ " ) then -- Skip the installer
local ok , filename = try_resolve_path ( k , v , true )
if ( not ok ) then
print ( " [Resolve Error] " .. filename )
return
end
if ( filename.sub ( 1 , 5 ) ~= " /tmp/ " ) then -- Files in /tmp/ are not checked and will not be removed by uninstall.
if ( not optionForce ( ) and not filesystem.exists ( filename ) ) then
print ( " [Error] Library " .. this_lib .. " check failed. " )
print ( " [Error] Missing file: " .. filename )
print ( " [Error] Library might be corrupted or missing. Try reinstall it or uninstall it in force mode. " )
return
end
end
count_byte = count_byte + filesystem.size ( filename )
table.insert ( this_files , filename )
2019-01-10 16:02:50 +08:00
end
end
2019-01-10 12:55:02 +08:00
end
end
2019-01-10 11:35:06 +08:00
print ( " About to uninstall the following libraries: " )
local count_libs = 0
local count_files = 0
io.write ( " \t " )
2019-01-10 16:02:50 +08:00
for this_lib , this_files in pairsKey ( to_uninstall ) do
2019-01-10 11:35:06 +08:00
io.write ( this_lib .. " " )
count_libs = count_libs + 1
2019-01-10 16:02:50 +08:00
count_files = count_files +# this_files
2019-01-10 11:35:06 +08:00
end
2019-01-10 16:02:50 +08:00
print ( " \n " .. count_libs .. " libraries will be uninstalled. " .. count_files .. " files will be removed. " .. getshowbyte ( count_byte ) .. " disk space will be freed. " )
2019-01-10 11:35:06 +08:00
print ( " Removing... " )
local id_current = 0
2019-01-10 16:02:50 +08:00
for this_lib , this_files in pairs ( to_uninstall ) do
for k , filename in pairs ( this_files ) do
2019-01-10 11:35:06 +08:00
id_current = id_current + 1
io.write ( " [ " .. id_current .. " / " .. count_files .. " ] Deleting " .. filename .. " for " .. this_lib .. " ... " )
2019-01-10 12:55:02 +08:00
2019-01-10 11:35:06 +08:00
local ok , err = filesystem.remove ( filename )
if ( not ok ) then
2019-01-10 16:38:46 +08:00
if ( not optionForce ( ) ) then
2019-01-10 16:02:50 +08:00
print ( " [Failed] " .. err )
return
else
print ( " [Skipped] " .. err )
end
2019-01-10 11:35:06 +08:00
else
print ( " [OK] " )
end
end
end
print ( " Removed " .. count_libs .. " libraries. " .. getshowbyte ( count_byte ) .. " disk space freed. " )
return
end
2018-11-21 11:55:45 +08:00
if ( args [ 1 ] == " list " ) then
2018-11-24 01:29:56 +08:00
if ( not check_db ( ) ) then return end
2018-11-21 11:55:45 +08:00
print ( " Listing projects... " )
2018-12-31 01:02:46 +08:00
for this_lib in pairsKey ( db ) do
2018-12-07 13:38:30 +08:00
if ( not db [ this_lib ] . hidden ) then
print ( this_lib )
end
2018-11-21 11:55:45 +08:00
end
return
end
2018-11-26 00:49:18 +08:00
if ( args [ 1 ] == " search " ) then
if ( not check_db ( ) ) then return end
if ( # args < 2 ) then
print ( " Nothing to search. " )
return
end
print ( " Libraries matches ' " .. args [ 2 ] .. " ' : " )
2018-12-31 01:02:46 +08:00
for this_lib in pairsKey ( db ) do
2018-11-26 00:49:18 +08:00
if ( string.match ( this_lib , args [ 2 ] ) ) then
print ( this_lib )
end
end
return
end
2018-11-24 01:29:56 +08:00
if ( args [ 1 ] == " show " ) then
if ( not check_db ( ) ) then return end
if ( # args < 2 ) then
print ( " Nothing to show. " )
2018-12-03 14:16:35 +08:00
return
2018-11-24 01:29:56 +08:00
end
if ( db [ args [ 2 ] ] ) then
local this_info = db [ args [ 2 ] ]
print ( " Name: " .. args [ 2 ] )
2018-11-30 17:48:05 +08:00
print ( " Title: " .. this_info.title )
if ( this_info.deprecated ) then print ( " Deprecated: Yes " ) end
if ( IsOfficial ( this_info ) ) then print ( " Type: Official " )
else print ( " Type: Unofficial " ) end
2018-11-24 21:33:02 +08:00
print ( " Info: " .. this_info.info )
if ( this_info.author ) then print ( " Author: " .. this_info.author ) end
if ( this_info.contact ) then print ( " Contact: " .. this_info.contact ) end
2018-11-24 01:29:56 +08:00
local nFiles = 0
2018-11-24 21:33:02 +08:00
for k , v in pairs ( this_info.files ) do nFiles = nFiles + 1 end
2018-11-24 01:29:56 +08:00
print ( " Files: " .. nFiles )
2018-11-24 21:33:02 +08:00
if ( this_info.precheck ) then print ( " Precheck: Yes " ) end
if ( this_info.installer ) then print ( " Installer: Yes " ) end
2018-11-30 17:48:05 +08:00
if ( this_info.proxy ) then print ( " Proxy: Yes " ) end
2018-12-07 13:38:30 +08:00
if ( this_info.hidden ) then print ( " Hidden: Yes " ) end
2018-12-03 16:58:54 +08:00
if ( this_info.provider ) then print ( " Provider: " .. this_info.provider ) end
2018-11-30 17:48:05 +08:00
if ( this_info.license ) then
print ( " License: " .. this_info.license . name )
end
2018-11-24 01:29:56 +08:00
else
print ( " Library " .. args [ 2 ] .. " not found. " )
2018-12-07 13:38:30 +08:00
local maybe_this = miss_suggestion ( this_lib , db )
if ( maybe_this ) then
2018-12-07 20:08:56 +08:00
print ( " You might want library ' " .. maybe_this .. " '. " )
2018-12-07 13:38:30 +08:00
end
2018-11-24 01:29:56 +08:00
end
return
end
2018-11-24 00:49:01 +08:00
if ( args [ 1 ] == " download " ) then
if ( # args < 2 ) then
print ( " Nothing to download. " )
return
else
if ( not check_internet ( ) ) then return end
print ( " Collecting files... " )
end
local files = { }
for i = 2 , # args , 1 do
table.insert ( files , args [ i ] )
end
for i = 1 , # files , 1 do
io.write ( " [ " .. i .. " / " .. # files .. " ] Downloading " .. files [ i ] .. " ... " )
2018-12-03 15:24:35 +08:00
local ok , result = download ( UrlGenerator ( " Kiritow/OpenComputerScripts " , " master " , files [ i ] ) )
2018-11-24 00:49:01 +08:00
if ( not ok ) then
print ( " [Download Failed] " .. result )
return
else
local f , ferr = io.open ( files [ i ] , " w " )
if ( not f ) then
print ( " [Write Failed] Unable to write. Error: " .. ferr )
else
f : write ( result )
f : close ( )
print ( " [OK] " )
end
end
end
2018-11-26 00:49:18 +08:00
return
2018-11-24 00:49:01 +08:00
end
2018-11-21 11:55:45 +08:00
-- reach here?
2018-11-24 00:49:01 +08:00
if ( # args < 1 ) then
show_usage ( )
else
print ( " Unknown command: " .. args [ 1 ] )
2018-12-07 13:38:30 +08:00
local maybe_this = miss_suggestion ( args [ 1 ] , valid_command )
if ( maybe_this ) then
print ( " Do you mean ' " .. maybe_this .. " ' ? " )
end
2018-11-24 00:49:01 +08:00
end