openos improvements

1. if /home is readonly, a helpful message is displayed tell the user to run install
2. remove -i from `cp` alias because a bunch of people complain about it
3. `install` now does not clobber /etc/rc.cfg nor /home/.shrc
This commit is contained in:
payonel 2020-05-21 00:36:09 -07:00
parent 4857395e6a
commit 09505e6cff
8 changed files with 91 additions and 60 deletions

View File

@ -1 +1 @@
{label = "OpenOS", reboot=true, setlabel=true, setboot=true}
{label = "OpenOS", reboot=true, setlabel=true, setboot=true, noclobber={"etc/rc.cfg","home/.shrc"}}

View File

@ -30,7 +30,7 @@ options =
P = options.P,
v = options.v,
x = options.x,
skip = options.skip,
skip = {options.skip},
}
return transfer.batch(args, options)

View File

@ -1,6 +1,4 @@
local computer = require("computer")
local shell = require("shell")
local options
do
@ -12,21 +10,23 @@ do
options = basic(...)
end
if not options then return end
if not options then
return
end
if computer.freeMemory() < 50000 then
print("Low memory, collecting garbage")
for i=1,20 do os.sleep(0) end
for i = 1, 20 do
os.sleep(0)
end
end
local cp, reason = loadfile(shell.resolve("cp", "lua"), "bt", _G)
assert(cp, reason)
local ok, ec = pcall(cp, table.unpack(options.cp_args))
assert(ok, ec)
if ec ~= nil and ec ~= 0 then
return ec
local transfer = require("tools/transfer")
for _, inst in ipairs(options.cp_args) do
local ec = transfer.batch(table.unpack(inst))
if ec ~= nil and ec ~= 0 then
return ec
end
end
print("Installation complete!")
@ -44,7 +44,7 @@ end
if options.reboot then
io.write("Reboot now? [Y/n] ")
if ((io.read() or "n").."y"):match("^%s*[Yy]") then
if ((io.read() or "n") .. "y"):match("^%s*[Yy]") then
print("\nRebooting now!\n")
computer.shutdown(true)
end

View File

@ -24,7 +24,7 @@ options =
i = options.i,
v = options.v,
n = options.n, -- no clobber
skip = options.skip,
skip = {options.skip},
P = true, -- move operations always preserve
r = true, -- move is allowed to move entire dirs
x = true, -- cannot move mount points

View File

@ -32,3 +32,7 @@ for _,line in ipairs(lines) do
io.write(borders[2][1], " ", line, (" "):rep(maxLine - #line + 1), borders[2][3], " \n")
end
io.write(borders[3][1] .. string.rep(borders[3][2], maxLine + 2) .. borders[3][3] .. "\n")
if require("filesystem").get("home").isReadOnly() then
io.write("\27[33mNote: Your home directory is readonly. Run `install` and reboot.\27[m\n")
end

View File

@ -20,7 +20,6 @@ shell.setAlias("cls", "clear")
shell.setAlias("rs", "redstone")
shell.setAlias("view", "edit -r")
shell.setAlias("help", "man")
shell.setAlias("cp", "cp -i")
shell.setAlias("l", "ls -lhp")
shell.setAlias("..", "cd ..")
shell.setAlias("df", "df -h")

View File

@ -27,7 +27,7 @@ local utils
local rootfs = fs.get("/")
if not rootfs then
io.stderr:write("no root filesystem, aborting\n");
io.stderr:write("no root filesystem, aborting\n")
os.exit(1)
end
@ -86,11 +86,13 @@ for dev, path in pairs(devices) do
io.stderr:write("Cannot install to " .. options.to .. ", it is read only\n")
os.exit(1)
end
elseif specified or
not (source_filter and address:find(source_filter, 1, true) == 1) and -- specified for source
not target_filter and
address ~= tmpAddress then
table.insert(targets, {dev=dev, path=install_path, specified=specified})
elseif
specified or
not (source_filter and address:find(source_filter, 1, true) == 1) and -- specified for source
not target_filter and
address ~= tmpAddress
then
table.insert(targets, {dev = dev, path = install_path, specified = specified})
end
end
@ -105,11 +107,11 @@ for dev, path in pairs(devices) do
local install_path = dev == source_filter_dev and options.from or path
local specified = source_filter and address:find(source_filter, 1, true) == 1
if fs.list(install_path)()
and (specified or
not source_filter and
address ~= tmpAddress and
not (address == rootfs.address and not rootfs.isReadOnly())) then
if
fs.list(install_path)() and
(specified or
not source_filter and address ~= tmpAddress and not (address == rootfs.address and not rootfs.isReadOnly()))
then
local prop = {}
local prop_path = path .. "/.prop"
local prop_file = fs.open(prop_path)
@ -125,7 +127,7 @@ for dev, path in pairs(devices) do
end
if not prop.ignore then
if not label or label:lower() == (prop.label or dev.getLabel() or ""):lower() then
table.insert(sources, {dev=dev, path=install_path, prop=prop, specified=specified})
table.insert(sources, {dev = dev, path = install_path, prop = prop, specified = specified})
end
end
end
@ -137,23 +139,24 @@ if #sources ~= 1 then
utils = loadfile(utils_path, "bt", _G)
source = utils("select", "sources", options, sources)
end
if not source then return end
if not source then
return
end
options =
{
from = source.path .. '/',
fromDir = fs.canonical(options.fromDir or source.prop.fromDir or ""),
root = fs.canonical(options.root or options.toDir or source.prop.root or ""),
update = options.update or options.u,
label = source.prop.label or label,
options = {
from = source.path .. "/",
fromDir = fs.canonical(options.fromDir or source.prop.fromDir or ""),
root = fs.canonical(options.root or options.toDir or source.prop.root or ""),
update = options.update or options.u,
label = source.prop.label or label,
setlabel = not (options.nosetlabel or options.nolabelset) and source.prop.setlabel,
setboot = not (options.nosetboot or options.noboot) and source.prop.setboot,
reboot = not options.noreboot and source.prop.reboot,
setboot = not (options.nosetboot or options.noboot) and source.prop.setboot,
reboot = not options.noreboot and source.prop.reboot
}
local source_display = options.label or source.dev.getLabel() or source.path
-- Remove the source from the target options
for index,entry in ipairs(targets) do
for index, entry in ipairs(targets) do
if entry.dev == source.dev then
table.remove(targets, index)
target = targets[1]
@ -162,47 +165,67 @@ end
-- Ask the user to select a target
if #targets ~= 1 then
if #sources == 1 then
io.write(source_display, " selected for install\n")
end
if #sources == 1 then
io.write(source_display, " selected for install\n")
end
utils = utils or loadfile(utils_path, "bt", _G)
utils = utils or loadfile(utils_path, "bt", _G)
target = utils("select", "targets", options, targets)
end
if not target then return end
if not target then
return
end
options.to = target.path .. '/'
options.to = target.path .. "/"
local cp_args =
{
"-vrx" .. (options.update and "ui" or ""),
"--skip=.prop",
fs.concat(options.from, options.fromDir) .. "/.",
fs.concat(options.to , options.root)
local function resolveFrom(path)
return fs.concat(options.from, options.fromDir) .. "/" .. path
end
local fullTargetPath = fs.concat(options.to, options.root)
local transfer_args = {
{
{resolveFrom("."), fullTargetPath},
{
cmd = "cp",
r = true, v = true, x = true, u = options.update, i = options.update,
skip = {resolveFrom(".prop")},
}
}
}
if source.prop.noclobber and #source.prop.noclobber > 0 then
local noclobber_opts = {cmd = "cp", v = true, n = true}
for _, noclobber in ipairs(source.prop.noclobber or {}) do
local noclobberFrom = resolveFrom(noclobber)
local noclobberTo = fs.concat(fullTargetPath, noclobber)
table.insert(transfer_args[1][2].skip, noclobberFrom)
table.insert(transfer_args, {{noclobberFrom, noclobberTo}, noclobber_opts})
end
end
local special_target = ""
if #targets > 1 or target_filter or source_filter then
special_target = " to " .. cp_args[4]
special_target = " to " .. transfer_args[1].args[2]
end
io.write("Install " .. source_display .. special_target .. "? [Y/n] ")
if not ((io.read() or "n").."y"):match("^%s*[Yy]") then
if not ((io.read() or "n") .. "y"):match("^%s*[Yy]") then
io.write("Installation cancelled\n")
os.exit()
end
local installer_path = options.from .. "/.install"
if fs.exists(installer_path) then
local installer, reason = loadfile(installer_path, "bt", setmetatable({install=options}, {__index = _G}))
local installer, reason = loadfile(installer_path, "bt", setmetatable({install = options}, {__index = _G}))
if not installer then
io.stderr:write("installer failed to load: " .. tostring(reason) .. '\n')
io.stderr:write("installer failed to load: " .. tostring(reason) .. "\n")
os.exit(1)
end
os.exit(installer())
end
options.cp_args = cp_args
options.cp_args = transfer_args
options.target = target
return options

View File

@ -93,7 +93,7 @@ function lib.recurse(fromPath, toPath, options, origin, top)
local toPathFull = shell.resolve(toPath)
local mv = options.cmd == "mv"
local verbose = options.v and (not mv or top)
if select(2, fromPathFull:find(options.skip)) == #fromPathFull then
if options.skip[fromPathFull] then
status(verbose, string.format("skipping %s", fromPath))
return true
end
@ -221,8 +221,13 @@ function lib.batch(args, options)
-- standardized options
options.i = options.i and not options.f
options.P = options.P or options.r
options.skip = text.escapeMagic(options.skip or "")
local skips = options.skip or {}
options.skip = {}
for _, skip_item in ipairs(skips) do
options.skip[shell.resolve(skip_item)] = true
end
local origin = {}
for dev,path in fs.mounts() do
origin[path] = dev