Skip to content

Commit 7790c97

Browse files
committed
Separated check_if_bin_exists() into 2 functions, one to check the returned
executable_path variable and another to search for the binary if it wasn't detected. All results are checked to ensure they exist, are a file, and are executable. This fixes the situation where a directory gets stored as an executable path. Search functions are operating system specific. Executable paths are saved for MacOS and Windows to make for shorter searches in the future.
1 parent 1d5192a commit 7790c97

File tree

1 file changed

+132
-49
lines changed

1 file changed

+132
-49
lines changed

lib/dtutils/file.lua

Lines changed: 132 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,27 @@ dtutils_file.libdoc.functions["is_file"] = {
8383

8484
function dtutils_file.is_file(path)
8585
local cmd = nil
86+
local result = false
8687

8788
if dt.configuration.running_os == "windows" then
8889
if not dtutils_file.is_dir(path) then
89-
cmd = "if exist " .. ds.sanitize(path)
90+
cmd = "if exist " .. ds.sanitize(path) .. " echo true"
91+
local p = io.popen(cmd)
92+
output = p:read("*a")
93+
p:close()
94+
if string.match(output, "true") then
95+
result = true
96+
else
97+
result = false
98+
end
9099
else
91-
return nil
100+
return false
92101
end
93102
else
94-
cmd = "test -f " .. ds.sanitize(path)
103+
result = os.execute("test -f " .. ds.sanitize(path))
95104
end
96105

97-
return os.execute(cmd)
106+
return result
98107
end
99108

100109
dtutils_file.libdoc.functions["is_executable"] = {
@@ -116,17 +125,17 @@ dtutils_file.libdoc.functions["is_executable"] = {
116125

117126
local function _is_windows_executable(path)
118127
local result = nil
128+
dt.print_log("checking " .. path)
119129

120-
if (string.match(path, ".exe$") or string.match(path, ".EXE$")) or
121-
(string.match(path, ".com$") or string.match(path, ".COM$")) or
122-
(string.match(path, ".bat$") or string.match(path, ".BAT$")) or
123-
(string.match(path, ".cmd$") or string.match(path, ".CMD$")) then
130+
if string.match(path, ".exe$") or string.match(path, ".EXE$") or
131+
string.match(path, ".com$") or string.match(path, ".COM$") or
132+
string.match(path, ".bat$") or string.match(path, ".BAT$") or
133+
string.match(path, ".cmd$") or string.match(path, ".CMD$") then
124134
result = true
125135
end
126136
return result
127137
end
128138

129-
130139
function dtutils_file.is_executable(path)
131140

132141
local result = nil
@@ -163,73 +172,146 @@ dtutils_file.libdoc.functions["check_if_bin_exists"] = {
163172
Copyright = [[]],
164173
}
165174

166-
local function _check_if_bin_exists_windows(bin)
175+
local function _search_for_bin_windows(bin)
167176
local result = false
168-
local path = nil
177+
-- use where on path
178+
-- use where on program files
179+
-- use where on program files (x86)
180+
local args = {"", '/R "C:\\Program Files"', '/R "C:\\Program Files (x86)"'}
181+
182+
for _,arg in ipairs(args) do
183+
local cmd = "where " .. arg .. " " .. ds.sanitize(bin)
184+
local p = io.popen(cmd)
185+
local output = p:read("*a")
186+
p:close()
187+
local lines = du.split(output, "\n")
188+
for _,line in ipairs(lines) do
189+
if string.match(line, bin) then
190+
if dtutils_file.is_file(line) and dtutils_file.is_executable(line) then
191+
dtutils_file.set_executable_path_preference(bin, line) -- save it so we don't have to search again
192+
return line
193+
end
194+
end
195+
end
196+
end
197+
return result
198+
end
169199

170-
if string.match(bin, "\\") then
171-
path = bin
172-
else
173-
path = dtutils_file.get_executable_path_preference(bin)
200+
local function _search_for_bin_nix(bin)
201+
local result = false
202+
local p = io.popen("which " .. bin)
203+
local output = p:read("*a")
204+
p:close()
205+
if string.len(output) > 0 then
206+
local spath = dtutils_file.sanitize_filename(output:sub(1,-2))
207+
if dtutils_file.is_file(spath) and dtutils_file.is_executable(spath) then
208+
result = spath
209+
end
174210
end
211+
return result
212+
end
175213

214+
local function _search_for_bin_macos(bin)
215+
local result = false
216+
217+
result = _search_for_bin_nix(bin)
176218

177-
if dtutils_file.check_if_file_exists(path) then
178-
if dtutils_file.is-executable(path) then
179-
result = dtutils_file.sanitize_filename(path)
219+
if not result then
220+
local search_start = "/Applications"
221+
222+
if dtutils_file.check_if_file_exists("/Applications/" .. bin .. ".app") then
223+
search_start = "/Applications/" .. bin .. ".app"
224+
end
225+
226+
local p = io.popen("find " .. search_start .. " -type f -name " .. bin .. " -print")
227+
local output = p:read("*a")
228+
p:close()
229+
local lines = du.split(output, "\n")
230+
231+
for _,line in ipairs(lines) do
232+
local spath = dtutils_file.sanitize_filename(line:sub(1, -2))
233+
if dtutils_file.is_executable(spath) then
234+
dtutils_file.set_executable_path_preference(bin, spath)
235+
result = spath
236+
end
180237
end
181238
end
239+
182240
return result
183241
end
184242

185-
-- check_if_bin_exists for unix like systems (linux, macos)
186-
local function _check_if_bin_exists_nix(bin)
243+
local function _search_for_bin(bin)
187244
local result = false
188-
local path = nil
189245

190-
if string.match(bin, "/") then
191-
path = bin
246+
if dt.configuration.running_os == "windows" then
247+
result = _search_for_bin_windows(bin)
248+
elseif dt.configuration.running_os == "macos" then
249+
result = _search_for_bin_macos(bin)
192250
else
193-
path = dtutils_file.get_executable_path_preference(bin)
251+
result = _search_for_bin_nix(bin)
194252
end
195253

196-
if path then dt.print_log("path is " .. path) end
254+
return result
255+
end
256+
257+
local function _check_path_for_wine_bin(path)
258+
local result = false
197259

198260
if string.len(path) > 0 then
199261
-- check for windows executable to run under wine
200-
if _is-windows_executable(path) then
201-
if dtutils_file.check_if_file_exists(path) then
202-
result = dtutils_file.sanitize_filename(path)
203-
end
204-
else
262+
if _is_windows_executable(path) then
205263
if dtutils_file.check_if_file_exists(path) then
206-
if dtutils_file.is_file(path) and dtutils_file.is_executable(path) then
207-
result = ds.sanitize(path)
208-
end
264+
result = "wine " .. dtutils_file.sanitize_filename(path)
209265
end
210266
end
211267
end
212-
if not result then
213-
local p = io.popen("which " .. bin)
214-
local output = p:read("*a")
215-
p:close()
216-
if string.len(output) > 0 then
268+
return result
269+
end
217270

218-
local spath = dtutils_file.sanitize_filename(output:sub(1,-2))
219-
if dtutils_file.is_file(spath) and dtutils_file.is_executable(spath) then
220-
result = spath
221-
end
271+
local function _check_path_for_bin(bin)
272+
local result = false
273+
local path = nil
274+
275+
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
276+
277+
if string.match(bin, PS) then
278+
path = bin
279+
else
280+
path = dtutils_file.get_executable_path_preference(bin)
281+
-- reset path preference is the returned preference is a directory
282+
if dtutils_file.is_dir(path) then
283+
dtutils_file.set_executable_path_preference(bin, "")
284+
path = nil
285+
end
286+
end
287+
288+
if path and dtutils_file.is_dir(path) then
289+
path = nil
290+
end
291+
292+
if path and dt.configuration.running_os ~= "windows" then
293+
result = _check_path_for_wine_bin(path)
294+
end
295+
296+
if path and not result then
297+
if dtutils_file.is_executable(path) then
298+
result = dtutils_file.sanitize_filename(path)
222299
end
223300
end
301+
224302
return result
225303
end
226304

227305
function dtutils_file.check_if_bin_exists(bin)
228-
if dt.configuration.running_os == "windows" then
229-
return _check_if_bin_exists_windows(bin)
230-
else
231-
return _check_if_bin_exists_nix(bin)
306+
local result = false
307+
308+
result = _check_path_for_bin(bin)
309+
310+
if not result then
311+
result = _search_for_bin(bin)
232312
end
313+
314+
return result
233315
end
234316

235317
dtutils_file.libdoc.functions["split_filepath"] = {
@@ -688,10 +770,11 @@ function dtutils_file.executable_path_widget(executables)
688770
is_directory = false,
689771
changed_callback = function(self)
690772
if dtutils_file.check_if_bin_exists(self.value) then
691-
dtutils_file.set_executable_path_preference(executable, dtutils_file.check_if_bin_exists(self.value))
773+
dtutils_file.set_executable_path_preference(executable, self.value)
692774
end
693-
end}
694-
)
775+
end
776+
}
777+
)
695778
end
696779
local box = dt.new_widget("box"){
697780
orientation = "vertical",

0 commit comments

Comments
 (0)