pkulchenko/MobDebug

File path error on OS X which installed tp case-sensitive partition.

Closed this issue · 15 comments

I installed my OS X to case-sensitive partion.

For now, debug server will get the file path like "/user/username/foo.lua" not "/Users/Username/foo.lua", and cause ZeroBraneStudio fail to begin debug.

I think "iscasepreserving" should be false on OS X.

It was introduced to address the opposite case, when you do require 'FOO' on a case-insensitive partition and the Lua interpreter loads the file fine, but you can't debug it properly as the breakpoints are set for foo.lua and not FOO.lua.

There doesn't seem to be a good way to detect the partition type (short of using diskutil), but I may be able to test it by opening a location of a known file to see if it is case sensitive or not. I might be able to fix this shortly. Thank you for the suggestion.

" test it by opening a location of a known file to see if it is case sensitive or not."
I thinks it is good enough.

Agree, but it's a bit more complex as I can't just check ahead of time (for example using /Applications or /Library) as you may be running on a case-sensitive partition and I need to check specifically for the files you are using. Still should be doable...

@deftsp, can you try with the following version? I did some limited testing and it seems to work for me. I'd appreciate if you could test it on case-sensitive and case-insensitive partitions.

diff --git a/src/mobdebug.lua b/src/mobdebug.lua
index 0debb86..7e4c464 100644
--- a/src/mobdebug.lua
+++ b/src/mobdebug.lua
@@ -1,12 +1,12 @@
 --
--- MobDebug 0.543
+-- MobDebug 0.544
 -- Copyright 2011-13 Paul Kulchenko
 -- Based on RemDebug 1.0 Copyright Kepler Project 2005
 --

 local mobdebug = {
   _NAME = "mobdebug",
-  _VERSION = 0.543,
+  _VERSION = 0.544,
   _COPYRIGHT = "Paul Kulchenko",
   _DESCRIPTION = "Mobile Remote Debugger for the Lua programming language",
   port = os and os.getenv and os.getenv("MOBDEBUG_PORT") or 8172,
@@ -61,11 +61,12 @@ end
 -- check for OS and convert file names to lower case on windows
 -- (its file system is case insensitive, but case preserving), as setting a
 -- breakpoint on x:\Foo.lua will not work if the file was loaded as X:\foo.lua.
--- OSX and Windows behave the same way (case insensitive, but case preserving)
-local iscasepreserving = os and os.getenv and (os.getenv('WINDIR')
-  or (os.getenv('OS') or ''):match('[Ww]indows')
-  or os.getenv('DYLD_LIBRARY_PATH'))
-  or not io.open("/proc")
+-- OSX and Windows behave the same way (case insensitive, but case preserving).
+-- It's possible to have a case-sensitive partition in OSX, which is checked
+-- separately when a new basedir is set (by default OSX is case-preserving).
+local win = os and os.getenv and (os.getenv('WINDIR') or (os.getenv('OS') or ''):match('[Ww]indows')) and true or false
+local mac = not win and (os and os.getenv and os.getenv('DYLD_LIBRARY_PATH') or not io.open("/proc")) and true or false
+local iscasepreserving = win or mac

 -- turn jit off based on Mike Pall's comment in this discussion:
 -- http://www.freelists.org/post/luajit/Debug-hooks-and-JIT,2
@@ -771,6 +772,10 @@ local function debugger_loop(sev, svars, sfile, sline)
     elseif command == "BASEDIR" then
       local _, _, dir = string.find(line, "^[A-Z]+%s+(.+)%s*$")
       if dir then
+        if mac then
+          -- check if this particular partition is case preserving
+          iscasepreserving = io.open(dir:lower()) and io.open(dir:upper()) and true or false
+        end
         basedir = iscasepreserving and string.lower(dir) or dir
         -- reset cached source as it may change with basedir
         lastsource = nil

@pkulchenko I have test it on OS X running at case-sensitive partition. Still can not get the right path.

local win = os and os.getenv and (os.getenv('WINDIR') or (os.getenv('OS') or ''):match('[Ww]indows')) and true or false

return false

local mac = not win and (os and os.getenv and os.getenv('DYLD_LIBRARY_PATH') or not io.open("/proc")) and true or false

return true

iscasepreserving is true, and the path will still be lowercased.

I pull a quick fix.

Howerver, I don't think it is a good idea to lower case the path. It's better to return the raw path as what OS gives.

You mentitioned SETB will not work on case-insensitive OS, if given wrong filename. I think check the path exist or not, when SETB execute is better.

iscasepreserving is true, and the path will still be lowercased.

Right, but there is one more change that takes care of that:

@@ -771,6 +772,10 @@ local function debugger_loop(sev, svars, sfile, sline)
     elseif command == "BASEDIR" then
       local _, _, dir = string.find(line, "^[A-Z]+%s+(.+)%s*$")
       if dir then
+        if mac then
+          -- check if this particular partition is case preserving
+          iscasepreserving = io.open(dir:lower()) and io.open(dir:upper()) and true or false
+        end
         basedir = iscasepreserving and string.lower(dir) or dir
         -- reset cached source as it may change with basedir
         lastsource = nil

Have you tried running with this version of mobdebug? It should work in the case-preserving test as far as I can tell.

You mentitioned SETB will not work on case-insensitive OS, if given wrong filename. I think check the path exist or not, when SETB execute is better.

This doesn't work because both foo and FOO paths exist. But when you set breakpoint on foo and the interpreter reports FOO, the two will not match. The problem is not with checking that the files exist (they are), but with quick checks for breakpoint matches.

@pkulchenko I'm sure I tested with your whole new version.

lua -e "require('mobdebug').listen()"

respone Paused at file /users/foo/bar.lua (lowercased path). setb works for both origin file path and lowercased file path.

However, ZeroBrandStudio Output show *Can't find file '/users/foo/bar.lua" and kill my Lua app.

I think client should send raw file path to debugger server, not lowercased one.

BTW, I noticed you used io.open to test file exist without close it. I'm new to Lua, I think it's better to close it explicitly not depend on GC.

local function is_file_exists(name)
   local f = io.open(name,"r")
   if f ~= nil then io.close(f) return true else return false end
end

Good point on the closing file, but I think it's correctly taken care of when the variable goes out of scope; I'll double check.

I think client should send raw file path to debugger server, not lowercased one.

As I said, it's not going to work. When you do require 'FOO', the interpreter returns the path as module/path/FOO.lua. If you set a breakpoint at module/path/foo.lua, the breakpoint won't fire as the filenames don't match.

I might have misunderstood something about your setup. You run ZBS on one partition while your application is running on another partition. Which of the two partitions are case-sensitive and which is not? Or are you running both on the same case-sensitive partition?

However, ZeroBrandStudio Output show *Can't find file '/users/foo/bar.lua" and kill my Lua app.

The only configuration that may trigger this error I can think of is when you run the application on a case-insensitive system (so it changes the path to lowercase), but ZBS itself is running on a case-sensitive partition, which distinguishes between /Users and /users, so the returned filename won't match. I may need to doublecheck the logic, but it should work even in that case as it's supposed to work when you debug an application running on Windows from OSX computer and vise versa.

Can you describe your setup in more detail and show the messages in the Output window when you start debugging? Do you see Mapped remote request for '...' to '...'. message?

I do see how the existing logic may fail: if you have a file name with uppercase letters on a non-case sensitive filesystem, while ZBS is running on a case-sensitive system/partition. The filename gets converted to lowercase, which is sent to ZBS; ZBS takes the filename "as is", but since the system is case sensitive, it fails to open the file.

I managed to reproduce this, but only when I start debugging outside of ZBS; I couldn't make it fail when the debugging is started from ZBS.

Let me think about a solution as what I offered earlier is not going to work; unfortunately your solution is not going to work either.

Both ZBS and My application are in case-sensitive partition. I have replace your new version to ZBS and my project.
My Output window

Debugger server started at XXX.local:8172.
Can't find file '/users/foo/bar/myapp.lua' in the current project to activate for debugging. Update the project or open the file in the editor before debugging.
Debugging session completed (traced 0 instructions).

I have opened myapp.lua in ZBS and click Menu -> Project Directory -> Set From Current File

This particular case can be addressed with this change (similar to what you've done):

local iscasepreserving = win or (mac and io.open('/library') and true or false)

This doesn't solve the problem of cross-partition debugging, but maybe it's a much more rare case. Please let me know if this fixes the issue. I'll doublecheck on file handles being properly closed when going out of scope.

It works. In fact, I have only case-sensitive env.

@deftsp, I pushed the changes we discussed earlier. Thank you for the feedback and the suggested fix!