aboutsummaryrefslogtreecommitdiff
path: root/lockfiles.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lockfiles.lua')
-rw-r--r--lockfiles.lua84
1 files changed, 84 insertions, 0 deletions
diff --git a/lockfiles.lua b/lockfiles.lua
new file mode 100644
index 0000000..9e120bd
--- /dev/null
+++ b/lockfiles.lua
@@ -0,0 +1,84 @@
+-- Copyright (c) 2024 Florian Fischer. All rights reserved.
+--
+-- vis-lockfiles is free software: you can redistribute it and/or modify it under
+-- the terms of the GNU General Public License as published by the Free Software
+-- Foundation, either version 3 of the License, or (at your option) any later
+-- version.
+--
+-- vis-lockfiles is distributed in the hope that it will be useful, but WITHOUT
+-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+-- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License along with
+-- vis-lockfiles found in the LICENSE file.
+-- If not, see <https://www.gnu.org/licenses/>.
+-- Helper to execute a command and capture its output
+local function capture_cmd(cmd)
+ local p = assert(io.popen(cmd, 'r'))
+ local s = assert(p:read('*a'))
+ local success, _, status = p:close()
+ if not success then
+ local err = cmd .. ' failed with exit code: ' .. status
+ vis:info('vis-lockfiles: ' .. err)
+ end
+ return s
+end
+
+local function lock_file_path(lock_dir, path)
+ -- escape '%' first
+ local filename = path:gsub('%%', '%%25'):gsub('/', '%%2F')
+ return lock_dir .. '/' .. filename .. '.lock'
+end
+
+-- determine vis' pid
+local vis_pid
+do
+ local vis_proc_file = io.open('/proc/self/stat', 'r')
+ if vis_proc_file then
+ vis_pid = vis_proc_file:read('*n')
+ vis_proc_file:close()
+
+ else -- fallback if /proc/self/stat is not available
+ local out = capture_cmd('sh -c "echo $PPID"')
+ vis_pid = tonumber(out)
+ end
+end
+assert(vis_pid)
+
+local function create_lock_file(lock_dir, lfile_path)
+ local lock_file = io.open(lfile_path)
+ if lock_file then
+ lock_file:close()
+ return false
+ end
+
+ -- create the lock file with our pid
+ if not io.open(lfile_path, 'w') then
+ assert(os.execute('mkdir -p "' .. lock_dir .. '"'))
+ end
+ lock_file = assert(io.open(lfile_path, 'w'))
+ lock_file:write(vis_pid)
+ lock_file:close()
+
+ -- detect a possible race
+ lock_file = assert(io.open(lfile_path))
+ local lock_pid = lock_file:read('*n')
+ lock_file:close()
+ local locked = tonumber(lock_pid) == vis_pid
+
+ return locked
+end
+
+local function delete_lock_file(lfile_path)
+ local success, err = os.remove(lfile_path)
+ if not success then
+ vis:info('vis-lockfiles: ' .. err)
+ end
+end
+
+return {
+ capture_cmd = capture_cmd,
+ lock_file_path = lock_file_path,
+ delete_lock_file = delete_lock_file,
+ create_lock_file = create_lock_file,
+}