2017-02-14 00:16:45 +01:00
|
|
|
---------------------------------------------------------------------------
|
2021-12-21 06:54:15 +01:00
|
|
|
--- Various filesystem utility functions.
|
|
|
|
--
|
|
|
|
-- Note that these functions are blocking. If you need to do a large number of
|
|
|
|
-- I/O operations, it is better to use `lgi.Gio` async functions.
|
2017-02-14 00:16:45 +01:00
|
|
|
--
|
2019-06-06 09:40:17 +02:00
|
|
|
-- @utillib gears.filesystem
|
2017-02-14 00:16:45 +01:00
|
|
|
---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
-- Grab environment we need
|
|
|
|
local Gio = require("lgi").Gio
|
2017-03-18 01:14:37 +01:00
|
|
|
local gstring = require("gears.string")
|
|
|
|
local gtable = require("gears.table")
|
2017-02-14 00:16:45 +01:00
|
|
|
|
|
|
|
local filesystem = {}
|
|
|
|
|
2017-04-02 18:52:23 +02:00
|
|
|
local function make_directory(gfile)
|
2017-04-02 18:46:54 +02:00
|
|
|
local success, err = gfile:make_directory_with_parents()
|
|
|
|
if success then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
if err.domain == Gio.IOErrorEnum and err.code == "EXISTS" then
|
2017-04-02 18:52:23 +02:00
|
|
|
-- Directory already exists, let this count as success
|
2017-04-02 18:46:54 +02:00
|
|
|
return true
|
|
|
|
end
|
|
|
|
return false, err
|
2017-02-14 00:16:45 +01:00
|
|
|
end
|
|
|
|
|
2017-04-08 11:02:53 +02:00
|
|
|
--- Create a directory, including all missing parent directories.
|
2017-04-02 18:52:23 +02:00
|
|
|
-- @tparam string dir The directory.
|
|
|
|
-- @return (true, nil) on success, (false, err) on failure
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.make_directories
|
2017-04-08 11:02:53 +02:00
|
|
|
function filesystem.make_directories(dir)
|
2017-04-02 18:52:23 +02:00
|
|
|
return make_directory(Gio.File.new_for_path(dir))
|
|
|
|
end
|
|
|
|
|
2017-04-08 11:02:53 +02:00
|
|
|
function filesystem.mkdir(dir)
|
|
|
|
require("gears.debug").deprecate("gears.filesystem.make_directories", {deprecated_in=5})
|
|
|
|
return filesystem.make_directories(dir)
|
|
|
|
end
|
|
|
|
|
2017-04-18 15:40:57 +02:00
|
|
|
--- Create all parent directories for a given path.
|
2017-04-02 18:52:23 +02:00
|
|
|
-- @tparam string path The path whose parents should be created.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @return (true, nil) on success, (false, err) on failure.
|
|
|
|
-- @staticfct gears.filesystem.make_parent_directories
|
2017-04-18 15:40:57 +02:00
|
|
|
function filesystem.make_parent_directories(path)
|
|
|
|
return make_directory(Gio.File.new_for_path(path):get_parent())
|
2017-04-02 18:52:23 +02:00
|
|
|
end
|
|
|
|
|
2017-02-14 00:16:45 +01:00
|
|
|
--- Check if a file exists, is readable and not a directory.
|
|
|
|
-- @tparam string filename The file path.
|
|
|
|
-- @treturn boolean True if file exists and is readable.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.file_readable
|
2017-02-14 00:16:45 +01:00
|
|
|
function filesystem.file_readable(filename)
|
|
|
|
local gfile = Gio.File.new_for_path(filename)
|
|
|
|
local gfileinfo = gfile:query_info("standard::type,access::can-read",
|
|
|
|
Gio.FileQueryInfoFlags.NONE)
|
|
|
|
return gfileinfo and gfileinfo:get_file_type() ~= "DIRECTORY" and
|
|
|
|
gfileinfo:get_attribute_boolean("access::can-read")
|
|
|
|
end
|
|
|
|
|
2017-07-02 15:55:19 +02:00
|
|
|
--- Check if a file exists, is executable and not a directory.
|
|
|
|
-- @tparam string filename The file path.
|
|
|
|
-- @treturn boolean True if file exists and is executable.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.file_executable
|
2017-07-02 15:55:19 +02:00
|
|
|
function filesystem.file_executable(filename)
|
|
|
|
local gfile = Gio.File.new_for_path(filename)
|
|
|
|
local gfileinfo = gfile:query_info("standard::type,access::can-execute",
|
|
|
|
Gio.FileQueryInfoFlags.NONE)
|
|
|
|
return gfileinfo and gfileinfo:get_file_type() ~= "DIRECTORY" and
|
|
|
|
gfileinfo:get_attribute_boolean("access::can-execute")
|
|
|
|
end
|
|
|
|
|
2017-02-14 00:16:45 +01:00
|
|
|
--- Check if a path exists, is readable and a directory.
|
|
|
|
-- @tparam string path The directory path.
|
|
|
|
-- @treturn boolean True if path exists and is readable.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.dir_readable
|
2017-02-14 00:16:45 +01:00
|
|
|
function filesystem.dir_readable(path)
|
|
|
|
local gfile = Gio.File.new_for_path(path)
|
|
|
|
local gfileinfo = gfile:query_info("standard::type,access::can-read",
|
|
|
|
Gio.FileQueryInfoFlags.NONE)
|
|
|
|
return gfileinfo and gfileinfo:get_file_type() == "DIRECTORY" and
|
|
|
|
gfileinfo:get_attribute_boolean("access::can-read")
|
|
|
|
end
|
|
|
|
|
2022-07-17 18:39:02 +02:00
|
|
|
--- Check if a path exists, is writable and a directory.
|
|
|
|
-- @tparam string path The directory path.
|
|
|
|
-- @treturn boolean True if path exists and is writable.
|
|
|
|
-- @staticfct gears.filesystem.dir_writable
|
|
|
|
function filesystem.dir_writable(path)
|
|
|
|
local gfile = Gio.File.new_for_path(path)
|
|
|
|
local gfileinfo = gfile:query_info("standard::type,access::can-write",
|
|
|
|
Gio.FileQueryInfoFlags.NONE)
|
|
|
|
return gfileinfo and gfileinfo:get_file_type() == "DIRECTORY" and
|
|
|
|
gfileinfo:get_attribute_boolean("access::can-write")
|
|
|
|
end
|
|
|
|
|
2017-02-14 00:16:45 +01:00
|
|
|
--- Check if a path is a directory.
|
|
|
|
-- @tparam string path The directory path
|
|
|
|
-- @treturn boolean True if path exists and is a directory.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.is_dir
|
2017-02-14 00:16:45 +01:00
|
|
|
function filesystem.is_dir(path)
|
|
|
|
return Gio.File.new_for_path(path):query_file_type({}) == "DIRECTORY"
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Get the config home according to the XDG basedir specification.
|
|
|
|
-- @return the config home (XDG_CONFIG_HOME) with a slash at the end.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.get_xdg_config_home
|
2017-02-14 00:16:45 +01:00
|
|
|
function filesystem.get_xdg_config_home()
|
|
|
|
return (os.getenv("XDG_CONFIG_HOME") or os.getenv("HOME") .. "/.config") .. "/"
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Get the cache home according to the XDG basedir specification.
|
|
|
|
-- @return the cache home (XDG_CACHE_HOME) with a slash at the end.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.get_xdg_cache_home
|
2017-02-14 00:16:45 +01:00
|
|
|
function filesystem.get_xdg_cache_home()
|
|
|
|
return (os.getenv("XDG_CACHE_HOME") or os.getenv("HOME") .. "/.cache") .. "/"
|
|
|
|
end
|
|
|
|
|
2017-03-18 01:14:37 +01:00
|
|
|
--- Get the data home according to the XDG basedir specification.
|
|
|
|
-- @treturn string the data home (XDG_DATA_HOME) with a slash at the end.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.get_xdg_data_home
|
2017-03-18 01:14:37 +01:00
|
|
|
function filesystem.get_xdg_data_home()
|
|
|
|
return (os.getenv("XDG_DATA_HOME") or os.getenv("HOME") .. "/.local/share") .. "/"
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Get the data dirs according to the XDG basedir specification.
|
|
|
|
-- @treturn table the data dirs (XDG_DATA_DIRS) with a slash at the end of each entry.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.get_xdg_data_dirs
|
2017-03-18 01:14:37 +01:00
|
|
|
function filesystem.get_xdg_data_dirs()
|
|
|
|
local xdg_data_dirs = os.getenv("XDG_DATA_DIRS") or "/usr/share:/usr/local/share"
|
|
|
|
return gtable.map(
|
|
|
|
function(dir) return dir .. "/" end,
|
|
|
|
gstring.split(xdg_data_dirs, ":"))
|
|
|
|
end
|
|
|
|
|
2017-02-14 00:16:45 +01:00
|
|
|
--- Get the path to the user's config dir.
|
|
|
|
-- This is the directory containing the configuration file ("rc.lua").
|
|
|
|
-- @return A string with the requested path with a slash at the end.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.get_configuration_dir
|
2017-02-14 00:16:45 +01:00
|
|
|
function filesystem.get_configuration_dir()
|
|
|
|
return awesome.conffile:match(".*/") or "./"
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Get the path to a directory that should be used for caching data.
|
|
|
|
-- @return A string with the requested path with a slash at the end.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.get_cache_dir
|
2017-02-14 00:16:45 +01:00
|
|
|
function filesystem.get_cache_dir()
|
2017-04-02 18:56:24 +02:00
|
|
|
local result = filesystem.get_xdg_cache_home() .. "awesome/"
|
2017-04-08 11:02:53 +02:00
|
|
|
filesystem.make_directories(result)
|
2017-04-02 18:56:24 +02:00
|
|
|
return result
|
2017-02-14 00:16:45 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
--- Get the path to the directory where themes are installed.
|
|
|
|
-- @return A string with the requested path with a slash at the end.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.get_themes_dir
|
2017-02-14 00:16:45 +01:00
|
|
|
function filesystem.get_themes_dir()
|
|
|
|
return (os.getenv('AWESOME_THEMES_PATH') or awesome.themes_path) .. "/"
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Get the path to the directory where our icons are installed.
|
|
|
|
-- @return A string with the requested path with a slash at the end.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.get_awesome_icon_dir
|
2017-02-14 00:16:45 +01:00
|
|
|
function filesystem.get_awesome_icon_dir()
|
|
|
|
return (os.getenv('AWESOME_ICON_PATH') or awesome.icon_path) .. "/"
|
|
|
|
end
|
|
|
|
|
|
|
|
--- Get the user's config or cache dir.
|
|
|
|
-- It first checks XDG_CONFIG_HOME / XDG_CACHE_HOME, but then goes with the
|
|
|
|
-- default paths.
|
|
|
|
-- @param d The directory to get (either "config" or "cache").
|
|
|
|
-- @return A string containing the requested path.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.get_dir
|
2017-02-14 00:16:45 +01:00
|
|
|
function filesystem.get_dir(d)
|
|
|
|
if d == "config" then
|
|
|
|
-- No idea why this is what is returned, I recommend everyone to use
|
|
|
|
-- get_configuration_dir() instead
|
2018-03-11 15:58:04 +01:00
|
|
|
require("gears.debug").deprecate("gears.filesystem.get_xdg_config_home() .. 'awesome/'", {deprecated_in=5})
|
2017-02-14 00:16:45 +01:00
|
|
|
return filesystem.get_xdg_config_home() .. "awesome/"
|
|
|
|
elseif d == "cache" then
|
2018-03-11 15:58:04 +01:00
|
|
|
require("gears.debug").deprecate("gears.filesystem.get_cache_dir", {deprecated_in=5})
|
2017-02-14 00:16:45 +01:00
|
|
|
return filesystem.get_cache_dir()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-02-16 19:58:24 +01:00
|
|
|
--- Get the name of a random file from a given directory.
|
|
|
|
-- @tparam string path The directory to search.
|
|
|
|
-- @tparam[opt] table exts Specific extensions to limit the search to. eg:`{ "jpg", "png" }`
|
|
|
|
-- If ommited, all files are considered.
|
2021-09-08 01:32:59 +02:00
|
|
|
-- @tparam[opt=false] boolean absolute_path Return the absolute path instead of the filename.
|
2019-02-16 19:58:24 +01:00
|
|
|
-- @treturn string|nil A randomly selected filename from the specified path (with
|
2021-09-08 01:32:59 +02:00
|
|
|
-- a specified extension if required) or nil if no suitable file is found. If `absolute_path`
|
|
|
|
-- is set, then a path is returned instead of a file name.
|
2019-06-08 01:08:05 +02:00
|
|
|
-- @staticfct gears.filesystem.get_random_file_from_dir
|
2021-09-08 01:32:59 +02:00
|
|
|
function filesystem.get_random_file_from_dir(path, exts, absolute_path)
|
2019-02-16 19:58:24 +01:00
|
|
|
local files, valid_exts = {}, {}
|
|
|
|
|
|
|
|
-- Transforms { "jpg", ... } into { [jpg] = #, ... }
|
2021-09-08 01:32:59 +02:00
|
|
|
if exts then for i, j in ipairs(exts) do valid_exts[j:lower():gsub("^[.]", "")] = i end end
|
2019-02-16 19:58:24 +01:00
|
|
|
|
|
|
|
-- Build a table of files from the path with the required extensions
|
|
|
|
local file_list = Gio.File.new_for_path(path):enumerate_children("standard::*", 0)
|
2021-09-08 01:32:59 +02:00
|
|
|
|
|
|
|
-- This will happen when the directory doesn't exist.
|
|
|
|
if not file_list then return nil end
|
|
|
|
|
2019-02-16 19:58:24 +01:00
|
|
|
for file in function() return file_list:next_file() end do
|
|
|
|
if file:get_file_type() == "REGULAR" then
|
|
|
|
local file_name = file:get_display_name()
|
2021-09-08 01:32:59 +02:00
|
|
|
|
2019-02-16 19:58:24 +01:00
|
|
|
if not exts or valid_exts[file_name:lower():match(".+%.(.*)$") or ""] then
|
|
|
|
table.insert(files, file_name)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-09-08 01:32:59 +02:00
|
|
|
if #files == 0 then return nil end
|
|
|
|
|
2019-02-16 19:58:24 +01:00
|
|
|
-- Return a randomly selected filename from the file table
|
2021-09-08 01:32:59 +02:00
|
|
|
local file = files[math.random(#files)]
|
|
|
|
|
|
|
|
return absolute_path and (path:gsub("[/]*$", "") .. "/" .. file) or file
|
2019-02-16 19:58:24 +01:00
|
|
|
end
|
|
|
|
|
2017-02-14 00:16:45 +01:00
|
|
|
return filesystem
|