Configure synchronization of files and directories through a plugin.
initial commit
11 files changed, +154 -73
+46-0lua/syncmap/dir/entry.lua
| @@ -0,0 +1,46 @@ | ||
| 1 | +local log = require("syncmap.log") | |
| 2 | +local simple_cmd = require("syncmap.simple_cmd") | |
| 3 | +local rsync = require("syncmap.rsync") | |
| 4 | +local M = { | |
| 5 | + opts = require("syncmap.default"), | |
| 6 | +} | |
| 7 | + | |
| 8 | +---@alias File string | |
| 9 | +---@alias Folder string | |
| 10 | + | |
| 11 | +---@alias Filetype "file"|"dir" | |
| 12 | + | |
| 13 | +---@class DirEntry | |
| 14 | +---@field path File|Folder | |
| 15 | +---@field rsync_flags RsyncFlag[] | |
| 16 | +---@field isfile? boolean | |
| 17 | +---@field isdir? boolean | |
| 18 | +DirEntry = {} | |
| 19 | + | |
| 20 | +---@return DirEntry|nil | |
| 21 | +---@param o DirEntry | |
| 22 | +function DirEntry:new(o) | |
| 23 | + local stat = vim.uv.fs_stat(o.path) | |
| 24 | + if stat and stat.type == "file" then | |
| 25 | + o.isfile = true | |
| 26 | + elseif stat and stat.type == "directory" then | |
| 27 | + o.isdir = true | |
| 28 | + else | |
| 29 | + log.error(string.format("%q is not a valid file or directory", o.path)) | |
| 30 | + return nil | |
| 31 | + end | |
| 32 | + | |
| 33 | + setmetatable(o, self) | |
| 34 | + self.__index = self | |
| 35 | + return o | |
| 36 | +end | |
| 37 | + | |
| 38 | +---@param src string | |
| 39 | +function DirEntry:rsync_from(src) | |
| 40 | + local cmd = { "rsync", unpack(self.rsync_flags), src, self.path } | |
| 41 | +end | |
| 42 | + | |
| 43 | +---@param dst string | |
| 44 | +function DirEntry:rsync_to(dst) end | |
| 45 | + | |
| 46 | +return M |
+0-0lua/syncmap/dir/init.lua
No content changes (mode or rename only).
+10-0lua/syncmap/dir/map.lua
| @@ -0,0 +1,10 @@ | ||
| 1 | +---@class MapConfig | |
| 2 | +---@field entries Entry[] | |
| 3 | + | |
| 4 | +---@class Map : MapConfig | |
| 5 | +Map = {} | |
| 6 | + | |
| 7 | +---@field o MapConfig | |
| 8 | +function Map:new(o) | |
| 9 | + o = o or {} | |
| 10 | +end |
+1-0lua/syncmap/exact/entry.lua
| @@ -0,0 +1 @@ | ||
| 1 | +---@class ExactEntry |
+0-0lua/syncmap/exact/init.lua
No content changes (mode or rename only).
+9-0lua/syncmap/flags.lua
| @@ -0,0 +1,9 @@ | ||
| 1 | +local log = require("syncmap.log") | |
| 2 | +local M = { | |
| 3 | + opts = require("syncmap.default"), | |
| 4 | +} | |
| 5 | + | |
| 6 | +---@param flags RsyncFlag[] | |
| 7 | +function M.parse() end | |
| 8 | + | |
| 9 | +return M |
+36-0lua/syncmap/inotify.lua
| @@ -0,0 +1,36 @@ | ||
| 1 | +local log = require("syncmap.log") | |
| 2 | +local spawn = require("syncmap.spawn") | |
| 3 | + | |
| 4 | +---@param src string | |
| 5 | +---@param dst string | |
| 6 | +---@param debounce integer | |
| 7 | +---@param rsync_flags RsyncFlag[] | |
| 8 | +return function(src, dst, debounce, rsync_flags) | |
| 9 | + local cmd = "while inotifywait " | |
| 10 | + local stat = vim.uv.fs_stat(src) | |
| 11 | + if stat and stat.type == "directory" then | |
| 12 | + log.debug(string.format("Setting up inotify for a file.\n%s", src)) | |
| 13 | + cmd = cmd .. string.format("-r -e modify,create,delete %q; ", src) | |
| 14 | + elseif stat and stat.type == "file" then | |
| 15 | + log.debug(string.format("Setting up inotify for a file.\n%s", src)) | |
| 16 | + cmd = cmd .. string.format("-e modify %q; ", src) | |
| 17 | + else | |
| 18 | + log.error(string.format("Could not stat %s", src)) | |
| 19 | + return "NO STAT" | |
| 20 | + end | |
| 21 | + cmd = cmd .. string.format("do rsync %s %q %q sleep %d; done", table.concat(rsync_flags, " "), src, dst, debounce) | |
| 22 | + local cmd_str_for_log = "sh -c '" .. cmd .. "'" | |
| 23 | + | |
| 24 | + local handle, pid = spawn("sh", { | |
| 25 | + args = { "-c", cmd }, | |
| 26 | + path = "sh", | |
| 27 | + callback = function(code, status, _, pid) | |
| 28 | + log.debug(string.format("%s\n%d completed with %d code and %d status", cmd_str_for_log, pid, code, status)) | |
| 29 | + end, | |
| 30 | + }) | |
| 31 | + if not handle then | |
| 32 | + log.error(string.format("Failed to start the following command.\n%s\nErr: %s", cmd_str_for_log, pid)) | |
| 33 | + else | |
| 34 | + log.debug(string.format("Started the following command with pid %d\n%s", pid, cmd_str_for_log)) | |
| 35 | + end | |
| 36 | +end |
+1-44lua/syncmap/rsync.lua
| @@ -6,7 +6,7 @@ local M = { | ||
| 6 | 6 | |
| 7 | 7 | ---Runs rsync |
| 8 | 8 | ---@param args RsyncParams |
| 9 | -function M.run(args) | |
| 9 | +return function(args) | |
| 10 | 10 | local cmd = { "rsync", unpack(args.flags), args.src, args.dst } |
| 11 | 11 | local result = vim.fn.system(cmd) |
| 12 | 12 | if vim.v.shell_error ~= 0 then |
| @@ -22,46 +22,3 @@ function M.run(args) | ||
| 22 | 22 | end |
| 23 | 23 | return result |
| 24 | 24 | end |
| 25 | - | |
| 26 | ----@param args RsyncParams | |
| 27 | -function M.spawn_watcher(args) | |
| 28 | - if M.opts.reverse_sync_on_startup then | |
| 29 | - M.run({ | |
| 30 | - src = args.dst, | |
| 31 | - dst = args.src, | |
| 32 | - reverse_sync_on_spawn = args.reverse_sync_on_spawn, | |
| 33 | - flags = args.flags, | |
| 34 | - }) | |
| 35 | - end | |
| 36 | - | |
| 37 | - local cmd = "while inotifywait " | |
| 38 | - local stat = vim.uv.fs_stat(args.src) | |
| 39 | - if stat and stat.type == "directory" then | |
| 40 | - log.debug(string.format("Setting up inotify for a file.\n%s", args.src)) | |
| 41 | - cmd = cmd .. string.format("-r -e modify,create,delete %q; ", args.src) | |
| 42 | - elseif stat and stat.type == "file" then | |
| 43 | - log.debug(string.format("Setting up inotify for a file.\n%s", args.src)) | |
| 44 | - cmd = cmd .. string.format("-e modify %q; ", args.src) | |
| 45 | - else | |
| 46 | - log.error(string.format("Could not stat %s", args.src)) | |
| 47 | - return "NO STAT" | |
| 48 | - end | |
| 49 | - cmd = cmd .. string.format("do rsync %s %q %q; done", table.concat(args.flags, " "), args.src, args.dst) | |
| 50 | - local cmd_str_for_log = "sh -c '" .. cmd .. "'" | |
| 51 | - | |
| 52 | - local handle, pid = simple_cmd.spawn("sh", { | |
| 53 | - args = { "-c", cmd }, | |
| 54 | - path = "sh", | |
| 55 | - callback = function(code, status, _, pid) | |
| 56 | - log.debug(string.format("%s\n%d completed with %d code and %d status", cmd_str_for_log, pid, code, status)) | |
| 57 | - end, | |
| 58 | - }) | |
| 59 | - if not handle then | |
| 60 | - log.error(string.format("Failed to start the following command.\n%s\nErr: %s", cmd_str_for_log, pid)) | |
| 61 | - else | |
| 62 | - log.debug(string.format("Started the following command with pid %d\n%s", pid, cmd_str_for_log)) | |
| 63 | - end | |
| 64 | - return pid, cmd_str_for_log | |
| 65 | -end | |
| 66 | - | |
| 67 | -return M |
+1-29lua/syncmap/simple_cmd.lua → lua/syncmap/spawn.lua
| @@ -1,5 +1,3 @@ | ||
| 1 | -local M = {} | |
| 2 | - | |
| 3 | 1 | ---@alias StdIO integer|uv.uv_stream_t|nil |
| 4 | 2 | |
| 5 | 3 | ---@alias SpawnCommandCallback fun(code:integer, signal:integer, handle:uv.uv_process_t, pid:integer) |
| @@ -21,7 +19,7 @@ local M = {} | ||
| 21 | 19 | ---A wrapper for uv.spawn that includes defaults. This makes it easier to spawn commands in the background. Also automatically closes the handle unless close is specified to false. |
| 22 | 20 | ---@param path string the exectuable path |
| 23 | 21 | ---@param p SpawnCommandParams |
| 24 | -function M.spawn(path, p) | |
| 22 | +return function(path, p) | |
| 25 | 23 | local args = p.args |
| 26 | 24 | local stdio = p.stdio or { nil, nil, nil } |
| 27 | 25 | local cwd = p.cwd or vim.fn.getcwd() |
| @@ -56,29 +54,3 @@ function M.spawn(path, p) | ||
| 56 | 54 | end) |
| 57 | 55 | return handle, pid |
| 58 | 56 | end |
| 59 | - | |
| 60 | ----Kills a process and all of its descendents | |
| 61 | ----@param pid integer|string | |
| 62 | -function M.kill(pid) | |
| 63 | - vim.fn.system({ "kill", "-TERM", "-" .. tostring(pid) }) | |
| 64 | -end | |
| 65 | - | |
| 66 | ----Checks if a process is running | |
| 67 | ----@param pid string|integer | |
| 68 | -function M.exists(pid) | |
| 69 | - local result = false | |
| 70 | - local done = false | |
| 71 | - M.spawn("ps", { | |
| 72 | - args = { "-s", tostring(pid) }, | |
| 73 | - callback = function(code, _, _, _) | |
| 74 | - result = code == 0 | |
| 75 | - done = true | |
| 76 | - end, | |
| 77 | - }) | |
| 78 | - vim.wait(100, function() | |
| 79 | - return done | |
| 80 | - end, 10) | |
| 81 | - return result | |
| 82 | -end | |
| 83 | - | |
| 84 | -return M |
+50-0lua/syncmap/system.lua
| @@ -0,0 +1,50 @@ | ||
| 1 | +local log = require("syncmap.log") | |
| 2 | +local simple_cmd = require("syncmap.simple_cmd") | |
| 3 | +local M = { | |
| 4 | + opts = require("syncmap.default"), | |
| 5 | +} | |
| 6 | + | |
| 7 | +---@param args RsyncParams | |
| 8 | +function M.rsync(args) | |
| 9 | + simple_cmd.spawn() | |
| 10 | + local cmd = { "rsync", unpack(args.flags), args.src, args.dst } | |
| 11 | + local result = vim.fn.system(cmd) | |
| 12 | + if vim.v.shell_error ~= 0 then | |
| 13 | + log.error( | |
| 14 | + string.format( | |
| 15 | + "Failed to run the the following rsync command.\n%s\nResult: %s", | |
| 16 | + table.concat(cmd, " "), | |
| 17 | + result | |
| 18 | + ) | |
| 19 | + ) | |
| 20 | + else | |
| 21 | + log.debug("Successfully ran the following rsync command.\n" .. table.concat(cmd, " ")) | |
| 22 | + end | |
| 23 | + return result | |
| 24 | +end | |
| 25 | + | |
| 26 | +---Kills a process and all of its descendents | |
| 27 | +---@param pid integer|string | |
| 28 | +function M.kill(pid) | |
| 29 | + vim.fn.system({ "kill", "-TERM", "-" .. tostring(pid) }) | |
| 30 | +end | |
| 31 | + | |
| 32 | +---Checks if a process is running | |
| 33 | +---@param pid string|integer | |
| 34 | +function M.exists(pid) | |
| 35 | + local result = false | |
| 36 | + local done = false | |
| 37 | + M.spawn("ps", { | |
| 38 | + args = { "-s", tostring(pid) }, | |
| 39 | + callback = function(code, _, _, _) | |
| 40 | + result = code == 0 | |
| 41 | + done = true | |
| 42 | + end, | |
| 43 | + }) | |
| 44 | + vim.wait(100, function() | |
| 45 | + return done | |
| 46 | + end, 10) | |
| 47 | + return result | |
| 48 | +end | |
| 49 | + | |
| 50 | +return M |
+0-0lua/syncmap/watch.lua
No content changes (mode or rename only).