mirror of
https://github.com/kepler155c/opus
synced 2024-11-15 21:24:49 +00:00
239 lines
6.2 KiB
Lua
239 lines
6.2 KiB
Lua
|
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()
|