This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
LtKillPuppy's profile picture

[1.31] os.loadAPI will not attempt to re-load an API that errored out

Started by LtKillPuppy, 31 March 2012 - 08:38 AM
LtKillPuppy #1
Posted 31 March 2012 - 10:38 AM
ComputerCraft Version Information:
1.31 (tried in SPP only)

Description of Bug:
Cannot re-load an API if it contains a bug and compilation of the chunk failed. (Works if you reboot the lua VM instance, however. ie: CTRL-R the Computer.)

Steps to Reproduce Bug:
Create a file to be loaded as an API. Make sure it's got a compile error in it. Example: A file called "testAPI" which contains…


-- Oops!  A typo!  Expression instead of statement!
test == 3

Now, load it in some other program. ie: os.loadapi ("testAPI")

You'll get the expected error when lua attempts to compile it. (bios:206: [string "testAPI"]:5: '=' expected)

Now go fix your typo!

Try to load it again.

You'll get API testAPI is already being loaded.

Proposed Fix:
Fix that seems obvious is to modify os.loadAPI in bios.lua as such:


if fnAPI then
  setfenv( fnAPI, tEnv )
  fnAPI()
else
  print( err )
  tAPIsLoading[sName] = nil
  return false
end

Note setting the tAPIsLoading set to nil if there is an error. Tested and it seems to work fine. But I don't know if this would break something else that might rely upon this behavior.
Liraal #2
Posted 31 March 2012 - 10:45 AM
You can also try os.unloadAPI(), works fine in newer version of CC (higher than 1.2).
xuma202 #3
Posted 31 March 2012 - 10:45 AM
Maybe you have to unload the buggy API beforehand?
FuzzyPurp #4
Posted 31 March 2012 - 04:26 PM
Or reboot the terminal.
LtKillPuppy #5
Posted 01 April 2012 - 02:05 AM
os.unloadAPI doesn't work. Because os.loadAPI remembers the API's basename in tAPIsLoading, then you are stuck.

Rebooting does work. But I still consider this a bug since os.loadAPI will no longer attempt to load that API for the duration of the VM's existence. Somewhat of a pain to me since I like to load/unload/test APIs at runtime. :o/>/>
davidgumazon #6
Posted 11 November 2014 - 02:43 PM
os.loadAPI API in latest Version is now Limited

i create new file myapi
function test(a)
print(a)
end

i create new file try
print("hi")
os.loadAPI("myapi")
myapi.test("hello")

i open the file try
Result :
hi
hello

i edit file myapi
function test(a)
print(a)
end
function plus(B)/>
print(B)/>
end

i edit the file try
print("hi")
os.loadAPI("myapi")
myapi.test("hello")
myapi.plus("hey")

i open the file try
Result :
hi
API myapi is already being loaded

i Repeat Open The File
Same Result
but
Reboot the Computer then open the File try
Works Fine!
this is the Result :
hi
hello
hey

i hate this New System of os.loadAPI
Lyqyd #7
Posted 11 November 2014 - 03:57 PM
This bug was fixed long ago. The fix is still present in ComputerCraft 1.65. Are you sure you didn't accidentally include an os.loadAPI line in your API, attempting to load your API? Which version are you using?
Bomb Bloke #8
Posted 11 November 2014 - 11:07 PM
I've been able to replicate in recent builds, but if memory serves, about the only way to pull it off is to have the API specifically call error() while it's loading. For whatever reason this causes os.loadAPI() to break out before updating its "being loaded" table.

To be clear davidgumazon, the function isn't complaining that the API has been loaded. It's complaining because it thinks it's already in the process of being loaded.
Lyqyd #9
Posted 12 November 2014 - 01:06 AM
Well, if that's the case, I suppose davidgumazon could try swapping out his os.loadAPI for this:


local tAPIsLoading = {}
function os.loadAPI( _sPath )
    local sName = fs.getName( _sPath )
    if tAPIsLoading[sName] == true then
        printError( "API "..sName.." is already being loaded" )
        return false
    end
    tAPIsLoading[sName] = true
    
    local tEnv = {}
    setmetatable( tEnv, { __index = _G } )
    local fnAPI, err = loadfile( _sPath )
    if fnAPI then
        setfenv( fnAPI, tEnv )
        local bSuccess, err = pcall( fnAPI )
        if not bSuccess then
            printError( err )
            tAPIsLoading[sName] = nil
            return false
        end
    else
        printError( err )
        tAPIsLoading[sName] = nil
        return false
    end
    
    local tAPI = {}
    for k,v in pairs( tEnv ) do
        tAPI[k] = v
    end
    
    _G[sName] = tAPI
    tAPIsLoading[sName] = nil
    return true
end
LtKillPuppy #10
Posted 08 December 2014 - 11:49 PM
Fast-forward to today: I've verified that this bug has been fixed in ComputerCraft as of 1.6.4. :)/>
ElvishJerricco #11
Posted 09 December 2014 - 06:46 AM
Looking at the code for os.loadAPI, there should still be a relevant error.


function os.loadAPI( _sPath )
	local sName = fs.getName( _sPath )
	if tAPIsLoading[sName] == true then
		printError( "API "..sName.." is already being loaded" )
		return false
	end
	tAPIsLoading[sName] = true

	local tEnv = {}
	setmetatable( tEnv, { __index = _G } )
	if fnAPI then
		setfenv( fnAPI, tEnv )
		fnAPI()
	else
		printError( err )
		tAPIsLoading[sName] = nil
		return false
	end

	local tAPI = {}
	for k,v in pairs( tEnv ) do
		tAPI[k] =  v
	end

	_G[sName] = tAPI	
	tAPIsLoading[sName] = nil
	return true
end

Note that the call to fnAPI isn't protected. If my api looks like this, it will error and the OS won't know that the API isn't still being loaded.


-- myapi
function doThing()
	...
end

function doOtherThing()
	...
end

-- initialize API
doThing()
doOtherThin() -- misspelled

This is just one example. Any runtime error, such as a typo in a function call, during the API's initialization will have this problem. The fix is simply to wrap the fnAPI call in pcall. EDIT: Or rather, I think, it should use os.run, so that any overrides of os.run get to apply on the API level.



function os.loadAPI( _sPath )
	local sName = fs.getName( _sPath )
	if tAPIsLoading[sName] == true then
		printError( "API "..sName.." is already being loaded" )
		return false
	end
	tAPIsLoading[sName] = true

	local tEnv = {}
	if not os.run(tEnv, _sPath) then
		tAPIsLoading[sName] = nil
		return false
	end

	local tAPI = {}
	for k,v in pairs( tEnv ) do
		tAPI[k] =  v
	end

	_G[sName] = tAPI	
	tAPIsLoading[sName] = nil
	return true
end
Edited on 09 December 2014 - 05:57 AM
dan200 #12
Posted 02 February 2015 - 09:31 PM
Fixed in CC1.66