@@ -35,86 +35,55 @@ local function _(msgid)
35
35
return gettext .dgettext (" dtutils.file" , msgid )
36
36
end
37
37
38
- dtutils_file . libdoc . functions [ " is_dir " ] = {
39
- Name = [[ is_dir ]] ,
40
- Synopsis = [[ check if a path is a directory ]] ,
41
- Usage = [[ local df = require "lib/dtutils.file"
38
+ --[[
39
+ local function to run a test command on windows and return a true if it succeeds
40
+ instead of returning true if it runs
41
+ ]]
42
42
43
- local result = df.is_dir(path)
44
- path - string - the path to check]] ,
45
- Description = [[ is_dir checks a path to see if it is a directory]] ,
46
- Return_Value = [[ result - boolean - true if path is a directory, nil if not]] ,
47
- Limitations = [[ ]] ,
48
- Example = [[ ]] ,
49
- See_Also = [[ ]] ,
50
- Reference = [[ ]] ,
51
- License = [[ ]] ,
52
- Copyright = [[ ]] ,
53
- }
54
-
55
- function dtutils_file .is_dir (path )
56
- local cmd = nil
57
-
58
- if dt .configuration .running_os == " windows" then
59
- cmd = " if exist " .. ds .sanitize (path .. " \\ *" )
43
+ local function _win_os_execute (cmd )
44
+ local result = nil
45
+ local p = io.popen (cmd )
46
+ local output = p :read (" *a" )
47
+ p :close ()
48
+ if string.match (output , " true" ) then
49
+ result = true
60
50
else
61
- cmd = " test -d " .. ds . sanitize ( path )
51
+ result = false
62
52
end
63
-
64
- return os.execute (cmd )
53
+ return result
65
54
end
66
55
67
- dtutils_file .libdoc .functions [" is_file" ] = {
68
- Name = [[ is_file]] ,
69
- Synopsis = [[ check if a path is a file]] ,
70
- Usage = [[ local df = require "lib/dtutils.file"
56
+ --[[
57
+ local function to determine if a path name is a windows executable
58
+ ]]
71
59
72
- local result = df.is_file(path)
73
- path - string - the path to check]] ,
74
- Description = [[ is_file checks a path to see if it is a file]] ,
75
- Return_Value = [[ result - boolean - true if path is a file, nil if not]] ,
76
- Limitations = [[ ]] ,
77
- Example = [[ ]] ,
78
- See_Also = [[ ]] ,
79
- Reference = [[ ]] ,
80
- License = [[ ]] ,
81
- Copyright = [[ ]] ,
82
- }
83
-
84
- function dtutils_file .is_file (path )
85
- local cmd = nil
60
+ local function _is_windows_executable (path )
86
61
local result = false
87
-
88
- if dt .configuration .running_os == " windows" then
89
- if not dtutils_file .is_dir (path ) then
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
62
+ if dtutils_file .test_file (path , " f" ) then
63
+ if string.match (path , " .exe$" ) or string.match (path , " .EXE$" ) or
64
+ string.match (path , " .com$" ) or string.match (path , " .COM$" ) or
65
+ string.match (path , " .bat$" ) or string.match (path , " .BAT$" ) or
66
+ string.match (path , " .cmd$" ) or string.match (path , " .CMD$" ) then
95
67
result = true
96
- else
97
- result = false
98
- end
99
- else
100
- return false
101
68
end
102
- else
103
- result = os.execute (" test -f " .. ds .sanitize (path ))
104
69
end
105
-
106
70
return result
107
71
end
108
72
109
- dtutils_file .libdoc .functions [" is_executable " ] = {
110
- Name = [[ is_executable ]] ,
111
- Synopsis = [[ check if a path is a executable ]] ,
73
+ dtutils_file .libdoc .functions [" test_file " ] = {
74
+ Name = [[ test_file ]] ,
75
+ Synopsis = [[ test a file to see what it is ]] ,
112
76
Usage = [[ local df = require "lib/dtutils.file"
113
77
114
- local result = df.is_executable(path)
115
- path - string - the path to check]] ,
116
- Description = [[ is_executable checks a path to see if it is an executable]] ,
117
- Return_Value = [[ result - boolean - true if path is an executable, nil if not]] ,
78
+ local result = df.test_file(path, test)
79
+ path - string - the path to check
80
+ test - one of d, e, f, x where
81
+ d - directory
82
+ e - exists
83
+ f - file
84
+ x - executable]] ,
85
+ Description = [[ test_file checks a path to see if it is a directory]] ,
86
+ Return_Value = [[ result - boolean - true if path is a directory, nil if not]] ,
118
87
Limitations = [[ ]] ,
119
88
Example = [[ ]] ,
120
89
See_Also = [[ ]] ,
@@ -123,54 +92,61 @@ dtutils_file.libdoc.functions["is_executable"] = {
123
92
Copyright = [[ ]] ,
124
93
}
125
94
126
- local function _is_windows_executable (path )
127
- local result = nil
128
- dt .print_log (" checking " .. path )
95
+ function dtutils_file .test_file (path , test )
96
+ local cmd = " test -"
97
+ local engine = os.execute
98
+ local cmdstring = " "
129
99
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
134
- result = true
100
+ if dt .configuration .running_os == " windows" then
101
+ cmd = " if exist "
102
+ engine = _win_os_execute
135
103
end
136
- return result
137
- end
138
-
139
- function dtutils_file .is_executable (path )
140
104
141
- local result = nil
142
-
143
- if dt .configuration .running_os == " windows" then
144
- if _is_windows_executable (path ) then
145
- result = true
105
+ if test == " d" then
106
+ -- test if directory
107
+ if dt .configuration .running_os == " windows" then
108
+ cmdstring = cmd .. dtutils_file .sanitize_filename (path .. " \\ *" ) .. " echo true"
109
+ else
110
+ cmdstring = cmd .. test .. " " .. dtutils_file .sanitize_filename (path )
111
+ end
112
+ elseif test == " e" then
113
+ -- test exists
114
+ if dt .configuration .running_os == " windows" then
115
+ cmdstring = cmd .. dtutils_file .sanitize_filename (path ) .. " echo true"
116
+ else
117
+ cmdstring = cmd .. test .. " " .. dtutils_file .sanitize_filename (path )
118
+ end
119
+ elseif test == " f" then
120
+ -- test if file
121
+ if dt .configuration .running_os == " windows" then
122
+ if not dtutils_file .test_file (path , " d" ) then -- make sure it's not a directory
123
+ cmdstring = cmd .. dtutils_file .sanitize_filename (path ) .. " echo true"
124
+ else
125
+ return false
126
+ end
127
+ else
128
+ cmdstring = cmd .. test .. " " .. dtutils_file .sanitize_filename (path )
129
+ end
130
+ elseif test == " x" then
131
+ -- test executable
132
+ if dt .configuration .running_os == " windows" then
133
+ return _is_windows_executable (path )
134
+ else
135
+ cmdstring = cmd .. test .. " " .. dtutils_file .sanitize_filename (path )
146
136
end
147
137
else
148
- result = os.execute (" test -x " .. ds .sanitize (path ))
138
+ dt .print_error (" [test_file] unknown test " .. test )
139
+ return false
149
140
end
150
- return result
151
- end
152
141
153
- dtutils_file .libdoc .functions [" check_if_bin_exists" ] = {
154
- Name = [[ check_if_bin_exists]] ,
155
- Synopsis = [[ check if an executable exists]] ,
156
- Usage = [[ local df = require "lib/dtutils.file"
142
+ return engine (cmdstring )
143
+ end
157
144
158
- local result = df.check_if_bin_exists(bin)
159
- bin - string - the binary to check for]] ,
160
- Description = [[ check_if_bin_exists checks to see if the specified binary exists.
161
- check_if_bin_exists first checks to see if a preference for the binary has been
162
- registered and uses that if found. The presence of the file is verified, then
163
- quoted and returned. If no preference is specified and the operating system is
164
- linux then the which command is used to check for a binary in the path. If found
165
- that path is returned. If no binary is found, false is returned.]] ,
166
- Return_Value = [[ result - string - the sanitized path of the binary, false if not found]] ,
167
- Limitations = [[ ]] ,
168
- Example = [[ ]] ,
169
- See_Also = [[ ]] ,
170
- Reference = [[ ]] ,
171
- License = [[ ]] ,
172
- Copyright = [[ ]] ,
173
- }
145
+ local function _case_insensitive_pattern (pattern )
146
+ return pattern :gsub (" (.)" , function (letter )
147
+ return string.format (" [%s$s]" , letter :lower (), letter :upper ())
148
+ end )
149
+ end
174
150
175
151
local function _search_for_bin_windows (bin )
176
152
local result = false
@@ -185,9 +161,11 @@ local function _search_for_bin_windows(bin)
185
161
local output = p :read (" *a" )
186
162
p :close ()
187
163
local lines = du .split (output , " \n " )
164
+ local cibin = _case_insensitive_pattern (bin )
188
165
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
166
+ if string.match (line , cibin ) then
167
+ dt .print_log (" found win search match " .. line )
168
+ if dtutils_file .test_file (line , " f" ) and dtutils_file .test_file (line , " x" ) then
191
169
dtutils_file .set_executable_path_preference (bin , line ) -- save it so we don't have to search again
192
170
return line
193
171
end
@@ -204,7 +182,7 @@ local function _search_for_bin_nix(bin)
204
182
p :close ()
205
183
if string.len (output ) > 0 then
206
184
local spath = dtutils_file .sanitize_filename (output :sub (1 ,- 2 ))
207
- if dtutils_file .is_file (spath ) and dtutils_file .is_executable (spath ) then
185
+ if dtutils_file .test_file (spath , " f " ) and dtutils_file .test_file (spath , " x " ) then
208
186
result = spath
209
187
end
210
188
end
@@ -230,7 +208,7 @@ local function _search_for_bin_macos(bin)
230
208
231
209
for _ ,line in ipairs (lines ) do
232
210
local spath = dtutils_file .sanitize_filename (line :sub (1 , - 2 ))
233
- if dtutils_file .is_executable (spath ) then
211
+ if dtutils_file .test_file (spath , " x " ) then
234
212
dtutils_file .set_executable_path_preference (bin , spath )
235
213
result = spath
236
214
end
@@ -245,6 +223,9 @@ local function _search_for_bin(bin)
245
223
246
224
if dt .configuration .running_os == " windows" then
247
225
result = _search_for_bin_windows (bin )
226
+ if result then
227
+ result = dtutils_file .sanitize_filename (result )
228
+ end
248
229
elseif dt .configuration .running_os == " macos" then
249
230
result = _search_for_bin_macos (bin )
250
231
else
@@ -279,13 +260,13 @@ local function _check_path_for_bin(bin)
279
260
else
280
261
path = dtutils_file .get_executable_path_preference (bin )
281
262
-- reset path preference is the returned preference is a directory
282
- if dtutils_file .is_dir (path ) then
263
+ if dtutils_file .test_file (path , " d " ) then
283
264
dtutils_file .set_executable_path_preference (bin , " " )
284
265
path = nil
285
266
end
286
267
end
287
268
288
- if path and dtutils_file .is_dir (path ) then
269
+ if path and dtutils_file .test_file (path , " d " ) then
289
270
path = nil
290
271
end
291
272
@@ -294,23 +275,77 @@ local function _check_path_for_bin(bin)
294
275
end
295
276
296
277
if path and not result then
297
- if dtutils_file .is_executable (path ) then
278
+ if dtutils_file .test_file (path , " x " ) then
298
279
result = dtutils_file .sanitize_filename (path )
299
280
end
300
281
end
301
282
302
283
return result
303
284
end
304
285
286
+ local function _old_check_if_bin_exists (bin ) -- only run on windows if preference checked
287
+ local result = false
288
+ local path = nil
289
+
290
+ if string.match (bin , " \\ " ) then
291
+ path = bin
292
+ else
293
+ path = dtutils_file .get_executable_path_preference (bin )
294
+ end
295
+
296
+ if string.len (path ) > 0 then
297
+ if dtutils_file .check_if_file_exists (path ) then
298
+ if (string.match (path , " .exe$" ) or string.match (path , " .EXE$" )) then
299
+ result = dtutils_file .sanitize_filename (path )
300
+ end
301
+ end
302
+ end
303
+ return result
304
+ end
305
+
306
+ dtutils_file .libdoc .functions [" check_if_bin_exists" ] = {
307
+ Name = [[ check_if_bin_exists]] ,
308
+ Synopsis = [[ check if an executable exists]] ,
309
+ Usage = [[ local df = require "lib/dtutils.file"
310
+
311
+ local result = df.check_if_bin_exists(bin)
312
+ bin - string - the binary to check for]] ,
313
+ Description = [[ check_if_bin_exists checks to see if the specified binary exists.
314
+ check_if_bin_exists first checks to see if a preference for the binary has been
315
+ registered and uses that if found, after it's verified to be an executable and
316
+ exist. If no preference exissts, the user's path is checked for the executable.
317
+ If the executable is not found in the users path, then a search of the operating
318
+ system is conducted to see if the executable can be found.
319
+
320
+ If an executalble is found, it's verified to exist and be an executable. Once
321
+ the executable is verified, the path is saved as a preference to speed up
322
+ subsequent checks. The executable path is sanitized and returned.
323
+
324
+ If no executable is found, false is returned.]] ,
325
+ Return_Value = [[ result - string - the sanitized path of the binary, false if not found]] ,
326
+ Limitations = [[ If more than one executable that satisfies the search results is found, the
327
+ wrong one may be returned. If the wrong value is returned, the user can still specify the
328
+ correct execuable using tools/executable_manager.]] ,
329
+ Example = [[ ]] ,
330
+ See_Also = [[ executable_manager]] ,
331
+ Reference = [[ ]] ,
332
+ License = [[ ]] ,
333
+ Copyright = [[ ]] ,
334
+ }
335
+
305
336
function dtutils_file .check_if_bin_exists (bin )
306
337
local result = false
307
338
308
- result = _check_path_for_bin (bin )
339
+ if dt .configuration .running_os == " windows" and dt .preferences .read (" dtutils.file" , " use_old_check_if_bin_exists" , " bool" ) then
340
+ result = _old_check_if_bin_exists (bin )
341
+ else
342
+
343
+ result = _check_path_for_bin (bin )
309
344
310
- if not result then
311
- result = _search_for_bin (bin )
345
+ if not result then
346
+ result = _search_for_bin (bin )
347
+ end
312
348
end
313
-
314
349
return result
315
350
end
316
351
@@ -856,5 +891,21 @@ function dtutils_file.rmdir(path)
856
891
return dsys .external_command (rm_cmd .. " " .. path )
857
892
end
858
893
894
+ --[[
895
+ The new check_if_bin_exists() does multiple calls to the operating system to check
896
+ if the file exists and is an executable. On windows, each call to the operating system
897
+ causes a window to open in order to run the command, then the window closes when the
898
+ command exits. If the user gets annoyed by the "flickering windows", then they can
899
+ enable this preference to use the old check_if_bin_exists() that relys on the
900
+ executable path preferences and doesn't do as many checks.
901
+ ]]
902
+
903
+ if dt .configuration .running_os == " windows" then
904
+ dt .preferences .register (" dtutils.file" , " use_old_check_if_bin_exists" , " bool" ,
905
+ " lua scripts use old check_if_bin_exists()" ,
906
+ " lessen flickering windows effect when scripts run" ,
907
+ false )
908
+ end
909
+
859
910
return dtutils_file
860
911
0 commit comments