Files
lua-scripts-w-api/lib/dtutils/file.lua

990 lines
31 KiB
Lua

local dtutils_file = {}
local dt = require "darktable"
local du = require "lib/dtutils"
local ds = require "lib/dtutils.string"
local dsys = require "lib/dtutils.system"
local log = require "lib/dtutils.log"
dtutils_file.libdoc = {
Name = [[dtutils.file]],
Synopsis = [[common darktable lua file functions]],
Usage = [[local df = require "lib/dtutils.file"]],
Description = [[[dtutils.file provides common file manipulation functions used in
constructing Darktable lua scripts]],
Return_Value = [[df - library - the file functions]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = log.libdoc.License,
Copyright = [[Copyright (C) 2016 Bill Ferguson <wpferguson@gmail.com>.]],
Copyright = [[Copyright (C) 2016 Bill Ferguson <wpferguson@gmail.com>.
Copyright (C) 2016 Tobias Jakobs]],
functions = {}
}
local gettext = dt.gettext
du.check_min_api_version("5.0.0", "dtutils.file")
-- Tell gettext where to find the .mo file translating messages for a particular domain
gettext.bindtextdomain("dtutils.file",dt.configuration.config_dir.."/lua/locale/")
local function _(msgid)
return gettext.dgettext("dtutils.file", msgid)
end
--[[
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.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 = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
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 "
engine = _win_os_execute
end
if test == "d" then
-- test if directory
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 == "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
cmdstring = cmd .. test .. " " .. dtutils_file.sanitize_filename(path)
end
elseif test == "x" then
-- test executable
if dt.configuration.running_os == "windows" then
return _is_windows_executable(path)
else
cmdstring = cmd .. test .. " " .. dtutils_file.sanitize_filename(path)
end
else
dt.print_error("[test_file] unknown test " .. test)
return false
end
return engine(cmdstring)
end
--[[
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
-- use where on path
-- use where on program files
-- use where on program files (x86)
local args = {"", '/R "C:\\Program Files"', '/R "C:\\Program Files (x86)"'}
for _,arg in ipairs(args) do
local cmd = "where " .. arg .. " " .. ds.sanitize(bin)
local p = io.popen(cmd)
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, 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
end
end
end
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)
local output = p:read("*a")
p:close()
if string.len(output) > 0 then
local spath = dtutils_file.sanitize_filename(output:sub(1, -2))
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) -- see if it's in the path
if not result then
local search_start = "/Applications"
if dtutils_file.check_if_file_exists("/Applications/" .. bin .. ".app") then
search_start = "/Applications/" .. bin .. ".app"
end
local p = io.popen("find " .. search_start .. " -type f -name " .. bin .. " -print")
local output = p:read("*a")
p:close()
local lines = du.split(output, "\n")
for _,line in ipairs(lines) do
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
end
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
result = _search_for_bin_nix(bin)
end
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
if string.len(path) > 0 then
-- check for windows executable to run under wine
if _is_windows_executable(path) then
if dtutils_file.check_if_file_exists(path) then
result = "wine " .. dtutils_file.sanitize_filename(path)
end
end
end
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
local PS = dt.configuration.running_os == "windows" and "\\" or "/"
if string.match(bin, PS) then
path = bin
else
path = dtutils_file.get_executable_path_preference(bin)
-- reset path preference is the returned preference is a directory
if dtutils_file.test_file(path, "d") then
dtutils_file.set_executable_path_preference(bin, "")
path = nil
end
end
if path and dtutils_file.test_file(path, "d") then
path = nil
end
if path and dt.configuration.running_os ~= "windows" then
result = _check_path_for_wine_bin(path)
end
if path and not result then
if dtutils_file.test_file(path, "x") then
result = dtutils_file.sanitize_filename(path)
end
end
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
dtutils_file.libdoc.functions["split_filepath"] = {
Name = [[split_filepath]],
Synopsis = [[split a filepath into parts]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.split_filepath(filepath)
filepath - string - path and filename]],
Description = [[split_filepath splits a filepath into the path, filename, basename and filetype and puts
that in a table]],
Return_Value = [[result - table - a table containing the path, filename, basename, and filetype]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.split_filepath(str)
-- strip out single quotes from quoted pathnames
str = string.gsub(str, "'", "")
str = string.gsub(str, '"', '')
local result = {}
-- Thank you Tobias Jakobs for the awesome regular expression, which I tweaked a little
result["path"], result["filename"], result["basename"], result["filetype"] = string.match(str, "(.-)(([^\\/]-)%.?([^%.\\/]*))$")
if result["basename"] == "" and result["filetype"]:len() > 1 then
result["basename"] = result["filetype"]
result["filetype"] = ""
end
return result
end
dtutils_file.libdoc.functions["get_path"] = {
Name = [[get_path]],
Synopsis = [[get the path from a file path]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.get_path(filepath)
filepath - string - path and filename]],
Description = [[get_path strips the filename and filetype from a path and returns the path]],
Return_Value = [[result - string - the path]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.get_path(str)
local parts = dtutils_file.split_filepath(str)
return parts["path"]
end
dtutils_file.libdoc.functions["get_filename"] = {
Name = [[get_filename]],
Synopsis = [[get the filename and extension from a file path]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.get_filename(filepath)
filepath - string - path and filename]],
Description = [[get_filename strips the path from a filepath and returns the filename]],
Return_Value = [[result - string - the file name and type]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.get_filename(str)
local parts = dtutils_file.split_filepath(str)
return parts["filename"]
end
dtutils_file.libdoc.functions["get_basename"] = {
Name = [[get_basename]],
Synopsis = [[get the filename without the path or extension]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.get_basename(filepath)
filepath - string - path and filename]],
Description = [[get_basename returns the name of the file without the path or filetype
]],
Return_Value = [[result - string - the basename of the file]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.get_basename(str)
local parts = dtutils_file.split_filepath(str)
return parts["basename"]
end
dtutils_file.libdoc.functions["get_filetype"] = {
Name = [[get_filetype]],
Synopsis = [[get the filetype from a filename]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.get_filetype(filepath)
filepath - string - path and filename]],
Description = [[get_filetype returns the filetype from the supplied filepath]],
Return_Value = [[result - string - the filetype]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.get_filetype(str)
local parts = dtutils_file.split_filepath(str)
return parts["filetype"]
end
-- Thanks Tobias Jakobs for the idea
dtutils_file.libdoc.functions["check_if_file_exists"] = {
Name = [[check_if_file_exists]],
Synopsis = [[check if a file or path exist]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.check_if_file_exists(filepath)
filepath - string - a file or path to check]],
Description = [[check_if_file_exists checks to see if a file or path exists]],
Return_Value = [[result - boolean - true if the file or path exists, false if it doesn't]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.check_if_file_exists(filepath)
local result = false
if (dt.configuration.running_os == 'windows') then
filepath = string.gsub(filepath, '[\\/]+', '\\')
local p = io.popen("if exist " .. dtutils_file.sanitize_filename(filepath) .. " (echo 'yes') else (echo 'no')")
local ans = p:read("*all")
p:close()
if string.match(ans, "yes") then
result = true
end
-- result = os.execute('if exist "'..filepath..'" (cmd /c exit 0) else (cmd /c exit 1)')
-- if not result then
-- result = false
-- end
elseif (dt.configuration.running_os == "linux") then
result = os.execute('test -e ' .. dtutils_file.sanitize_filename(filepath))
if not result then
result = false
end
else
local file = io.open(filepath, "r")
if file then
result = true
file:close()
else
result = false
end
end
return result
end
dtutils_file.libdoc.functions["chop_filetype"] = {
Name = [[chop_filetype]],
Synopsis = [[remove a filetype from a filename]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.chop_filetype(path)
path - string - a filename with or without a path]],
Description = [[chop_filetype removes the filetype from the filename]],
Return_Value = [[result - string - the path and filename without the filetype]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.chop_filetype(path)
local length = dtutils_file.get_filetype(path):len() + 2
if length > 2 then
return string.sub(path, 1, -length)
else
return path
end
end
dtutils_file.libdoc.functions["file_copy"] = {
Name = [[file_copy]],
Synopsis = [[copy a file to another name/location]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.file_copy(fromFile, toFile)
fromFile - string - name of file to copy from
toFile - string - name of file to copy to]],
Description = [[copy a file using a succession of methods from operating system
to a pure lua solution]],
Return_Value = [[result - boolean - nil on error, true on success]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.file_copy(fromFile, toFile)
local result = nil
-- if cp exists, use it
if dt.configuration.running_os == "windows" then
result = os.execute('copy "' .. fromFile .. '" "' .. toFile .. '"')
elseif dtutils_file.check_if_bin_exists("cp") then
result = os.execute("cp '" .. fromFile .. "' '" .. toFile .. "'")
end
-- if cp was not present, or if cp failed, then a pure lua solution
if not result then
local fileIn, err = io.open(fromFile, 'rb')
if fileIn then
local fileOut, errr = io.open(toFile, 'w')
if fileOut then
local content = fileIn:read(4096)
while content do
fileOut:write(content)
content = fileIn:read(4096)
end
result = true
fileIn:close()
fileOut:close()
else
log.msg(log.error, errr)
end
else
log.msg(log.error, err)
end
end
return result
end
dtutils_file.libdoc.functions["file_move"] = {
Name = [[file_move]],
Synopsis = [[move a file from one directory to another]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.file_move(fromFile, toFile)
fromFile - string - name of the original file
toFile - string - the new file location and name]],
Description = [[Move a file from one place to another. Try a succession of methods from
builtin to operating system to a pure lua solution.]],
Return_Value = [[result - boolean - nil on error, some value on success]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.file_move(fromFile, toFile)
local success = os.rename(fromFile, toFile)
if not success then
-- an error occurred, so let's try using the operating system function
if dtutils_file.check_if_bin_exists("mv") then
success = os.execute("mv '" .. fromFile .. "' '" .. toFile .. "'")
end
-- if the mv didn't exist or succeed, then...
if not success then
-- pure lua solution
success = dtutils_file.file_copy(fromFile, toFile)
if success then
os.remove(fromFile)
else
log.msg(log.error, "Unable to move " .. fromFile .. " to " .. toFile .. ". Leaving " .. fromFile .. " in place.")
end
end
end
return success -- nil on error, some value if success
end
dtutils_file.libdoc.functions["filename_increment"] = {
Name = [[filename_increment]],
Synopsis = [[add a two digit increment to a filename]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.filename_increment(filepath)
filepath - string - filename to increment]],
Description = [[filename_increment solves the problem of filename confllict by adding an
increment to the filename. If the supplied filename has no increment then
"01" is added to the basename. If the filename already has an increment, then
1 is added to it and the filename returned.]],
Return_Value = [[result - string - the incremented filename]],
Limitations = [[The filename will be incremented to 99]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.filename_increment(filepath)
-- break up the filepath into parts
local path = dtutils_file.get_path(filepath)
local basename = dtutils_file.get_basename(filepath)
local filetype = dtutils_file.get_filetype(filepath)
-- check to see if we've incremented before
local increment = string.match(basename, "_(%d-)$")
if increment then
-- we do 2 digit increments so make sure we didn't grab part of the filename
if string.len(increment) > 2 then
-- we got the filename so set the increment to 01
increment = "01"
elseif increment == "99" then
dt.print_error("not incrementing, filename has already been incremented 99 times.")
return filepath
else
increment = string.format("%02d", tonumber(increment) + 1)
basename = string.gsub(basename, "_(%d-)$", "")
end
else
increment = "01"
end
local incremented_filepath = path .. basename .. "_" .. increment .. "." .. filetype
return incremented_filepath
end
dtutils_file.libdoc.functions["create_unique_filename"] = {
Name = [[create_unique_filename]],
Synopsis = [[create a unique filename from the supplied argment]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.create_unique_filename(filepath)
filepath - string - the path and filename requested]],
Description = [[create_unique_filename takes a requested filepath and checks to see if
it exists. If if doesn't then it's returned intact. If it already exists, then a two
digit increment is added to the filename and it is tested again. The increment keeps
increasing until either a unique filename is found or there have been 100 attempts.]],
Return_Value = [[result - string - the incremented filename]],
Limitations = [[create_unique_filename will only attempt 100 increments.]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.create_unique_filename(filepath)
while dtutils_file.check_if_file_exists(filepath) do
filepath = dtutils_file.filename_increment(filepath)
-- limit to 99 more exports of the original export
local increment = string.match(dtutils_file.get_basename(filepath), "_(%d-)$")
if increment == "99" then
break
end
end
return filepath
end
dtutils_file.libdoc.functions["set_executable_path_preference"] = {
Name = [[set_executable_path_preference]],
Synopsis = [[set a preference for the path to an executable]],
Usage = [[local df = require "lib/dtutils.file"
df.set_executable_path_preference(executable, path)
executable - string - the name of the executable to set the path for
path - string - the path to the binary]],
Description = [[set_executable_path_preference takes an executable name and path to the
executable and registers the preference for later use.]],
Return_Value = [[]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.set_executable_path_preference(executable, path)
dt.preferences.write("executable_paths", executable, "string", path)
end
dtutils_file.libdoc.functions["get_executable_path_preference"] = {
Name = [[get_executable_path_preference]],
Synopsis = [[return the path to an executable from a preference]],
Usage = [[local df = require "lib/dtutils.file"
local result = df.get_executable_path_preference(executable)
executable - string - the name of the executable to get the path for]],
Description = [[get_executable_path_preference returns the path preference to
the requested executable.]],
Return_Value = [[result - string - path to the executable]],
Limitations = [[executable should be the basename of the executable without extensions]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.get_executable_path_preference(executable)
return dt.preferences.read("executable_paths", executable, "string")
end
dtutils_file.libdoc.functions["executable_path_widget"] = {
Name = [[executable_path_widget]],
Synopsis = [[create a widget to get executable path preferences]],
Usage = [[local df = require "lib/dtutils.file"
local widget = df.executable_path_widget(executables)
executables - table - a table of strings that are executable names]],
Description = [[executable_path_widget takes a table of executable names
and builds a set of file selector widgets to get the path to the executable.
The resulting widgets are wrapped in a box widget and returned.]],
Return_Value = [[widget - widget - a widget containing a file selector widget for
each executable.]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.executable_path_widget(executables)
local box_widgets = {}
table.insert(box_widgets, dt.new_widget("section_label"){label = "select executable(s)"})
for _, executable in pairs(executables) do
table.insert(box_widgets, dt.new_widget("label"){label = "select " .. executable .. " executable"})
local path = dtutils_file.get_executable_path_preference(executable)
if not path then
path = ""
end
table.insert(box_widgets, dt.new_widget("file_chooser_button"){
title = "select " .. executable .. " executable",
value = path,
is_directory = false,
changed_callback = function(self)
if dtutils_file.check_if_bin_exists(self.value) then
dtutils_file.set_executable_path_preference(executable, self.value)
end
end
}
)
end
local box = dt.new_widget("box"){
orientation = "vertical",
table.unpack(box_widgets)
}
return box
end
dtutils_file.libdoc.functions["sanitize_filename"] = {
Name = [[sanitize_filename]],
Synopsis = [[make a filename safe to pass as an argument]],
Usage = [[local df = require "lib/dtutils.file"
local sanitized_filename = df.sanitize_filename(filename)
filename - string - a filepath and filename]],
Description = [[sanitize_file places quotes around the filename in an
operating system specific manner. The result is safe to pass as
an argument to the operating system.]],
Return_Value = [[sanitized_filename - string - quoted filename]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.sanitize_filename(filename)
return ds.sanitize(filename)
end
dtutils_file.libdoc.functions["mkdir"] = {
Name = [[mkdir]],
Synopsis = [[create the directory(ies) if they do not already exists]],
Usage = [[local df = require "lib/dtutils.file"
df.mkdir(path)
path - string - a directory path]],
Description = [[mkdir creates directories if not already exists. It
create whole parents subtree if needed
]],
Return_Value = [[path - string - a directory path]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.mkdir(path)
if not dtutils_file.check_if_file_exists(path) then
local mkdir_cmd = dt.configuration.running_os == "windows" and "mkdir" or "mkdir -p"
return dsys.external_command(mkdir_cmd.." "..path)
else
return 0
end
end
dtutils_file.libdoc.functions["rmdir"] = {
Name = [[rmdir]],
Synopsis = [[recursively remove a directory]],
Usage = [[local df = require "lib/dtutils.file"
df.rmdir(path)
path - string - a directory path]],
Description = [[rm allow to recursively remove directories]],
Return_Value = [[path - string - a directory path]],
Limitations = [[]],
Example = [[]],
See_Also = [[]],
Reference = [[]],
License = [[]],
Copyright = [[]],
}
function dtutils_file.rmdir(path)
local rm_cmd = dt.configuration.running_os == "windows" and "rmdir /S /Q" or "rm -r"
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