removed stuff
This commit is contained in:
170
PowerManager.lua
170
PowerManager.lua
@@ -1,170 +0,0 @@
|
|||||||
--Programm um an den PC angeschlossene TE und RF Speicherzellen grafisch darzustellen
|
|
||||||
|
|
||||||
local component = require( "component" )
|
|
||||||
local gpu = component.gpu
|
|
||||||
local event = require( "event" )
|
|
||||||
|
|
||||||
local splashText = "Stromanzeige - Ultimate ROG RGB LED Edition"
|
|
||||||
local frameTitle = "Power Monitor - Klicken zum Beenden"
|
|
||||||
|
|
||||||
local oldW, oldH = gpu.getResolution()
|
|
||||||
local newW = 160
|
|
||||||
local newH = 50
|
|
||||||
local numberOfPanels = 2
|
|
||||||
local panelWidth = (newW / numberOfPanels)
|
|
||||||
gpu.setResolution(newW, newH)
|
|
||||||
|
|
||||||
function clearScreen()
|
|
||||||
local w,h = gpu.getResolution()
|
|
||||||
drawLine(1, 1, w, h, 0x000000)
|
|
||||||
end
|
|
||||||
|
|
||||||
function drawLine(startX, startY, stopX, stopY, colorOfLine)
|
|
||||||
local oldColor = gpu.getBackground(false)
|
|
||||||
gpu.setBackground(colorOfLine, false)
|
|
||||||
gpu.fill(startX, startY, stopX, stopY, " ")
|
|
||||||
gpu.setBackground(oldColor, false)
|
|
||||||
end
|
|
||||||
|
|
||||||
function powerBar( label, y, x, value, maxVal, colorOfBar, show, unit, border)
|
|
||||||
local oldColor = gpu.getBackground(false)
|
|
||||||
local borderSymbol = " "
|
|
||||||
local barSymbol = " "
|
|
||||||
local percentage = (value * 100 / maxVal)
|
|
||||||
local redGraphValue = 20
|
|
||||||
|
|
||||||
if percentage <= redGraphValue then
|
|
||||||
colorOfBar = 0xf00000
|
|
||||||
end
|
|
||||||
drawLine(border, y, x, 2, 0x000000)
|
|
||||||
w = math.floor( value * (x / maxVal) )
|
|
||||||
p = math.floor( (w / x) * 100 )
|
|
||||||
gpu.set( border, y, label .. ": " .. tostring( p ) .. "%" )
|
|
||||||
drawLine(border, y+1, x, 1, 0x222222)
|
|
||||||
drawLine(border, y+1, w, 1, colorOfBar)
|
|
||||||
gpu.setBackground( oldColor, false )
|
|
||||||
if show then
|
|
||||||
local valStr = formatBig( value ) .. unit
|
|
||||||
local n = string.len( valStr )
|
|
||||||
gpu.set( (x+3) - n, y, valStr )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function formatBig( value )
|
|
||||||
local output = ""
|
|
||||||
local valRem = 0
|
|
||||||
local valPart = 0
|
|
||||||
while value > 0 do
|
|
||||||
valRem = math.floor( value / 1000 )
|
|
||||||
valPart = value - (valRem * 1000)
|
|
||||||
if output == "" then
|
|
||||||
output = string.format( "%03d", valPart )
|
|
||||||
elseif valRem == 0 then
|
|
||||||
output = valPart .. "," .. output
|
|
||||||
else
|
|
||||||
output = string.format( "%03d", valPart ) .. "," .. output
|
|
||||||
end
|
|
||||||
value = valRem
|
|
||||||
end
|
|
||||||
return output
|
|
||||||
end
|
|
||||||
|
|
||||||
function getCells()
|
|
||||||
local countDcOrb = 0
|
|
||||||
local countTEcell = 0
|
|
||||||
local countRfTCell = 0
|
|
||||||
|
|
||||||
local TEcell = component.list( "energy_device" )
|
|
||||||
local RfTCell = component.list("rftools_powercell")
|
|
||||||
|
|
||||||
local cellsID = {}
|
|
||||||
|
|
||||||
for address, name in pairs(TEcell) do
|
|
||||||
countTEcell = countTEcell + 1
|
|
||||||
if countTEcell > 1 then
|
|
||||||
cellsID[address] = "TE Zelle".." "..countTEcell
|
|
||||||
else
|
|
||||||
cellsID[address] = "TE Zelle"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for address, name in pairs(RfTCell) do
|
|
||||||
countRfTCell = countRfTCell + 1
|
|
||||||
if countRfTCell > 1 then
|
|
||||||
cellsID[address] = "RfT Zelle".." "..countRfTCell
|
|
||||||
else
|
|
||||||
cellsID[address] = "RfT Zelle"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return cellsID
|
|
||||||
end
|
|
||||||
|
|
||||||
function getTotal()
|
|
||||||
local totalPower = 0
|
|
||||||
local totalMaxPower = 0
|
|
||||||
local cellid = getCells()
|
|
||||||
for address, name in pairs(cellid) do
|
|
||||||
local cell = component.proxy( address )
|
|
||||||
totalPower = totalPower + cell.getEnergyStored()
|
|
||||||
totalMaxPower = totalMaxPower + cell.getMaxEnergyStored()
|
|
||||||
end
|
|
||||||
return totalPower, totalMaxPower
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function drawPanel(x, y, width, height, color)
|
|
||||||
drawLine(x, y, width, height, color)
|
|
||||||
drawLine(x + 1, y + 1, width -1, height - 1, 0x000000)
|
|
||||||
end
|
|
||||||
|
|
||||||
function drawDesktop()
|
|
||||||
--Title
|
|
||||||
local titleHeight = 3
|
|
||||||
drawPanel(1, 1, newW, titleHeight, 0xffffff)
|
|
||||||
gpu.set((newW - #frameTitle) / 2, 2, frameTitle)
|
|
||||||
local cellsID = getCells()
|
|
||||||
local count = 0
|
|
||||||
local t = titleHeight
|
|
||||||
|
|
||||||
for i = numberOfPanels - 1, 0, -1
|
|
||||||
do
|
|
||||||
drawPanel(panelWidth*i+1, titleHeight + 1, panelWidth, newH - titleHeight, 0xffffff)
|
|
||||||
if i == 0 then
|
|
||||||
for address, name in pairs(cellsID) do
|
|
||||||
local cell = component.proxy( address )
|
|
||||||
count = count + 1
|
|
||||||
t = t + 3
|
|
||||||
powerBar( name, t , panelWidth - 6, cell.getEnergyStored(), cell.getMaxEnergyStored() , 0x00bb00, true, "RF", panelWidth*i+2)
|
|
||||||
end
|
|
||||||
elseif i == 1 then
|
|
||||||
local totalPower, totalMaxPower = getTotal()
|
|
||||||
powerBar( "Gesamt", titleHeight + 3, panelWidth - 6, totalPower, totalMaxPower, 0x00bb00, true, "RF", panelWidth*i+2)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
clearScreen()
|
|
||||||
drawLine(1, 1, newW, 1, 0xbbbbbb)
|
|
||||||
gpu.set((newW - #splashText) / 2, 24, splashText)
|
|
||||||
os.sleep(1)
|
|
||||||
clearScreen()
|
|
||||||
|
|
||||||
while true do
|
|
||||||
drawDesktop()
|
|
||||||
local id, _, x, y = event.pullMultiple("touch", "interrupted")
|
|
||||||
if id == "interrupted" then
|
|
||||||
print("soft interrupt, closing")
|
|
||||||
goto quit
|
|
||||||
elseif id == "touch" then
|
|
||||||
goto quit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
::quit::
|
|
||||||
gpu.setResolution( oldW, oldH )
|
|
||||||
clearScreen()
|
|
||||||
print("Programm beendet.")
|
|
||||||
41
README.md
41
README.md
@@ -1,41 +1,10 @@
|
|||||||
|
# Repo Template for git-tool compatible layout
|
||||||
|
|
||||||

|
unfinished
|
||||||
|
|
||||||
|
|
||||||
# Powerman - A powerful toolset for OpenComputers
|
|
||||||
|
|
||||||
This is a project combining a super cool git-download-tool for use on the in-game computer running OpenOS and an application with a rudimentary windowed GUI.
|
|
||||||
|
|
||||||
You can expect more features in future releases.
|
|
||||||
|
|
||||||
|
|
||||||
## Installation:
|
|
||||||
For the initial install you have to have an internet card in your computer. Also for the GUI you need at least a tier 2 GPU and screen.
|
|
||||||
|
|
||||||
Run the following command in the OpenOS shell:
|
|
||||||
`pastebin run <Placeholder> <argument>`
|
|
||||||
|
|
||||||
The git-tool will then walk you through manual installation of dependencies, the tool itself and the application module(s).
|
|
||||||
|
|
||||||
## Git tool:
|
|
||||||
<To be filled out>
|
|
||||||
|
|
||||||
### Usage
|
|
||||||
|
|
||||||
### Installation path
|
|
||||||
|
|
||||||
### Uninstalling via manifest
|
|
||||||
|
|
||||||
### Setting up Preferences
|
|
||||||
|
|
||||||
## GUI API
|
|
||||||
The GUI API installs to /lib by default. It is a fork of Kevink525's OC-GUI-API tailored to our needs and expanded by a Windowing system.
|
|
||||||
It is an object oriented Interface system to let the user decide what the application does by just pushing a few buttons or inputing a string. There are simple objects like rectangles or containerized-objects like Windows or ProgressBars.
|
|
||||||
|
|
||||||
The GUI is typically contained in (creatable, moveable and deletable) Windows, but there is also the ability to hard-code objects to certain screens or whatever.
|
|
||||||
For example: Display Windowed application on screen one and have a status display on screen 2
|
|
||||||
|
|
||||||
## Shortcut
|
## Shortcut
|
||||||
|
FIXME: Explain shortcuts generically and remove logic from actual program, instead replace with generic configurable shortcut
|
||||||
|
|
||||||
Of course this project will be installed with a shell shortcut. To run the application with GUI just type `powerman`.
|
Of course this project will be installed with a shell shortcut. To run the application with GUI just type `powerman`.
|
||||||
If you want to know what arguments can be used put an `-h` behind it.
|
If you want to know what arguments can be used put an `-h` behind it.
|
||||||
For example:
|
For example:
|
||||||
@@ -44,5 +13,7 @@ For example:
|
|||||||
The shortcut is installed in /usr/bin. If this folder does not exist yet it will be created.
|
The shortcut is installed in /usr/bin. If this folder does not exist yet it will be created.
|
||||||
|
|
||||||
## Application
|
## Application
|
||||||
|
FIXME: Explain layout of repo for generic Application here
|
||||||
|
|
||||||
This is where the fun begins. On startup you will be greeted with a desktop.
|
This is where the fun begins. On startup you will be greeted with a desktop.
|
||||||
These features are yet to be implemented, but you can expect things like Powermanagement (Hey, the original idea behind this Project), AE2 interfaces (including Autocrafting and stuff), redstone control, chat application for communicating with friends on a server and many more! Just wait till we are done (which will be never because there are many ideas)
|
These features are yet to be implemented, but you can expect things like Powermanagement (Hey, the original idea behind this Project), AE2 interfaces (including Autocrafting and stuff), redstone control, chat application for communicating with friends on a server and many more! Just wait till we are done (which will be never because there are many ideas)
|
||||||
|
|||||||
236
desktopGui.lua
236
desktopGui.lua
@@ -1,236 +0,0 @@
|
|||||||
|
|
||||||
local version="0.0.1a"
|
|
||||||
local author="Frederick"
|
|
||||||
---
|
|
||||||
|
|
||||||
local computer=require"computer"
|
|
||||||
local gui=require"GUI"
|
|
||||||
|
|
||||||
gui.initialize()
|
|
||||||
local w,h = gui.getResolution()
|
|
||||||
local start_time = computer.uptime()
|
|
||||||
local running = true
|
|
||||||
|
|
||||||
gui.show()
|
|
||||||
|
|
||||||
--Usage? (no good docs)
|
|
||||||
--labelbox(x, y, w, h, layer, fColor, bColor, clickEvent, ?, text)
|
|
||||||
--when nil is used most params have standard values you can globally adjust.
|
|
||||||
|
|
||||||
--initiate this object using: [Name] = windows:new()
|
|
||||||
windows = {
|
|
||||||
name = "",
|
|
||||||
title = "Name",
|
|
||||||
titleForegroundColor = 0xFFFFFF,
|
|
||||||
titleBackgroundColor = 0x0000bb,
|
|
||||||
contentBackgroundColor = 0x0F0F0F,
|
|
||||||
exitTextBackgroundColor = 0xFF0000,
|
|
||||||
exitText = "Exit",
|
|
||||||
titleHeight = 0, --0 = 1 line high
|
|
||||||
size = { 100, 20},
|
|
||||||
position = { 10, 10},
|
|
||||||
layer = 105,
|
|
||||||
|
|
||||||
closeable = true,
|
|
||||||
defaultContents = function(self)
|
|
||||||
c = {
|
|
||||||
self:drawTitle(),
|
|
||||||
self:drawPanel(),
|
|
||||||
self:drawButton(1, 1, "+", 0x00FF00, function() self:moveWindowUp() end),
|
|
||||||
self:drawButton(1, 2, "-", 0x0000FF, function() self:moveWindowDown() end),
|
|
||||||
self:drawButton(1, 3, ">", 0x00BB00, function() self:moveWindowR() end),
|
|
||||||
self:drawButton(1, 4, "<", 0x0000BB, function() self:moveWindowL() end)
|
|
||||||
}
|
|
||||||
return c end,
|
|
||||||
|
|
||||||
activeObjects = {},
|
|
||||||
--are there pending changes on the position?
|
|
||||||
--changes = false,
|
|
||||||
|
|
||||||
--TODO: at the moment this exits the gui. Maybe make it delete this object?
|
|
||||||
exit = function(self) if self.closeable == true then self:deleteWindow() end end,
|
|
||||||
|
|
||||||
moveWindowR = function(self) self:updateWindow(1) end,
|
|
||||||
moveWindowL = function(self) self:updateWindow(-1) end,
|
|
||||||
moveWindowUp = function(self) self:updateWindow(nil, -1) end,
|
|
||||||
moveWindowDown = function(self) self:updateWindow(nil, 1) end,
|
|
||||||
moveToForeground = function(self) self:updateWindow(nil, nil, 10) end,
|
|
||||||
|
|
||||||
insertActiveObjectToTable = function(self, obj) table.insert(self.activeObjects, obj) end,
|
|
||||||
|
|
||||||
drawTitle = function(self)
|
|
||||||
titlebar = gui.labelbox(self.position[1],
|
|
||||||
self.position[2],
|
|
||||||
self.size[1] - #self.exitText - 1,
|
|
||||||
self.titleHeight,
|
|
||||||
self.layer,
|
|
||||||
self.titleForegroundColor,
|
|
||||||
self.titleBackgroundColor,
|
|
||||||
function() self:moveToForeground() end, nil,
|
|
||||||
self.title)
|
|
||||||
exit = gui.labelbox(self.position[1] + (self.size[1] - #self.exitText),
|
|
||||||
self.position[2],
|
|
||||||
#self.exitText,
|
|
||||||
self.titleHeight,
|
|
||||||
self.layer,
|
|
||||||
self.titleForegroundColor,
|
|
||||||
self.exitTextBackgroundColor,
|
|
||||||
function() self:exit() end, nil,
|
|
||||||
self.exitText)
|
|
||||||
self:insertActiveObjectToTable(exit)
|
|
||||||
self:insertActiveObjectToTable(titlebar)
|
|
||||||
end,
|
|
||||||
|
|
||||||
drawPanel = function(self)
|
|
||||||
contentPanel = gui.rect_full(self.position[1],
|
|
||||||
self.position[2] + 1,
|
|
||||||
self.size[1],
|
|
||||||
self.size[2] - 1,
|
|
||||||
self.layer - 1, --Background has to be in the Background... duh...
|
|
||||||
nil, --no text => no foreground color
|
|
||||||
self.contentBackgroundColor)
|
|
||||||
self:insertActiveObjectToTable(contentPanel)
|
|
||||||
end,
|
|
||||||
|
|
||||||
--use relX and relY with to align relative to window
|
|
||||||
drawButton = function(self, relX, relY, description, color, clickEvent)
|
|
||||||
if relX > self.size[1] then relX = self.size[1] end
|
|
||||||
if relY > self.size[2] then relY = self.size[2] end
|
|
||||||
absX = self.position[1] + (relX)
|
|
||||||
absY = self.position[2] + (relY)
|
|
||||||
button = gui.labelbox( absX,
|
|
||||||
absY,
|
|
||||||
#description,
|
|
||||||
0,
|
|
||||||
self.layer,
|
|
||||||
nil,
|
|
||||||
color,
|
|
||||||
clickEvent, nil,
|
|
||||||
description)
|
|
||||||
self:insertActiveObjectToTable(button)
|
|
||||||
return button
|
|
||||||
end,
|
|
||||||
|
|
||||||
insertObjectToContents = function(self, object)
|
|
||||||
content = self:windowContents()
|
|
||||||
table.insert(content, object)
|
|
||||||
function self:windowContents()
|
|
||||||
b = content
|
|
||||||
return b
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
resetContents = function(self)
|
|
||||||
function self:windowContent()
|
|
||||||
b = self:defaultContents()
|
|
||||||
return b
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
--do it my boy, draw it!
|
|
||||||
drawProgressBar = function(self, relX, relY, value, maxValue, description, width, color, backgroundColor, warningThreshold)
|
|
||||||
color = color or 0x00FF00
|
|
||||||
warningThreshold = warningThreshold or 20
|
|
||||||
description = description or "Name"
|
|
||||||
width = width or 10
|
|
||||||
backgroundColor = backgroundColor or self.contentBackgroundColor
|
|
||||||
percentage = (value*100)/maxValue
|
|
||||||
if percentage < warningThreshold then color = 0xBB0000 end
|
|
||||||
|
|
||||||
if relX > self.size[1] then relX = self.size[1] end
|
|
||||||
if relY > self.size[2] then relY = self.size[2] end
|
|
||||||
absX = self.position[1] + (relX)
|
|
||||||
absY = self.position[2] + (relY)
|
|
||||||
|
|
||||||
outline = gui.labelbox( absX,
|
|
||||||
absY,
|
|
||||||
width,
|
|
||||||
1,
|
|
||||||
self.layer,
|
|
||||||
nil,
|
|
||||||
backgroundColor,
|
|
||||||
nil, nil,
|
|
||||||
description)
|
|
||||||
bar = gui.labelbox (absX,
|
|
||||||
absY + 1,
|
|
||||||
math.floor((width * percentage) / 100),
|
|
||||||
0,
|
|
||||||
self.layer,
|
|
||||||
nil,
|
|
||||||
color)
|
|
||||||
self:insertActiveObjectToTable(outline)
|
|
||||||
self:insertActiveObjectToTable(bar)
|
|
||||||
end,
|
|
||||||
|
|
||||||
--insert wanted content into this table.
|
|
||||||
windowContents = function(self)
|
|
||||||
b = self:defaultContents()
|
|
||||||
return b end,
|
|
||||||
|
|
||||||
--Init Window
|
|
||||||
drawWindow = function(self)
|
|
||||||
self.activeObjects = {}
|
|
||||||
for i, method in ipairs(self:windowContents()) do
|
|
||||||
method()
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
--used for updating the contents when moved (args may be nil for content updates)
|
|
||||||
updateWindow = function(self, x, y, layer)
|
|
||||||
for i, object in ipairs(self.activeObjects) do
|
|
||||||
object.move(x, y, layer)
|
|
||||||
--object.update()
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
rebootWindow = function(self)
|
|
||||||
self:deleteWindow()
|
|
||||||
self:drawWindow()
|
|
||||||
end,
|
|
||||||
|
|
||||||
--delete all window objects
|
|
||||||
deleteWindow = function(self)
|
|
||||||
for i, object in ipairs(self.activeObjects) do
|
|
||||||
object.remove(false) --remove all objects and show layers behind it
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
-- Constructor
|
|
||||||
new = function(self, name, o)
|
|
||||||
self.__index = self
|
|
||||||
o = o or {}
|
|
||||||
local inst = setmetatable(o, self)
|
|
||||||
inst.name = name
|
|
||||||
self.title = name
|
|
||||||
return inst
|
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
Window1 = windows:new("Win1")
|
|
||||||
Window2 = windows:new("Win2")
|
|
||||||
ExitWindow = windows:new("Exit")
|
|
||||||
|
|
||||||
Window2.size = {50, 10}
|
|
||||||
Window2.position = {1, 1}
|
|
||||||
Window2.layer = 101
|
|
||||||
Window2.titleBackgroundColor = 0x00bb00
|
|
||||||
|
|
||||||
ExitWindow.size = {30, 10}
|
|
||||||
ExitWindow.position = {100, 1}
|
|
||||||
ExitWindow.closeable = false
|
|
||||||
ExitWindow.contentBackgroundColor = 0xbbbbbb
|
|
||||||
ExitWindow:insertObjectToContents(ExitWindow:drawButton(5, 1, "Exit GUI", 0xFF0000, function() running = false end))
|
|
||||||
Window1:insertObjectToContents(Window1:drawProgressBar(5, 3, 25, 100, "TestBar", 10))
|
|
||||||
|
|
||||||
|
|
||||||
Window1:drawWindow()
|
|
||||||
Window2:drawWindow()
|
|
||||||
ExitWindow:drawWindow()
|
|
||||||
|
|
||||||
while running do
|
|
||||||
os.sleep(0.2)
|
|
||||||
--just loop. put some looping shit here!
|
|
||||||
end
|
|
||||||
--os.execute("reboot")
|
|
||||||
gui.stopGUI()
|
|
||||||
os.exit()
|
|
||||||
339
git-tool.lua
339
git-tool.lua
@@ -1,339 +0,0 @@
|
|||||||
local args = {...}
|
|
||||||
local internet=require("internet")
|
|
||||||
local filesystem=require("filesystem")
|
|
||||||
local unicode=require("unicode")
|
|
||||||
|
|
||||||
YES = {"y","yes","Y","Yes","YES"}
|
|
||||||
NO = {"n","no","N","No","NO"}
|
|
||||||
|
|
||||||
SupportedRemotes = {
|
|
||||||
Github = {
|
|
||||||
BaseUrl = "https://github.com/",
|
|
||||||
RawApiUrl = "https://raw.githubusercontent.com/",
|
|
||||||
Implemented = true
|
|
||||||
},
|
|
||||||
Gitea = {
|
|
||||||
BaseUrl = "https://git.realrobin.io",
|
|
||||||
Implemented = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EmptyRepository = {
|
|
||||||
Owner = nil,
|
|
||||||
Name = nil,
|
|
||||||
ShortName = nil,
|
|
||||||
RepoIdentifier = nil,
|
|
||||||
Remote = nil,
|
|
||||||
CurrentBranch = nil,
|
|
||||||
CurrentLocalPath = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
---default repo to update
|
|
||||||
DefaultRepository = {
|
|
||||||
Owner = "seesberger",
|
|
||||||
Name = "PowerManager",
|
|
||||||
ShortName = "powerman",
|
|
||||||
RepoIdentifier = "seesberger/PowerManager",
|
|
||||||
Remote = SupportedRemotes.Github,
|
|
||||||
CurrentBranch = "master",
|
|
||||||
CurrentLocalPath = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
DefaultTemporaryDownloadPath = "/home/.tmp/git/"
|
|
||||||
DefaultInstallationPath = "/usr/"
|
|
||||||
|
|
||||||
local function askYesOrNoQuestion(question, expectedTrue, expectedFalse, defaultYesOnEnter)
|
|
||||||
local function checkContains(array,value)
|
|
||||||
for idx, val in pairs(array) do
|
|
||||||
if value == val then return true end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
if defaultYesOnEnter==true then print(question.." [Y/n]") else print(question.." [y/N]") end
|
|
||||||
while true do
|
|
||||||
local userInput = io.read("l")
|
|
||||||
if checkContains({""}, userInput) then return defaultYesOnEnter end
|
|
||||||
if checkContains(expectedTrue, userInput) then return true end
|
|
||||||
if checkContains(expectedFalse, userInput) then return false end
|
|
||||||
print("Please answer with yes or no. You can also press ENTER to choose the default option.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function askTextQuestion(question, defaultAnswerOnEnter, allowOnly)
|
|
||||||
local allowedInputsString = ""
|
|
||||||
for idx, entry in pairs(allowOnly) do allowedInputsString = allowedInputsString..entry end
|
|
||||||
if allowOnly then print(question.." ["..allowedInputsString.."]")
|
|
||||||
else print(question) end
|
|
||||||
local userInput = nil
|
|
||||||
local found = false
|
|
||||||
repeat
|
|
||||||
userInput = io.read("l")
|
|
||||||
if allowOnly then
|
|
||||||
for idx, entry in pairs(allowOnly) do if entry == userInput then found = true end end
|
|
||||||
else break end
|
|
||||||
until found
|
|
||||||
if userInput == "" then return defaultAnswerOnEnter else return userInput end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function makeDirIfNotExists(target)
|
|
||||||
if filesystem.exists(target) then
|
|
||||||
if not filesystem.isDirectory(target) then error("target directory already exists and is not a directory.") end
|
|
||||||
if filesystem.get(target).isReadOnly() then error("target directory is read-only.") end
|
|
||||||
else
|
|
||||||
if not filesystem.makeDirectory(target) then error("directory creation failed") end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- todo: pcall and catch errors
|
|
||||||
local function downloadRepo(repository, remote, autoOverride, targetDownloadPath)
|
|
||||||
|
|
||||||
local function validateRepositoryIdentifier(repository)
|
|
||||||
if not repository.RepoIdentifier:match("^[%w-.]*/[%w-.]*$") then
|
|
||||||
print('"'..repository.RepoIdentifier..'" does not look like a valid repo identifier.\nShould be <owner>/<reponame>')
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
validateRepositoryIdentifier(repository)
|
|
||||||
|
|
||||||
--- FIXME: If download only mode is enabled, set this to /home. still todo
|
|
||||||
repository.CurrentLocalPath = targetDownloadPath.."/"
|
|
||||||
local success, res = pcall(makeDirIfNotExists, targetDownloadPath)
|
|
||||||
if not success then error("the download failed because of filesystem errors.") end
|
|
||||||
|
|
||||||
local function fetchFilesAndSubdirs(repository, remote, dir)
|
|
||||||
dir = dir or "" -- default value, start at root dir
|
|
||||||
if remote == SupportedRemotes.Github then
|
|
||||||
print("fetching contents for "..repository.RepoIdentifier..dir)
|
|
||||||
local githubApiUrl="https://api.github.com/repos/"..repository.RepoIdentifier.."/contents"..dir
|
|
||||||
local success,chunks=pcall(internet.request,githubApiUrl)
|
|
||||||
local raw=""
|
|
||||||
local files={}
|
|
||||||
local directories={}
|
|
||||||
|
|
||||||
if success then for chunk in chunks do raw=raw..chunk end
|
|
||||||
else error("you've been cut off. Serves you right.") end
|
|
||||||
|
|
||||||
--- do not question the magic of the outer gods
|
|
||||||
--- turns raw response into t, which has usable fields.
|
|
||||||
raw=raw:gsub("%[","{"):gsub("%]","}"):gsub("(\".-\"):(.-[,{}])",function(a,b) return "["..a.."]="..b end)
|
|
||||||
local t=load("return "..raw)()
|
|
||||||
|
|
||||||
for i=1,#t do
|
|
||||||
if t[i].type=="dir" then
|
|
||||||
table.insert(directories,dir.."/"..t[i].name)
|
|
||||||
|
|
||||||
local subfiles,subdirs=fetchFilesAndSubdirs(repository,remote,dir.."/"..t[i].name)
|
|
||||||
for i=1,#subfiles do
|
|
||||||
table.insert(files,subfiles[i])
|
|
||||||
end
|
|
||||||
for i=1,#subdirs do
|
|
||||||
table.insert(directories,subdirs[i])
|
|
||||||
end
|
|
||||||
else
|
|
||||||
files[#files+1]=dir.."/"..t[i].name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return files, directories
|
|
||||||
else error("not Implemented") end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- fetch and make dirs in the target download path recursively
|
|
||||||
local files,dirs=fetchFilesAndSubdirs(repository, repository.Remote, "")
|
|
||||||
for i=1,#dirs do
|
|
||||||
local success, err = pcall(makeDirIfNotExists, targetDownloadPath..dirs[i])
|
|
||||||
if not success then error(("the download failed because of filesystem errors. %x"):format(err)) end
|
|
||||||
end
|
|
||||||
|
|
||||||
local replaceMode="ask"
|
|
||||||
if autoOverride == true then replaceMode = "always" end
|
|
||||||
|
|
||||||
local function downloadFiles(files, targetDownloadPath, replaceMode)
|
|
||||||
local replace=nil
|
|
||||||
local downloadedFileTargets = {}
|
|
||||||
for i=1,#files do
|
|
||||||
if replaceMode == "always" then replace = true end
|
|
||||||
local fileExists = filesystem.exists(targetDownloadPath..files[i])
|
|
||||||
if fileExists then
|
|
||||||
--- FIXME dir löschen statt error
|
|
||||||
if filesystem.isDirectory(targetDownloadPath..files[i]) then error("file "..targetDownloadPath..files[i].." blocked by directory with same name!") end
|
|
||||||
|
|
||||||
if replace == nil then
|
|
||||||
local userInput = askTextQuestion("\nFile "..targetDownloadPath..files[i].." already exists.\nReplace with new version?","n",{"y","n","A","S"})
|
|
||||||
|
|
||||||
--- FIXME: replaceMode ist broken. A wird immer wieder gefragt.
|
|
||||||
if userInput=="A" then
|
|
||||||
replaceMode="always"
|
|
||||||
userInput="y"
|
|
||||||
elseif userInput=="S" then
|
|
||||||
replaceMode="never"
|
|
||||||
userInput="n"
|
|
||||||
end
|
|
||||||
if userInput == "y" then replace=true end
|
|
||||||
if userInput == "n" then replace=false end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if fileExists and replace then filesystem.remove(targetDownloadPath..files[i]) end
|
|
||||||
if replace or (replace == nil) then
|
|
||||||
--- TODO @Freddy: Coole Animation hinzufügen
|
|
||||||
print("downloading file "..files[i])
|
|
||||||
--- HACK: RawApiUrl is for using Github Raw API. may have to be patched for Gitea Support
|
|
||||||
local url=repository.Remote.RawApiUrl..repository.RepoIdentifier.."/"..repository.CurrentBranch..files[i]
|
|
||||||
local success,response=pcall(internet.request,url)
|
|
||||||
if success then
|
|
||||||
local raw=""
|
|
||||||
for chunk in response do
|
|
||||||
raw=raw..chunk
|
|
||||||
end
|
|
||||||
local absoluteDownloadFileTargetPath = targetDownloadPath..files[i]
|
|
||||||
print("writing to "..absoluteDownloadFileTargetPath)
|
|
||||||
local file=io.open(absoluteDownloadFileTargetPath,"w")
|
|
||||||
if file then -- might be nil under wierd circumstances
|
|
||||||
file:write(raw)
|
|
||||||
file:close()
|
|
||||||
end
|
|
||||||
table.insert(downloadedFileTargets, files[i])
|
|
||||||
else error("a file did not download correctly. aborting") end
|
|
||||||
else error("file not removed, but installation was cancelled - This might result in a broken install.") end
|
|
||||||
end
|
|
||||||
--- return list of all abolute paths the files were downloaded to
|
|
||||||
return downloadedFileTargets
|
|
||||||
end
|
|
||||||
|
|
||||||
success, res = pcall(downloadFiles, files, targetDownloadPath, replaceMode)
|
|
||||||
if success then print("All files downloaded successfully.") return res else error(res) end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function installFiles(downloadedFiles, downloadTargetDir, installTargetDir)
|
|
||||||
local installedFiles = {}
|
|
||||||
|
|
||||||
--- FIXME: ask user about replacing files.
|
|
||||||
local replace = true
|
|
||||||
makeDirIfNotExists(installTargetDir)
|
|
||||||
for idx, file in pairs(downloadedFiles) do
|
|
||||||
local absoluteDownloadFilePath = downloadTargetDir.."/"..file:sub(2,-1)
|
|
||||||
print(idx..": Installing File "..absoluteDownloadFilePath.." to target directory "..installTargetDir..file)
|
|
||||||
local fileExists = filesystem.exists(installTargetDir..file)
|
|
||||||
if fileExists and replace then filesystem.remove(installTargetDir..file) end
|
|
||||||
if replace or (replace == nil) then
|
|
||||||
--- TODO @Freddy: Coole Animation hinzufügen
|
|
||||||
os.execute("cp "..absoluteDownloadFilePath.." "..installTargetDir..file)
|
|
||||||
table.insert(installedFiles, installTargetDir..file)
|
|
||||||
else error("file not removed, but installation was cancelled - This might result in a broken install.") end
|
|
||||||
end
|
|
||||||
return installedFiles
|
|
||||||
end
|
|
||||||
|
|
||||||
local function installShortcut(currentRepoPath, shortcutName, targetDir)
|
|
||||||
print("installing shortcut...")
|
|
||||||
makeDirIfNotExists(targetDir)
|
|
||||||
local shortcutInstallTarget = currentRepoPath.."shortcut.lua "..targetDir..shortcutName..".lua"
|
|
||||||
os.execute("mv "..shortcutInstallTarget)
|
|
||||||
return {shortcutInstallTarget}
|
|
||||||
end
|
|
||||||
|
|
||||||
--- todo: automatic read of dependency list (txt file containing lines with <link> <dst> or somethink like it)
|
|
||||||
--- removeme
|
|
||||||
local function legacyInstallDependencies()
|
|
||||||
print("Legacy Mode: Installing hardcoded dependencies...")
|
|
||||||
os.execute("wget -f https://github.com/kevinkk525/OC-GUI-API/raw/master/shapes_default.lua /lib/shapes_default.lua")
|
|
||||||
os.execute("wget -f https://github.com/kevinkk525/OC-GUI-API/raw/master/GUI.lua /lib/GUI.lua")
|
|
||||||
os.execute("wget -f https://github.com/kevinkk525/OC-GUI-API/raw/master/term_mod.lua /lib/term_mod.lua")
|
|
||||||
os.execute("wget -f https://github.com/kevinkk525/OC-GUI-API/raw/master/tech_demo.lua /home/GUI_tech_demo.lua")
|
|
||||||
local installedDependencies = {"/lib/shapes_default.lua", "/lib/GUI.lua", "/lib/term_mod.lua", "/home/GUI_tech_demo.lua"}
|
|
||||||
return installedDependencies
|
|
||||||
end
|
|
||||||
|
|
||||||
local function removeDownloads(downloadTargetDir, downloadedFiles)
|
|
||||||
for idx, file in pairs(downloadedFiles) do
|
|
||||||
file = file:sub(2,-1) --- get "file" from previous string "/file"
|
|
||||||
print(idx..": Removing temporary file "..downloadTargetDir..file)
|
|
||||||
local fileExists = filesystem.exists(downloadTargetDir..file)
|
|
||||||
if fileExists then filesystem.remove(downloadTargetDir..file) end
|
|
||||||
end
|
|
||||||
print("cleaned temporary files.")
|
|
||||||
end
|
|
||||||
|
|
||||||
local function removeFilesViaManifest(manifestTarget)
|
|
||||||
--- todo
|
|
||||||
end
|
|
||||||
|
|
||||||
local function createManifest(installedDependencies, installedFiles, installedShortcuts, manifestTarget, repoName)
|
|
||||||
makeDirIfNotExists(manifestTarget)
|
|
||||||
local manifest = ""
|
|
||||||
for idx, file in pairs(installedFiles) do
|
|
||||||
manifest = manifest..file.."\n"
|
|
||||||
end
|
|
||||||
for idy, shortcut in pairs(installedShortcuts) do
|
|
||||||
manifest = manifest..shortcut.."\n"
|
|
||||||
end
|
|
||||||
for idz, dependency in pairs(installedDependencies) do
|
|
||||||
manifest = manifest..dependency.."\n"
|
|
||||||
end
|
|
||||||
print("writing manifest to "..manifestTarget..repoName)
|
|
||||||
local file=io.open(manifestTarget..repoName,"w")
|
|
||||||
if file then -- might be nil under wierd circumstances
|
|
||||||
file:write(manifest)
|
|
||||||
file:close()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- fix legacy shit
|
|
||||||
local function runFullInstallTask(repository, shortcutName)
|
|
||||||
--- first, download the actual repo.
|
|
||||||
--- then, find dependencies - if then exist, download and install them
|
|
||||||
--- then, install the actual program
|
|
||||||
local installTargetDir = "/usr/"..repository.Name
|
|
||||||
local shortcutTargetDir = "/usr/bin/"
|
|
||||||
local downloadTargetDir = DefaultTemporaryDownloadPath..repository.RepoIdentifier
|
|
||||||
local manifestTarget = "/etc/manifest/"
|
|
||||||
|
|
||||||
local installedDependencies = legacyInstallDependencies() --only for testing while new version not implemented yet
|
|
||||||
print("downloading "..repository.RepoIdentifier)
|
|
||||||
local downloadedFiles = downloadRepo(repository, repository.Remote, false, downloadTargetDir) --enable auto-overwrite in other situations still todo
|
|
||||||
local installedFiles = installFiles(downloadedFiles, downloadTargetDir, installTargetDir)
|
|
||||||
local installedShortcuts = installShortcut(repository.CurrentLocalPath, shortcutName, shortcutTargetDir)
|
|
||||||
|
|
||||||
--- remove temporary files and create manifest for later uninstall
|
|
||||||
removeDownloads(downloadTargetDir, downloadedFiles)
|
|
||||||
createManifest(installedDependencies, installedFiles, installedShortcuts, manifestTarget, repository.Name)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function printHelpText()
|
|
||||||
local helpText = "This updater pulls the git files for installation and application updates.\n"..
|
|
||||||
"Usage:\n" ..
|
|
||||||
"updater <option> - no args: manual update and install\n"..
|
|
||||||
" '' -h or - this help text\n"..
|
|
||||||
" '' -d or - install default config"
|
|
||||||
print(helpText)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function run(cliArgs)
|
|
||||||
local repo = EmptyRepository
|
|
||||||
local shortcutName = nil
|
|
||||||
|
|
||||||
if #cliArgs<1 then
|
|
||||||
print("No Arguments given. For help, please check -h or --help")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if cliArgs[1] == "-h" then
|
|
||||||
printHelpText()
|
|
||||||
return
|
|
||||||
elseif cliArgs[1] == "-d" then
|
|
||||||
--- ask user about repo
|
|
||||||
if askYesOrNoQuestion("Use default config? (github::seesberger/PowerManager)?",YES,NO,true) == true then
|
|
||||||
repo = DefaultRepository
|
|
||||||
--- ask user about shortcutname
|
|
||||||
if askYesOrNoQuestion("Use default shortcut name \"powerman\"?",YES,NO,true) then shortcutName = "powerman" end
|
|
||||||
runFullInstallTask(repo, shortcutName)
|
|
||||||
--- TODO non-default config
|
|
||||||
else print("other things not implemented yet") end
|
|
||||||
else
|
|
||||||
print('"'..cliArgs[1]..'" - Bad argument. Try --help')
|
|
||||||
print("Program exited.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
run(args)
|
|
||||||
Reference in New Issue
Block a user