diff --git a/src/base/_foundation.lua b/src/base/_foundation.lua index 1a700e0cf2..68a62b6fbb 100644 --- a/src/base/_foundation.lua +++ b/src/base/_foundation.lua @@ -227,8 +227,22 @@ table.insert(filenames, path.getabsolute(fname, _SCRIPT_DIR)) end - local compiled_chunk - local res = os.locate(table.unpack(filenames)) + local compiled_chunk = nil + local res = nil + + -- First try to find the file directly on file system. + for _, candidate in ipairs(filenames) do + if os.isfile(candidate) then + res = path.getabsolute(candidate) + break + end + end + + -- If that fails, try to find the file using the search paths. + if res == nil then + res = os.locate(table.unpack(filenames)) + end + if res == nil then local caller = filelineinfo(3) premake.error(caller .. ": Cannot find neither " .. table.implode(filenames, "", "", " nor ")) diff --git a/tests/base/test_include.lua b/tests/base/test_include.lua index d88466d7d3..0208e658fe 100644 --- a/tests/base/test_include.lua +++ b/tests/base/test_include.lua @@ -65,3 +65,54 @@ includeexternal (_TESTS_DIR .. "/folder/premake5.lua") test.isequal("okokok", p.captured()) end + + +-- +-- Tests for local-first search priority (fix for issue #1783): +-- Local files must be found before identically-named files in premake.path. +-- + + -- Helper: run fn with CWD and premake.path temporarily overridden. + local function withLocalPriority(cwd, searchPath, fn) + local savedPath = premake.path + local savedCwd = os.getcwd() + premake.path = searchPath + os.chdir(cwd) + local ok, err = pcall(fn) + os.chdir(savedCwd) + premake.path = savedPath + if not ok then error(err, 2) end + end + + -- A local "name/premake5.lua" must be preferred over a plain file named + -- "name" that lives only in a premake.path search directory. + function suite.findProjectScript_prefersLocalSubdir_overPathDecoy() + local folder = _TESTS_DIR .. "/folder" + withLocalPriority(folder, folder .. "/subfolder", function() + local res, _ = premake.findProjectScript("shadowlib") + test.isequal( + path.normalize(folder .. "/shadowlib/premake5.lua"), + path.normalize(res)) + end) + end + + -- A local "name.lua" must be preferred over a plain file named "name" + -- (no extension) that lives only in a premake.path search directory. + function suite.findProjectScript_prefersLocalLuaFile_overPathDecoy() + local folder = _TESTS_DIR .. "/folder" + withLocalPriority(folder, folder .. "/subfolder", function() + local res, _ = premake.findProjectScript("ok") + test.isequal( + path.normalize(folder .. "/ok.lua"), + path.normalize(res)) + end) + end + + -- Verify the full include() call for the subdir-priority scenario. + function suite.include_prefersLocalSubdir_overPathDecoy() + local folder = _TESTS_DIR .. "/folder" + withLocalPriority(folder, folder .. "/subfolder", function() + include("shadowlib") + end) + test.isequal("shadowlocal", p.captured()) + end diff --git a/tests/folder/shadowlib/premake5.lua b/tests/folder/shadowlib/premake5.lua new file mode 100644 index 0000000000..eb89db8093 --- /dev/null +++ b/tests/folder/shadowlib/premake5.lua @@ -0,0 +1 @@ +premake.out("shadowlocal") diff --git a/tests/folder/subfolder/ok b/tests/folder/subfolder/ok new file mode 100644 index 0000000000..e940e7e951 --- /dev/null +++ b/tests/folder/subfolder/ok @@ -0,0 +1 @@ +-- decoy: this file should NOT be loaded by include("ok") when a local ok.lua exists diff --git a/tests/folder/subfolder/shadowlib b/tests/folder/subfolder/shadowlib new file mode 100644 index 0000000000..6945e1bc53 --- /dev/null +++ b/tests/folder/subfolder/shadowlib @@ -0,0 +1 @@ +-- decoy: this file should NOT be loaded by include("shadowlib") when a local shadowlib/ directory exists diff --git a/website/docs/globals/include.md b/website/docs/globals/include.md index 34f31c89d3..aca4b53f98 100644 --- a/website/docs/globals/include.md +++ b/website/docs/globals/include.md @@ -6,7 +6,9 @@ include("path") ### Parameters ### -`path` is the file system path to a script file or a directory. If a directory is specified, Premake looks for a file named `premake5.lua` in that directory and runs it if found. +`path` is the file system path to a script file or a directory. If a directory is specified, Premake looks for a file named `premake5.lua` in that directory and runs it if found. If the `.lua` extension is omitted from the file name, Premake will also look for a file with that extension. + +See [Locating Scripts](Locating-Scripts.md) for more information about how script files are located. If the file or directory specified has already been included previously, the call is ignored. If you want to execute the same script multiple times, use Lua's [dofile()](http://www.lua.org/manual/5.1/manual.html#pdf-dofile) instead.