6 Commits

Author SHA1 Message Date
wpferguson
96ba075e86 Removed debugging statement 2020-12-22 22:00:41 -05:00
Bill Ferguson
e86a3a3236 [file.lua] removed debugging statement 2020-12-18 11:08:12 -05:00
Bill Ferguson
b41b2a1566 [file.lua] Added create_tmp_file() back in. 2020-11-30 21:51:55 -05:00
Bill Ferguson
b893383353 [file.lua] Added comments for local functions. Added more API
documentation for check_if_bin_exists.  Added save
           executable path preference to _search_for_nix_bin()
           so that we can save a little time on subsequent runs
           once an executable is found.
2020-11-30 21:06:57 -05:00
Bill Ferguson
ddcf3ed3f4 [file.lua] fixed line trimming in macos search for bin 2020-11-29 18:41:32 -05:00
Bill Ferguson
da05748393 [file.lua] combined the is_ functions into file_test() which allows
testing to see if a path exists, is a dir, is a file, or
	   is executable.  Added case insensitive search to the
           windows search for bin.
2020-11-29 18:00:47 -05:00

View File

@@ -35,14 +35,54 @@ local function _(msgid)
return gettext.dgettext("dtutils.file", msgid)
end
dtutils_file.libdoc.functions["is_dir"] = {
Name = [[is_dir]],
Synopsis = [[check if a path is a directory]],
--[[
local function to run a test command on windows and return a true if it succeeds
instead of returning true if it runs
]]
local function _win_os_execute(cmd)
local result = nil
local p = io.popen(cmd)
local output = p:read("*a")
p:close()
if string.match(output, "true") then
result = true
else
result = false
end
return result
end
--[[
local function to determine if a path name is a windows executable
]]
local function _is_windows_executable(path)
local result = false
if dtutils_file.test_file(path, "f") then
if string.match(path, ".exe$") or string.match(path, ".EXE$") or
string.match(path, ".com$") or string.match(path, ".COM$") or
string.match(path, ".bat$") or string.match(path, ".BAT$") or
string.match(path, ".cmd$") or string.match(path, ".CMD$") then
result = true
end
end
return result
end
dtutils_file.libdoc.functions["test_file"] = {
Name = [[test_file]],
Synopsis = [[test a file to see what it is]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.is_dir(path)
path - string - the path to check]],
Description = [[is_dir checks a path to see if it is a directory]],
local result = df.test_file(path, test)
path - string - the path to check
test - one of d, e, f, x where
d - directory
e - exists
f - file
x - executable]],
Description = [[test_file checks a path to see if it is a directory]],
Return_Value = [[result - boolean - true if path is a directory, nil if not]],
Limitations = [[]],
Example = [[]],
@@ -52,125 +92,71 @@ dtutils_file.libdoc.functions["is_dir"] = {
Copyright = [[]],
}
function dtutils_file.is_dir(path)
local cmd = nil
function dtutils_file.test_file(path, test)
local cmd = "test -"
local engine = os.execute
local cmdstring = ""
if dt.configuration.running_os == "windows" then
cmd = "if exist " .. ds.sanitize(path .. "\\*")
else
cmd = "test -d " .. ds.sanitize(path)
cmd = "if exist "
engine = _win_os_execute
end
return os.execute(cmd)
end
dtutils_file.libdoc.functions["is_file"] = {
Name = [[is_file]],
Synopsis = [[check if a path is a file]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.is_file(path)
path - string - the path to check]],
Description = [[is_file checks a path to see if it is a file]],
Return_Value = [[result - boolean - true if path is a file, nil if not]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.is_file(path)
local cmd = nil
local result = false
if test == "d" then
-- test if directory
if dt.configuration.running_os == "windows" then
if not dtutils_file.is_dir(path) then
cmd = "if exist " .. ds.sanitize(path) .. " echo true"
local p = io.popen(cmd)
output = p:read("*a")
p:close()
if string.match(output, "true") then
result = true
cmdstring = cmd .. dtutils_file.sanitize_filename(path .. "\\*") .. " echo true"
else
result = false
cmdstring = cmd .. test .. " " .. dtutils_file.sanitize_filename(path)
end
elseif test == "e" then
-- test exists
if dt.configuration.running_os == "windows" then
cmdstring = cmd .. dtutils_file.sanitize_filename(path) .. " echo true"
else
cmdstring = cmd .. test .. " " .. dtutils_file.sanitize_filename(path)
end
elseif test == "f" then
-- test if file
if dt.configuration.running_os == "windows" then
if not dtutils_file.test_file(path, "d") then -- make sure it's not a directory
cmdstring = cmd .. dtutils_file.sanitize_filename(path) .. " echo true"
else
return false
end
else
result = os.execute("test -f " .. ds.sanitize(path))
cmdstring = cmd .. test .. " " .. dtutils_file.sanitize_filename(path)
end
return result
end
dtutils_file.libdoc.functions["is_executable"] = {
Name = [[is_executable]],
Synopsis = [[check if a path is a executable]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.is_executable(path)
path - string - the path to check]],
Description = [[is_executable checks a path to see if it is an executable]],
Return_Value = [[result - boolean - true if path is an executable, nil if not]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
local function _is_windows_executable(path)
local result = nil
dt.print_log("checking " .. path)
if string.match(path, ".exe$") or string.match(path, ".EXE$") or
string.match(path, ".com$") or string.match(path, ".COM$") or
string.match(path, ".bat$") or string.match(path, ".BAT$") or
string.match(path, ".cmd$") or string.match(path, ".CMD$") then
result = true
end
return result
end
function dtutils_file.is_executable(path)
local result = nil
elseif test == "x" then
-- test executable
if dt.configuration.running_os == "windows" then
if _is_windows_executable(path) then
result = true
return _is_windows_executable(path)
else
cmdstring = cmd .. test .. " " .. dtutils_file.sanitize_filename(path)
end
else
result = os.execute("test -x " .. ds.sanitize(path))
end
return result
dt.print_error("[test_file] unknown test " .. test)
return false
end
dtutils_file.libdoc.functions["check_if_bin_exists"] = {
Name = [[check_if_bin_exists]],
Synopsis = [[check if an executable exists]],
Usage = [[local df = require "lib/dtutils.file"
return engine(cmdstring)
end
local result = df.check_if_bin_exists(bin)
bin - string - the binary to check for]],
Description = [[check_if_bin_exists checks to see if the specified binary exists.
check_if_bin_exists first checks to see if a preference for the binary has been
registered and uses that if found. The presence of the file is verified, then
quoted and returned. If no preference is specified and the operating system is
linux then the which command is used to check for a binary in the path. If found
that path is returned. If no binary is found, false is returned.]],
Return_Value = [[result - string - the sanitized path of the binary, false if not found]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
--[[
local function to return a case insensitive pattern for matching
i.e. gimp becomes [Gg][Ii][Mm][Pp] which should match any capitalization
of gimp.
]]
local function _case_insensitive_pattern(pattern)
return pattern:gsub("(.)", function(letter)
return string.format("[%s$s]", letter:lower(), letter:upper())
end)
end
--[[
local function to search windows for an executable
]]
local function _search_for_bin_windows(bin)
local result = false
@@ -185,9 +171,11 @@ local function _search_for_bin_windows(bin)
local output = p:read("*a")
p:close()
local lines = du.split(output, "\n")
local cibin = _case_insensitive_pattern(bin)
for _,line in ipairs(lines) do
if string.match(line, bin) then
if dtutils_file.is_file(line) and dtutils_file.is_executable(line) then
if string.match(line, cibin) then
dt.print_log("found win search match " .. line)
if dtutils_file.test_file(line, "f") and dtutils_file.test_file(line, "x") then
dtutils_file.set_executable_path_preference(bin, line) -- save it so we don't have to search again
return line
end
@@ -197,6 +185,10 @@ local function _search_for_bin_windows(bin)
return result
end
--[[
local function to search *nix systems for an executable
]]
local function _search_for_bin_nix(bin)
local result = false
local p = io.popen("which " .. bin)
@@ -204,17 +196,22 @@ local function _search_for_bin_nix(bin)
p:close()
if string.len(output) > 0 then
local spath = dtutils_file.sanitize_filename(output:sub(1, -2))
if dtutils_file.is_file(spath) and dtutils_file.is_executable(spath) then
if dtutils_file.test_file(spath, "f") and dtutils_file.test_file(spath, "x") then
dtutils_file.set_executable_path_preference(bin, spath)
result = spath
end
end
return result
end
--[[
local function to search macos systems for an executable
]]
local function _search_for_bin_macos(bin)
local result = false
result = _search_for_bin_nix(bin)
result = _search_for_bin_nix(bin) -- see if it's in the path
if not result then
local search_start = "/Applications"
@@ -229,9 +226,9 @@ local function _search_for_bin_macos(bin)
local lines = du.split(output, "\n")
for _,line in ipairs(lines) do
local spath = dtutils_file.sanitize_filename(line:sub(1, -2))
if dtutils_file.is_executable(spath) then
dtutils_file.set_executable_path_preference(bin, spath)
local spath = dtutils_file.sanitize_filename(line:sub(1, -1))
if dtutils_file.test_file(spath, "x") then
dtutils_file.set_executable_path_preference(bin, spath) -- save it so we don't have to search again
result = spath
end
end
@@ -240,11 +237,19 @@ local function _search_for_bin_macos(bin)
return result
end
--[[
local function to provide a generic search call that can be
split into operating system specific calls
]]
local function _search_for_bin(bin)
local result = false
if dt.configuration.running_os == "windows" then
result = _search_for_bin_windows(bin)
if result then
result = dtutils_file.sanitize_filename(result)
end
elseif dt.configuration.running_os == "macos" then
result = _search_for_bin_macos(bin)
else
@@ -254,6 +259,11 @@ local function _search_for_bin(bin)
return result
end
--[[
local function to check if an executable path is
a windows executable on linux or macos, thus requiring wine to run
]]
local function _check_path_for_wine_bin(path)
local result = false
@@ -268,6 +278,12 @@ local function _check_path_for_wine_bin(path)
return result
end
--[[
local function to check if an executable path is
a valid executable. Some generic checks are done before
system specific checks are done.
]]
local function _check_path_for_bin(bin)
local result = false
local path = nil
@@ -279,13 +295,13 @@ local function _check_path_for_bin(bin)
else
path = dtutils_file.get_executable_path_preference(bin)
-- reset path preference is the returned preference is a directory
if dtutils_file.is_dir(path) then
if dtutils_file.test_file(path, "d") then
dtutils_file.set_executable_path_preference(bin, "")
path = nil
end
end
if path and dtutils_file.is_dir(path) then
if path and dtutils_file.test_file(path, "d") then
path = nil
end
@@ -294,7 +310,7 @@ local function _check_path_for_bin(bin)
end
if path and not result then
if dtutils_file.is_executable(path) then
if dtutils_file.test_file(path, "x") then
result = dtutils_file.sanitize_filename(path)
end
end
@@ -302,15 +318,78 @@ local function _check_path_for_bin(bin)
return result
end
--[[
local function to the old check_if_bin_exists functionality
on windows in order to decrease the amount of windows being
created and destroyed by system calls.
]]
local function _old_check_if_bin_exists(bin) -- only run on windows if preference checked
local result = false
local path = nil
if string.match(bin, "\\") then
path = bin
else
path = dtutils_file.get_executable_path_preference(bin)
end
if string.len(path) > 0 then
if dtutils_file.check_if_file_exists(path) then
if (string.match(path, ".exe$") or string.match(path, ".EXE$")) then
result = dtutils_file.sanitize_filename(path)
end
end
end
return result
end
dtutils_file.libdoc.functions["check_if_bin_exists"] = {
Name = [[check_if_bin_exists]],
Synopsis = [[check if an executable exists]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.check_if_bin_exists(bin)
bin - string - the binary to check for]],
Description = [[check_if_bin_exists checks to see if the specified binary exists.
check_if_bin_exists first checks to see if a preference for the binary has been
registered and uses that if found, after it's verified to be an executable and
exist. If no preference exissts, the user's path is checked for the executable.
If the executable is not found in the users path, then a search of the operating
system is conducted to see if the executable can be found.
If an executalble is found, it's verified to exist and be an executable. Once
the executable is verified, the path is saved as a preference to speed up
subsequent checks. The executable path is sanitized and returned.
If no executable is found, false is returned.]],
Return_Value = [[result - string - the sanitized path of the binary, false if not found]],
Limitations = [[If more than one executable that satisfies the search results is found, the
wrong one may be returned. If the wrong value is returned, the user can still specify the
correct execuable using tools/executable_manager. Most packages are well behaved with the
notiable exception being GIMP on windows. Depending on the packager there are multiple
gimp executables, often with version numbers. In this case, the user needs to specify
the location of the correct executable using executable_manager.]],
Example = [[]],
See_Also = [[executable_manager]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.check_if_bin_exists(bin)
local result = false
if dt.configuration.running_os == "windows" and dt.preferences.read("dtutils.file", "use_old_check_if_bin_exists", "bool") then
result = _old_check_if_bin_exists(bin)
else
result = _check_path_for_bin(bin)
if not result then
result = _search_for_bin(bin)
end
end
return result
end
@@ -856,5 +935,53 @@ function dtutils_file.rmdir(path)
return dsys.external_command(rm_cmd.." "..path)
end
dtutils_file.libdoc.functions["create_tmp_file"] = {
Name = [[create_tmp_file]],
Synopsis = [[creates a temporary file]],
Usage = [[local df = require "lib/dtutils.file
local result = df.create_tmp_file()]],
Description = [[create_tmp_file can be used to create temporary files]],
Return_Value = [[result - string - path to the created temporary file.]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.create_tmp_file()
local tmp_file = os.tmpname()
if dt.configuration.running_os == "windows" then
tmp_file = dt.configuration.tmp_dir .. tmp_file -- windows os.tmpname() defaults to root directory
end
local f = io.open(tmp_file, "w")
if not f then
log.msg(log.error, string.format("Error writing to `%s`", tmp_file))
os.remove(tmp_file)
return nil
end
return tmp_file
end
--[[
The new check_if_bin_exists() does multiple calls to the operating system to check
if the file exists and is an executable. On windows, each call to the operating system
causes a window to open in order to run the command, then the window closes when the
command exits. If the user gets annoyed by the "flickering windows", then they can
enable this preference to use the old check_if_bin_exists() that relys on the
executable path preferences and doesn't do as many checks.
]]
if dt.configuration.running_os == "windows" then
dt.preferences.register("dtutils.file", "use_old_check_if_bin_exists", "bool",
"lua scripts use old check_if_bin_exists()",
"lessen flickering windows effect when scripts run",
false)
end
return dtutils_file