summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@gmail.com>2013-05-23 21:39:48 +0100
committerRichard Maw <richard.maw@gmail.com>2013-05-27 14:38:17 +0100
commitd3b151d89c0b0342eeb54291ded9304dcea767fa (patch)
treefdcd07a780a7d21f190024f13fc035b07c04aa41
parent4b7f212ba3a34d05cc51fccc0c6776d1f3f116c3 (diff)
downloadgitano-d3b151d89c0b0342eeb54291ded9304dcea767fa.tar.gz
util: add recursive directory copy functions
This is complicated enough it could be split out into its own module. The most important function is copy_dir, which along with the source and target, is given an optional table of functions, which can be used to change its behaviour for different types of files. It may also be given a filter function to determine which files to process. The default function excludes . and .. of each directory from the set of directories to process. It is given the parent directory, filename and fileinfo of every file to process, so it may exclude based on any combination of location, file name and file type by returning true.
-rw-r--r--lib/gitano/util.lua70
1 files changed, 70 insertions, 0 deletions
diff --git a/lib/gitano/util.lua b/lib/gitano/util.lua
index 44ad5ed..51c5bc2 100644
--- a/lib/gitano/util.lua
+++ b/lib/gitano/util.lua
@@ -8,6 +8,7 @@
local luxio = require 'luxio'
local sio = require 'luxio.simple'
+local log = require 'gitano.log'
local tconcat = table.concat
@@ -251,6 +252,71 @@ local function copy_symlink(from, to)
return true
end
+local function copy_pathname_filter(exclude_set)
+ return function(parent_path, filename, fileinfo)
+ return exclude_set[filename]
+ end
+end
+local _exclude_builtin = { ["."] = true, [".."] = true }
+local copy_dir_filter_base = copy_pathname_filter(_exclude_builtin)
+
+local copy_dir_copy_callbacks
+-- filter_cb is a function, which takes (parent_path, filename, fileinfo)
+-- and returns true if the component should not be copied
+-- parent_path is required, since filter_cb is passed on to subdirectories
+-- copy_cbs is an optional table of callbacks
+local function copy_dir(from, to, copy_cbs, filter_cb)
+ filter_cb = filter_cb or copy_dir_filter_base
+ copy_cbs = copy_cbs or copy_dir_copy_callbacks
+ local ret, err, dirp
+ ret, err = mkdir_p(to)
+ if not ret then
+ return ret, err
+ end
+ dirp, err, ret = sio.opendir(from)
+ if not dirp then
+ return ret, err
+ end
+ for filename, fileinfo in dirp:iterate() do
+ local copycb = copy_cbs[fileinfo.d_type]
+ local filefrom = path_join(from, filename)
+ local fileto = path_join(to, filename)
+ if filter_cb(from, filename, fileinfo) then
+ log.ddebug("Skipping file", filename)
+ elseif fileinfo.d_type == luxio.DT_REG then
+ log.ddebug("Copying file", filefrom, "to", fileto)
+ ret, err = copycb(filefrom, fileto)
+ if not ret then
+ log.critical("Copy file", filefrom, "to", fileto, "failed:", err)
+ return false, err
+ end
+ elseif fileinfo.d_type == luxio.DT_LNK then
+ log.ddebug("Copying symlink", filefrom, "to", fileto)
+ ret, err = copycb(filefrom, fileto)
+ if not ret then
+ log.critical("Copy symlink", filefrom, "to", fileto, "failed:", err)
+ return false, err
+ end
+ elseif fileinfo.d_type == luxio.DT_DIR then
+ log.ddebug("Copying dir", filefrom, "to", fileto)
+ ret, err = copycb(filefrom, fileto, copy_cbs, filter_cb)
+ if not ret then
+ log.critical("Copy dir", filefrom, "to", fileto, "failed:", err)
+ return ret, err
+ end
+ else
+ return false, ("Unsupported file type %d"):format(fileinfo.d_type)
+ end
+ end
+ return true
+end
+
+copy_dir_copy_callbacks = {
+ [luxio.DT_DIR] = copy_dir,
+ [luxio.DT_REG] = copy_file,
+ [luxio.DT_LNK] = copy_symlink,
+}
+
local function html_escape(s)
return (s:gsub("&", "&amp;"):
gsub("<", "&lt;"):
@@ -399,6 +465,10 @@ return {
copy_file = copy_file,
mkdir_p = mkdir_p,
rm_rf = rm_rf,
+ copy_pathname_filter = copy_pathname_filter,
+ copy_dir_filter_base = copy_dir_filter_base,
+ copy_dir_copy_callbacks = copy_dir_copy_callbacks,
+ copy_dir = copy_dir,
html_escape = html_escape,