Accessing shell API from shell-less environment
#1
Posted 10 September 2015 - 03:03 PM
My current solution works by getting the environment from the startup program (where shell is available) using getfenv, making it available to the menu program by using os.run, and then passing it back and forth so it can be accessed by the function I use to load programs when neccessary.
Is there a way to get access to the shell api from the fileloading function without passing the appropriate environment as a function parameter? One possibility: I know I can get the environment from different stack levels, for example, getfenv(2) gets the environment that called the current function (as I understood it. I just don't know how to determine the *first* caller.
Thanks for your help. Please let me know if you need clarification and I will edit my question!
#2
Posted 10 September 2015 - 03:18 PM
local env = setmetatable({shell = shell, multishell = multishell}, {__index = _G})
Bear in mind that you are breaking the functionality of the shell "API" when you do this, as any programs you are running this way will not get sane values when calling shell.getRunningProgram().
#3
Posted 10 September 2015 - 05:27 PM
Lyqyd, on 10 September 2015 - 03:18 PM, said:
local env = setmetatable({shell = shell, multishell = multishell}, {__index = _G})
Bear in mind that you are breaking the functionality of the shell "API" when you do this, as any programs you are running this way will not get sane values when calling shell.getRunningProgram().
Hi, thanks for your answer. I don't think I understood your suggestion correctly; I tried the following to handle the loading:
-- first try
function runFile(path)
local file = fs.open(path, 'r').readAll();
file = "local env = setmetatable({shell = shell, multishell = multishell}, {__index = _G}); "..file
local func = loadstring(file)
func()
end
-- second try
function runFile(path)
local func = loadfile(path)
local env = setmetatable({shell = shell, multishell = multishell}, {__index = _G})
setfenv(func, env)
func()
end
Alas, neither worked. Can you elaborate on your answer?
Edited by statistician, 10 September 2015 - 08:01 PM.
#4
Posted 10 September 2015 - 07:09 PM
#5
Posted 10 September 2015 - 07:59 PM
Lyqyd, on 10 September 2015 - 07:09 PM, said:
There was an error with my paste, I'll correct it. Can you answer based on the edited reply?
Also, I was able to make the following code work:
function runFile(path)
local n = 1
local function tryenv()
return getfenv(n)
end
while pcall(tryenv) do
n = n + 1
if getfenv(n).shell then
print("environment containing shell found at level: "..n)
break
end
end
local func = loadfile(path)
setfenv(func, getfenv(n))
func()
end
I'm still interested in the method you're describing, though. If I understood correctly, however, the above method isn't breaking shell API's functionality like the one we are discussing.
#6
Posted 10 September 2015 - 09:03 PM
local n = 0
while getfenv(n) and not getfenv(n).shell do
n = n + 1
end
local _shell = getfenv(n).shell
Seems a bit shorter to me, and I don't think getfenv() can error?Your second attempt (now edited I believe) should work just fine, although you might want to switch to using load() for future compatibility. In future CC versions, setfenv() won't be supported. Instead, you can use load() which works like this:
load( string code, string source, _ignore_this_, table env )With the arguments past the first one all being optional. That'll work like loadstring(), but allow you to set its environment.
The reason that shell may break is because the thing that shell.getRunningProgram() returns will be the path to your program rather than the one you run using runFile(). You could load up a custom shell API yourself, or even use:
env.shell = setmetatable( { getRunningProgram = customGetRunningProgram }, { __index = shell } )
to fix it. Then again, it might not be a huge issue, and you might be able to leave it. I generally write programs with this in mind so they don't rely too heavily on shell.getRunningProgram().
#7
Posted 10 September 2015 - 11:54 PM
#8
Posted 11 September 2015 - 09:42 AM
function runFile(path)
local n = 0
while getfenv(n) and not getfenv(n).shell do
n = n + 1
end
local func = loadfile(path)
setfenv(func, getfenv(n))
func()
end
which is pretty much what awsumben13 suggested. I had it like this before, but it didn't work then; I guess there was something else wrong. Even so, this code still doesn't work:
function runFile(path)
local func = loadfile(path)
local env = setmetatable({shell = shell, multishell = multishell}, {__index = _G})
setfenv(func, env)
func()
end
#9
Posted 11 September 2015 - 02:56 PM
#10
Posted 11 September 2015 - 03:22 PM
awsumben13, on 11 September 2015 - 02:56 PM, said:
Ah, that's true. The startup file calls a "controlpanel" program with shell.run, but the "controlpanel" program loads "utils" (where the runFile method resides) with os.loadAPI. shell isn't available to apis, am I correct? Is there an easy way to bypass this?
#11
Posted 11 September 2015 - 03:32 PM
local _shell = _G.shell _G.shell = shell os.loadAPI( "SomeAPI" ) _G.shell = _shelland in 'SomeAPI'
local shell = _G.shell ...
#12
Posted 11 September 2015 - 04:57 PM
#13
Posted 12 September 2015 - 03:40 PM
#14
Posted 12 September 2015 - 04:52 PM
Creator, on 12 September 2015 - 03:40 PM, said:
The shell API doesn't exist in the global namespace. It resides in _ENV only for programs ran through the shell/started with shell.run.
#15
Posted 12 September 2015 - 10:45 PM
Creator, on 12 September 2015 - 03:40 PM, said:
Because the shell "API" is an interface exposed by a specific shell instance to programs running under it. Changes to one instance would not affect any other instances, and programs running contemporaneously should have their own instance to work with. For example, if you were using multishell and started a second shell in a new tab, you could modify the path, or the aliases, or run a program, and you would not see any changes to the values the shell "API" would return in the other shell instance.
#16
Posted 13 September 2015 - 09:21 AM
2 user(s) are reading this topic
0 members, 2 guests, 0 anonymous users











