aboutsummaryrefslogtreecommitdiffstats
path: root/main.lua
diff options
context:
space:
mode:
Diffstat (limited to 'main.lua')
-rw-r--r--main.lua247
1 files changed, 247 insertions, 0 deletions
diff --git a/main.lua b/main.lua
new file mode 100644
index 0000000..83316b8
--- /dev/null
+++ b/main.lua
@@ -0,0 +1,247 @@
+-- Copyright (c) 2024 squibid, see LICENSE file for more info
+local mp = require('mp')
+local msg = require('mp.msg')
+local utils = require('mp.utils')
+
+local proc = require('proc')
+
+-- load the config file
+local config = dofile(mp.command_native({"expand-path", "~~/eatit-cfg.lua"}))
+if not config or type(config) ~= "table" then
+ msg.fatal("no config provided, bailing out")
+ return
+end
+
+local base_dir = mp.command_native({"expand-path", "~~cache/plugins"})
+local packages = {}
+
+-- make sure the base directory exists (*nix only)
+if utils.file_info(base_dir) == nil then
+ proc.exec({ "mkdir", "-p", base_dir }, {}, function(err, message)
+ if err then
+ msg.fatal(string.format("failed to create plugin directory: %s", err))
+ return
+ end
+ end)
+end
+
+--- regiester a new package spec
+---@param spec table package spec from config
+---@return table package
+local function register_pkg(spec)
+ if type(spec) ~= "table" then
+ spec = { spec }
+ end
+
+ local id = spec[1]
+ local package = packages[id]
+
+ if not package then
+ package = {
+ id = id,
+ exists = false,
+ setup = false
+ }
+
+ packages[id] = package
+ end
+
+ package.name = string.sub(package.id, string.find(package.id, "%/") + 1, #package.id)
+ package.url = spec.url or ("https://github.com/"..package.id..".git")
+ package.branch = spec.branch
+ package.files = spec.files
+ package.dir = package.files and utils.join_path(base_dir, package.name) or utils.join_path(mp.command_native({ 'expand-path', "~~/scripts" }), package.name)
+ package.pin = spec.pin
+
+ package.exists = utils.file_info(package.dir) ~= nil
+ -- validate that all files have been installed
+ if type(package.files) == "table" then
+ for filename, dest in pairs(package.files) do
+ if not utils.file_info(utils.join_path(package.dir, filename)) or
+ not utils.file_info(utils.join_path(mp.command_native({ "expand-path", dest }), filename)) then
+ package.exists = false
+ break
+ end
+ end
+ end
+
+ package.on_setup = spec.setup
+
+ return package
+end
+
+--- run package setup
+---@param package table package
+local function setup_package(package)
+ if type(package.on_setup) ~= "function" then
+ return
+ end
+
+ local ok, err = pcall(package.on_setup, package.dir)
+ if not ok then
+ msg.warn(string.format("error when running setup on '%s': %s", package.id, err))
+ return
+ end
+ package.setup = true
+end
+
+--- copy all files according to package spec
+---@param package table package
+local function copy_files(package)
+ --- copy src to dest
+ ---@param src string path to src file
+ ---@param dest string path to dest file
+ local function cp(src, dest)
+ local i = io.open(src, 'r')
+ if not i then return end
+ local o = io.open(dest, 'w')
+ if not o then return end
+ o:write(i:read('*a'))
+ o:close()
+ i:close()
+ end
+
+ if type(package.files) == "table" then
+ for name, loc in pairs(package.files) do
+ local path = mp.command_native({'expand-path', loc})
+ local dest = utils.join_path(path, name)
+
+ local src = utils.join_path(package.dir, name)
+ if not utils.file_info(src) then
+ msg.warn(string.format("file %s not found", name))
+ return
+ end
+ local ok, err = pcall(cp, src, dest)
+ if not ok then
+ msg.warn(string.format("failed to copy %s: %s", name, utils.to_string(err)))
+ end
+ end
+ end
+end
+
+local function validate_package()
+end
+
+--- download or update package
+---@param package table package
+---@param cb function callback
+local function sync(package, cb)
+ if package.exists then
+ if package.pin then
+ cb()
+ return
+ end
+
+ --- generic error
+ ---@param err any error
+ local function log_err(err)
+ msg.error(string.format("failed to update %s; reason: %s", package.id, err))
+ end
+
+ -- get current head commit hash
+ proc.git_rev_parse(package.dir, "HEAD", function(err, before)
+ if err then
+ log_err(before)
+ cb(err)
+ return
+ end
+
+ -- get the latest commit hash
+ proc.git_fetch(package.dir, "origin", package.branch or "HEAD", function(err, message)
+ if err then
+ log_err(message)
+ cb(err)
+ return
+ end
+
+ -- check the latest and current against eachother
+ proc.git_rev_parse(package.dir, "FETCH_HEAD", function(err, after)
+ if err then
+ log_err(after)
+ cb(err)
+ return
+ elseif before == after then
+ msg.info(string.format("skipped %s", package.id))
+ cb(err)
+ return
+ end
+
+ -- switch HEAD to new commit
+ proc.git_reset(package.dir, after, function(err, message)
+ if err then
+ log_err(message)
+ return
+ end
+ setup_package(package)
+ copy_files(package)
+ msg.info(string.format("updated %s; %s -> %s", package.id, before, after))
+
+ cb(err)
+ end)
+ end)
+ end)
+ end)
+ else
+ -- clone repo since it doesn't exist
+ proc.git_clone(package.dir, package.url, package.branch, function(err, message)
+ if err then
+ msg.error(string.format("failed to install %s; reason: %s", package.id, utils.to_string(message)))
+ else
+ setup_package(package)
+ copy_files(package)
+ package.exists = true
+ msg.info(string.format("installed %s", package.id))
+ end
+
+ cb(err)
+ end)
+ end
+end
+
+--- sync a list of plugins
+---@param list table list of packages
+---@param cb function callback
+local function sync_list(list, cb)
+ local progress = 0
+
+ for i in pairs(list) do
+ sync(list[i], function()
+ progress = progress + 1
+ cb()
+ end)
+ end
+end
+
+--- check if package spec should be synced
+---@param package table package
+---@return boolean
+local function should_sync(package)
+ if config.sync == "new" or config.sync == nil then
+ return not package.exists
+ else
+ return config.sync == "always"
+ end
+end
+
+-- register all packages
+for i = 1, #config do
+ local ok, err = pcall(register_pkg, config[i])
+ if not ok then
+ msg.warn(string.format("%s: %s", err, config[i].as))
+ end
+end
+
+-- check for package updates
+local targets = {}
+for i in pairs(packages) do
+ if should_sync(packages[i]) then
+ targets[#targets + 1] = packages[i]
+ end
+end
+
+sync_list(targets, function() end)
+
+-- register script message for keybinding
+mp.register_script_message("eatit-sync", function(name, value)
+ sync_list(packages, function() end)
+end)