complete refactor see README for more info
This commit is contained in:
247
main.lua
Normal file
247
main.lua
Normal file
@ -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)
|
Reference in New Issue
Block a user