partition manager + tab/wizard rework
This commit is contained in:
238
sys/apps/Partition.lua
Normal file
238
sys/apps/Partition.lua
Normal file
@@ -0,0 +1,238 @@
|
||||
local Ansi = require('opus.ansi')
|
||||
local Event = require('opus.event')
|
||||
local UI = require('opus.ui')
|
||||
local Util = require('opus.util')
|
||||
|
||||
local fs = _G.fs
|
||||
local peripheral = _G.peripheral
|
||||
|
||||
local source, target
|
||||
|
||||
local function getDriveInfo(tgt)
|
||||
local total = 0
|
||||
local throttle = Util.throttle()
|
||||
|
||||
tgt = fs.combine(tgt, '')
|
||||
local src = fs.getNode(tgt).source or tgt
|
||||
|
||||
local function recurse(path)
|
||||
throttle()
|
||||
if fs.isDir(path) then
|
||||
if path ~= src then
|
||||
total = total + 500
|
||||
end
|
||||
for _, v in pairs(fs.native.list(path)) do
|
||||
recurse(fs.combine(path, v))
|
||||
end
|
||||
else
|
||||
local sz = fs.getSize(path)
|
||||
total = total + math.max(500, sz)
|
||||
end
|
||||
end
|
||||
|
||||
recurse(src)
|
||||
|
||||
local drive = fs.getDrive(src)
|
||||
return {
|
||||
path = tgt,
|
||||
drive = drive,
|
||||
type = peripheral.getType(drive) or drive,
|
||||
used = total,
|
||||
free = fs.getFreeSpace(src),
|
||||
mountPoint = src,
|
||||
}
|
||||
end
|
||||
|
||||
local function getDrives(exclude)
|
||||
local drives = { }
|
||||
|
||||
for _, path in pairs(fs.native.list('/')) do
|
||||
local side = fs.getDrive(path)
|
||||
if side and not drives[side] and not fs.isReadOnly(path) and side ~= exclude then
|
||||
if side == 'hdd' then
|
||||
path = ''
|
||||
end
|
||||
drives[side] = getDriveInfo(path)
|
||||
end
|
||||
end
|
||||
return drives
|
||||
end
|
||||
|
||||
local page = UI.Page {
|
||||
wizard = UI.Wizard {
|
||||
ey = -2,
|
||||
partitions = UI.WizardPage {
|
||||
index = 1,
|
||||
info = UI.TextArea {
|
||||
x = 3, y = 2, ex = -3, ey = 5,
|
||||
value = [[Move the contents of a directory to another disk. A link will be created to point to that location.]]
|
||||
},
|
||||
grid = UI.Grid {
|
||||
x = 2, y = 7, ex = -2, ey = -2,
|
||||
columns = {
|
||||
{ heading = 'Path', key = 'path', textColor = 'yellow', width = 10 },
|
||||
{ heading = 'Mount Point', key = 'mountPoint' },
|
||||
{ heading = 'Used', key = 'used', width = 6 },
|
||||
},
|
||||
sortColumn = 'path',
|
||||
getDisplayValues = function (_, row)
|
||||
row = Util.shallowCopy(row)
|
||||
row.used = Util.toBytes(row.used)
|
||||
return row
|
||||
end,
|
||||
enable = function(self)
|
||||
Event.onTimeout(0, function()
|
||||
local mounts = {
|
||||
usr = getDriveInfo('usr/config'),
|
||||
packages = getDriveInfo('packages'),
|
||||
}
|
||||
self:setValues(mounts)
|
||||
self:draw()
|
||||
self:sync()
|
||||
end)
|
||||
self:setValues({ })
|
||||
UI.Grid.enable(self)
|
||||
end,
|
||||
},
|
||||
validate = function(self)
|
||||
target = self.grid:getSelected()
|
||||
return not not target
|
||||
end,
|
||||
},
|
||||
mounts = UI.WizardPage {
|
||||
index = 2,
|
||||
info = UI.TextArea {
|
||||
x = 3, y = 2, ex = -3, ey = 5,
|
||||
value = [[Select the target disk. Labeled computers can be inserted into disk drives for larger volumes.]]
|
||||
},
|
||||
grid = UI.Grid {
|
||||
x = 2, y = 7, ex = -2, ey = -2,
|
||||
columns = {
|
||||
{ heading = 'Path', key = 'path', textColor = 'yellow', width = 10 },
|
||||
{ heading = 'Type', key = 'type' },
|
||||
{ heading = 'Side', key = 'drive' },
|
||||
{ heading = 'Free', key = 'free', width = 6 },
|
||||
},
|
||||
sortColumn = 'path',
|
||||
getDisplayValues = function (_, row)
|
||||
row = Util.shallowCopy(row)
|
||||
row.free = Util.toBytes(row.free)
|
||||
return row
|
||||
end,
|
||||
getRowTextColor = function(self, row)
|
||||
if row.free < target.used then
|
||||
return 'lightGray'
|
||||
end
|
||||
return UI.Grid.getRowTextColor(self, row)
|
||||
end,
|
||||
enable = function(self)
|
||||
Event.on({ 'disk', 'disk_eject', 'partition_update' }, function()
|
||||
self:setValues(getDrives(target.drive))
|
||||
self:draw()
|
||||
self:sync()
|
||||
end)
|
||||
os.queueEvent('partition_update')
|
||||
self:setValues({ })
|
||||
UI.Grid.enable(self)
|
||||
end,
|
||||
},
|
||||
validate = function(self)
|
||||
source = self.grid:getSelected()
|
||||
if not source then
|
||||
self:emit({ type = 'notify', message = 'No drive selected' })
|
||||
elseif source.free < target.used then
|
||||
self:emit({ type = 'notify', message = 'Insufficient disk space' })
|
||||
else
|
||||
return true
|
||||
end
|
||||
end,
|
||||
},
|
||||
confirm = UI.WizardPage {
|
||||
index = 3,
|
||||
info = UI.TextArea {
|
||||
x = 2, y = 2, ex = -2, ey = -2,
|
||||
marginTop = 1, marginLeft = 1,
|
||||
backgroundColor = 'black',
|
||||
},
|
||||
enable = function(self)
|
||||
local fstab = Util.readFile('usr/etc/fstab')
|
||||
local lines = { }
|
||||
table.insert(lines, string.format('%sReview changes%s\n', Ansi.yellow, Ansi.reset))
|
||||
if fstab then
|
||||
for _,l in ipairs(Util.split(fstab)) do
|
||||
l = Util.trim(l)
|
||||
if #l > 0 and l:sub(1, 1) ~= '#' then
|
||||
local m = Util.matches(l)
|
||||
if m and m[1] and m[1] == target.path then
|
||||
table.insert(lines, string.format('Removed from usr/etc/fstab:\n%s%s%s\n', Ansi.red, l, Ansi.reset))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
local t = target.path
|
||||
local s = fs.combine(source.path .. '/' .. target.path, '')
|
||||
if t ~= s then
|
||||
table.insert(lines, string.format('Added to usr/etc/fstab:\n%s%s linkfs %s%s\n', Ansi.green, t, s, Ansi.reset))
|
||||
end
|
||||
|
||||
table.insert(lines, string.format('Move directory:\n%s/%s -> /%s', Ansi.green, target.mountPoint, s))
|
||||
|
||||
self.info:setText(table.concat(lines, '\n'))
|
||||
UI.WizardPage.enable(self)
|
||||
end,
|
||||
validate = function(self)
|
||||
if self.changesApplied then
|
||||
return true
|
||||
end
|
||||
local fstab = Util.readFile('usr/etc/fstab')
|
||||
local lines = { }
|
||||
if fstab then
|
||||
for _,l in ipairs(Util.split(fstab)) do
|
||||
table.insert(lines, l)
|
||||
l = Util.trim(l)
|
||||
if #l > 0 and l:sub(1, 1) ~= '#' then
|
||||
local m = Util.matches(l)
|
||||
if m and m[1] and m[1] == target.path then
|
||||
fs.unmount(m[1])
|
||||
table.remove(lines)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local t = target.path
|
||||
local s = fs.combine(source.path .. '/' .. target.path, '')
|
||||
|
||||
fs.move('/' .. target.mountPoint, '/' .. s)
|
||||
|
||||
if t ~= s then
|
||||
table.insert(lines, string.format('%s linkfs %s', t, s))
|
||||
fs.mount(t, 'linkfs', s)
|
||||
end
|
||||
|
||||
Util.writeFile('usr/etc/fstab', table.concat(lines, '\n'))
|
||||
|
||||
self.parent.nextButton.text = 'Exit'
|
||||
self.parent.cancelButton:disable()
|
||||
self.parent.previousButton:disable()
|
||||
|
||||
self.changesApplied = true
|
||||
self.info:setValue('Changes have been applied')
|
||||
self.parent:draw()
|
||||
end,
|
||||
},
|
||||
},
|
||||
notification = UI.Notification { },
|
||||
eventHandler = function(self, event)
|
||||
if event.type == 'notify' then
|
||||
self.notification:error(event.message)
|
||||
elseif event.type == 'accept' or event.type == 'cancel' then
|
||||
UI:quit()
|
||||
end
|
||||
return UI.Page.eventHandler(self, event)
|
||||
end,
|
||||
}
|
||||
|
||||
UI:disableEffects()
|
||||
UI:setPage(page)
|
||||
UI:start()
|
||||
Reference in New Issue
Block a user