343 lines
7.5 KiB
Lua
343 lines
7.5 KiB
Lua
local _VERSION = '2.3.0';
|
|
local CUBE_CHANNEL = 64;
|
|
|
|
local net = require('/apis/net')();
|
|
|
|
local args = table.pack(...);
|
|
local cubeCommand = args[1];
|
|
local firstArg = args[2];
|
|
local secondArg = args[3];
|
|
|
|
local function getRemainingArgs(startIndex)
|
|
local remainingArgs = {};
|
|
|
|
for i = startIndex, args.n do
|
|
table.insert(remainingArgs, tostring(args[i]));
|
|
end
|
|
|
|
return table.concat(remainingArgs, ' ');
|
|
end
|
|
|
|
local IGNORED_PATHS = {
|
|
['/rom'] = true,
|
|
['/.cubeboot'] = true,
|
|
['/.git'] = true,
|
|
['/.gitignore'] = true,
|
|
['/startup.lua'] = true,
|
|
}
|
|
|
|
local function isValidPath(givenPath)
|
|
return not IGNORED_PATHS[givenPath]
|
|
end
|
|
|
|
local function getAllFiles(basePath, result)
|
|
basePath = basePath or '/'
|
|
result = result or {};
|
|
|
|
local fileNames = fs.list(basePath)
|
|
|
|
for i = 1, #fileNames do
|
|
local filePath = basePath .. fileNames[i];
|
|
local valid = isValidPath(filePath);
|
|
|
|
if valid and fs.isDir(filePath) then
|
|
getAllFiles(filePath .. '/', result);
|
|
elseif valid and not fs.isDir(filePath) then
|
|
table.insert(result, filePath)
|
|
end
|
|
end
|
|
|
|
return result;
|
|
end
|
|
|
|
local function readFile(path)
|
|
local file = fs.open(path, "r");
|
|
|
|
if not file then
|
|
return nil;
|
|
end
|
|
|
|
local contents = file.readAll()
|
|
file.close()
|
|
|
|
return contents
|
|
end
|
|
|
|
--- Pads str to length len with char from right
|
|
local leftPad = function(str, len, char)
|
|
if char == nil then char = ' ' end
|
|
local nbRepetition = len - #str;
|
|
|
|
if nbRepetition > 0 then
|
|
return str .. string.rep(char, len - #str)
|
|
end
|
|
|
|
return str;
|
|
end
|
|
|
|
local function getRow(margin, str1, str2, str3)
|
|
|
|
margin = margin or '';
|
|
|
|
local row1 = leftPad(margin .. tostring(str1 or ''), 8, ' ')
|
|
local row2 = leftPad(tostring(str2 or ''), 16, ' ')
|
|
local row3 = leftPad(tostring(str3 or ''), 6, ' ')
|
|
|
|
return row1 .. row2 .. row3;
|
|
end
|
|
|
|
local function isFlag(name)
|
|
return function(arg)
|
|
return arg == '-' .. name or arg == '--' .. name;
|
|
end
|
|
end
|
|
|
|
local isHelpFlag = isFlag('help');
|
|
local isVersionFlag = isFlag('version');
|
|
|
|
local function printUsage()
|
|
print('cube usage:')
|
|
print();
|
|
print('\t\t\tcube ls');
|
|
print('\t\t\tcube configure');
|
|
print('\t\t\tcube set-boot <machineId> [command]')
|
|
print('\t\t\tcube reboot <machineId>')
|
|
print('\t\t\tcube deploy')
|
|
print('\t\t\tcube version')
|
|
print('\t\t\tcube help <command>')
|
|
end
|
|
|
|
local function printUsageCommand(commandName)
|
|
local function setBootUsage()
|
|
print('\t\t\tcube set-boot <machineId> [command]')
|
|
print('Setup a startup shell command on a remote cube.')
|
|
end
|
|
|
|
local USAGES = {
|
|
ls = function()
|
|
print('\t\t\tcube ls');
|
|
print('Print all available cubes in the cluster.')
|
|
end,
|
|
configure = function()
|
|
print('\t\t\tcube configure');
|
|
print('Setup remote slave cubes.')
|
|
end,
|
|
["set-boot"] = setBootUsage,
|
|
["setboot"] = setBootUsage,
|
|
["set-start"] = setBootUsage,
|
|
["setstart"] = setBootUsage,
|
|
["set-startup"] = setBootUsage,
|
|
["setstartup"] = setBootUsage,
|
|
reboot = function()
|
|
print('\t\t\tcube reboot <machineId>')
|
|
print('Reboot a cube machine.');
|
|
end,
|
|
deploy = function()
|
|
print('\t\t\tcube deploy')
|
|
print('Transfer files on all slave cubes.')
|
|
end,
|
|
version = function()
|
|
print('\t\t\tcube version')
|
|
print('Print the program version.')
|
|
end,
|
|
help = function()
|
|
print('\t\t\tcube help <command>')
|
|
print('Print help on commands.')
|
|
end,
|
|
}
|
|
|
|
local usageFn = USAGES[commandName]
|
|
|
|
if not usageFn then
|
|
return printUsage();
|
|
end
|
|
|
|
return usageFn();
|
|
end
|
|
|
|
if cubeCommand == nil or cubeCommand == '' or isHelpFlag(cubeCommand) then
|
|
printUsage();
|
|
return;
|
|
end
|
|
|
|
------------
|
|
-- reboot --
|
|
------------
|
|
local function rebootCommand(machineId, silentReboot)
|
|
if not machineId or machineId == '' then
|
|
printUsageCommand('reboot');
|
|
return;
|
|
end
|
|
|
|
local ok, results, packets = net.sendMultipleRequests(CUBE_CHANNEL, 'reboot', true, machineId);
|
|
|
|
if not ok then
|
|
error(results);
|
|
end
|
|
|
|
for k in ipairs(results) do
|
|
local packet = packets[k];
|
|
|
|
if not silentReboot == true then
|
|
print('reboot machine \'' .. tostring(packet.sourceId) .. '\'');
|
|
end
|
|
end
|
|
end
|
|
|
|
--------------
|
|
-- set-boot --
|
|
--------------
|
|
local function setBootCommand(machineId, shellCommand)
|
|
if not machineId then
|
|
printUsageCommand('set-boot');
|
|
return;
|
|
end
|
|
|
|
local ok, results, packets = net.sendMultipleRequests(CUBE_CHANNEL, 'set-boot', shellCommand, machineId);
|
|
|
|
if not ok then
|
|
error(results);
|
|
end
|
|
|
|
for k in ipairs(results) do
|
|
local packet = packets[k];
|
|
|
|
if shellCommand == nil or shellCommand == '' then
|
|
print('boot DELETED');
|
|
else
|
|
print('boot UPDATED');
|
|
end
|
|
|
|
rebootCommand(packet.sourceId, true);
|
|
|
|
-- prevent CraftOS-PC crashes
|
|
if periphemu then
|
|
os.sleep(0.5)
|
|
end
|
|
end
|
|
end
|
|
|
|
------------
|
|
-- deploy --
|
|
------------
|
|
local function deployCommand()
|
|
local allFiles = getAllFiles()
|
|
|
|
-- 1. get all machine ids (except the current one)
|
|
local ok, results, packets = net.sendMultipleRequests(CUBE_CHANNEL, 'ping', 'ping');
|
|
|
|
if not ok then
|
|
error(results);
|
|
end
|
|
|
|
local machineIds = {};
|
|
|
|
local localComputerId = os.getComputerID();
|
|
|
|
for k in ipairs(results) do
|
|
local packet = packets[k];
|
|
|
|
if packet.sourceId ~= localComputerId then
|
|
table.insert(machineIds, packet.sourceId);
|
|
end
|
|
end
|
|
|
|
-- 2. transfer files on all concerned machines
|
|
for machineIndex = 1, #machineIds do
|
|
local machineId = machineIds[machineIndex];
|
|
|
|
local fileTransfered = 0;
|
|
|
|
for i = 1, #allFiles do
|
|
local filePath = allFiles[i];
|
|
local fileContent = readFile(filePath)
|
|
|
|
local transferOk, res = net.sendRequest(CUBE_CHANNEL, 'deploy-file', { path = filePath, content = fileContent }, machineId);
|
|
|
|
if transferOk and res then
|
|
fileTransfered = fileTransfered + 1;
|
|
else
|
|
print('Error transfering file \'' .. filePath .. '\'');
|
|
end
|
|
end
|
|
|
|
print(tostring(fileTransfered) .. ' file(s) transfered on machine ' .. tostring(machineId))
|
|
|
|
rebootCommand(machineId, true);
|
|
|
|
-- prevent CraftOS-PC crashes
|
|
if periphemu then
|
|
os.sleep(0.5)
|
|
end
|
|
end
|
|
end
|
|
|
|
local COMMANDS = {
|
|
ls = function()
|
|
local ok, results, packets = net.sendMultipleRequests(CUBE_CHANNEL, 'ping', 'ping');
|
|
|
|
if not ok then
|
|
error(results);
|
|
end
|
|
|
|
-- print('ID LABEL\t\t\t\tSTARTUP');
|
|
print(getRow(' ', 'ID', 'LABEL', 'BOOT'))
|
|
print('--------------------------------------------')
|
|
|
|
local localMachineId = os.getComputerID();
|
|
|
|
for k in ipairs(results) do
|
|
local result = results[k];
|
|
local packet = packets[k];
|
|
|
|
local prefix = ' ';
|
|
|
|
if packet.sourceId == localMachineId then
|
|
prefix = '* '
|
|
end
|
|
|
|
print(getRow(prefix, packet.sourceId, packet.sourceLabel, result.startup))
|
|
end
|
|
end,
|
|
configure = function()
|
|
print('not implemented yet.');
|
|
end,
|
|
["set-boot"] = setBootCommand,
|
|
["setboot"] = setBootCommand,
|
|
["set-start"] = setBootCommand,
|
|
["setstart"] = setBootCommand,
|
|
["set-startup"] = setBootCommand,
|
|
["setstartup"] = setBootCommand,
|
|
reboot = rebootCommand,
|
|
deploy = deployCommand,
|
|
version = function()
|
|
print('cube client v' .. _VERSION);
|
|
end,
|
|
help = function(commandName)
|
|
printUsageCommand(commandName);
|
|
end
|
|
}
|
|
|
|
local cmd;
|
|
if isVersionFlag(cubeCommand) then
|
|
cmd = COMMANDS.version;
|
|
else
|
|
cmd = COMMANDS[cubeCommand];
|
|
end
|
|
|
|
if not cmd then
|
|
printUsage();
|
|
return;
|
|
end
|
|
|
|
if (isHelpFlag(firstArg)) then
|
|
printUsageCommand(cubeCommand);
|
|
return;
|
|
end
|
|
|
|
if cmd == setBootCommand then
|
|
cmd(firstArg, getRemainingArgs(3));
|
|
else
|
|
cmd(firstArg, secondArg);
|
|
end
|