Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
e87ac7a437
|
|||
16f32bdcdd
|
@ -1,6 +1,6 @@
|
|||||||
Eat It - a Mpv plugin manager
|
Eat It - a Mpv plugin manager
|
||||||
|
|
||||||
Copyright © 2023 squibid
|
Copyright (c) 2024 squibid
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
70
README.md
70
README.md
@ -1,25 +1,63 @@
|
|||||||
# Eat It
|
# Eat It
|
||||||
Eat It is a plugin manager for mpv which allows you to declare what files you
|
Preface - eatit is a "plugin manager" for mpv it's sole purpose is to provide a
|
||||||
want from git repos.
|
declerative way to install and update your plugins. Loading the plugins is done
|
||||||
|
by mpv itself.
|
||||||
|
## Installation
|
||||||
|
put this script into your ~/.config/mpv/scripts/ directory:
|
||||||
|
```lua
|
||||||
|
-- install eat-it on startup
|
||||||
|
local mp = require("mp")
|
||||||
|
local utils = require("mp.utils")
|
||||||
|
local path = mp.command_native({ "expand-path", "~~/scripts/eat-it" })
|
||||||
|
|
||||||
## Installing Eat It
|
if not utils.readdir(path) then
|
||||||
|
mp.command_native_async({
|
||||||
|
name = "subprocess",
|
||||||
|
playback_only = false,
|
||||||
|
args = { "git", "clone", "--depth=1", "https://git.squi.bid/dep", path }
|
||||||
|
})
|
||||||
|
end
|
||||||
|
```
|
||||||
|
## Setup
|
||||||
|
in ~/.config/mpv/eatit-cfg.lua put:
|
||||||
|
```lua
|
||||||
|
return {
|
||||||
|
-- list of packages
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### Package Spec
|
||||||
|
```lua
|
||||||
|
{
|
||||||
|
-- [string] Specifies the full name of the package (required)
|
||||||
|
"user/package",
|
||||||
|
|
||||||
### First time
|
-- [string] Overrides the url of the git repo to clone
|
||||||
To install eatit run these two commands [Make sure you know what it does](https://explainshell.com/explain?cmd=curl+-L+https%3A%2F%2Fgit.squi.bid%2Feat-it%2Fplain%2Featit.lua+-o+~%2F.config%2Fmpv%2Fscripts%2Featit.lua+curl+-L+https%3A%2F%2Fgit.squi.bid%2Feat-it%2Fplain%2Featit-cfg.lua+-o+~%2F.config%2Fmpv%2Featit-cfg.lua):
|
-- by default eatit tries https://github.com/user/package.git
|
||||||
|
url = "",
|
||||||
curl -L https://git.squi.bid/eat-it/plain/eatit.lua -o ~/.config/mpv/scripts/eatit.lua
|
|
||||||
curl -L https://git.squi.bid/eat-it/plain/eatit-cfg.lua -o ~/.config/mpv/eatit-cfg.lua
|
|
||||||
|
|
||||||
### Bootstraping
|
-- [boolean] whether to ignore updates
|
||||||
The included bootstrap script will install and load eatit as soon as mpv starts.
|
pin = true,
|
||||||
|
|
||||||
|
-- [string] git branch to clone
|
||||||
|
branch = "",
|
||||||
|
|
||||||
|
-- [table] table of files to copy
|
||||||
|
files = {
|
||||||
|
[""] = ""
|
||||||
|
},
|
||||||
|
|
||||||
|
-- [function] code to run when installing/updating the package note due to how
|
||||||
|
-- mpv works eatit cannot change the working directory while running the setup
|
||||||
|
-- function
|
||||||
|
setup = function()
|
||||||
|
end
|
||||||
|
}
|
||||||
|
```
|
||||||
## FAQ
|
## FAQ
|
||||||
Q: Where does the name 'Eat It' come from?
|
Q: Where does the name "Eat It" come from?
|
||||||
A: The plugin manager eats all the useless files and keeps the ones you want,
|
A: The plugin manager eats all the useless files and keeps the ones you want,
|
||||||
*and Weird Al is a funny guy*
|
~~also a refrence to Weird Al's song "Eat It"~~
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
## ALTERNATIVES
|
## ALTERNATIVES
|
||||||
[email me](mailto:me@zacharyscheiman.com) if you know of any alternatives
|
[email me](mailto:me@zacharyscheiman.com) if you know of any other alternatives
|
||||||
|
|
||||||
- [mpv_manager](https://github.com/po5/mpv_manager)
|
- [mpv_manager](https://github.com/po5/mpv_manager)
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
os.execute('git clone https://git.squi.bid/eat-it /tmp/eatit-tmp')
|
|
||||||
local a = io.open('/tmp/eatit-tmp/eatit.lua', 'r')
|
|
||||||
local b = io.open(mp.command_native({'expand-path', '~~/scripts/eatit.lua'}), 'w')
|
|
||||||
b:write(a:read('*a'))
|
|
||||||
b:close()
|
|
||||||
a:close()
|
|
||||||
dofile(mp.command_native({'expand-path', '~~/scripts/eatit.lua'}))
|
|
||||||
os.execute('rm -rf /tmp/eatit-tmp')
|
|
@ -1,76 +0,0 @@
|
|||||||
--[[
|
|
||||||
Eat It - a Mpv plugin manager
|
|
||||||
|
|
||||||
Copyright © 2023 squibid
|
|
||||||
|
|
||||||
This program 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.
|
|
||||||
|
|
||||||
This program 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.
|
|
||||||
]]
|
|
||||||
|
|
||||||
-- NOTE: The variables in this file need to be global in order to be read
|
|
||||||
-- after being called with dofile()
|
|
||||||
|
|
||||||
plugins = { -- the plugins you want to load
|
|
||||||
{ 'squibid/eat-it', -- required, specifies the git repo
|
|
||||||
-- optional, sets repo link (see advanced example for more info on how to
|
|
||||||
-- use this)
|
|
||||||
url = 'https://git.squi.bid/eat-it',
|
|
||||||
|
|
||||||
-- required, specifies the desired file from the git repo
|
|
||||||
file = 'eatit.lua',
|
|
||||||
|
|
||||||
-- optional, sets the destination of the requested file
|
|
||||||
dir = 'scripts',
|
|
||||||
|
|
||||||
-- optional, sets the desired branch of the git repo
|
|
||||||
branch = 'master',
|
|
||||||
|
|
||||||
-- optional, stop the plugin from being updated
|
|
||||||
pin = false,
|
|
||||||
},
|
|
||||||
|
|
||||||
-- advanced example
|
|
||||||
{ 'gh:po5/thumbfast', -- expands to https://github.com/po5/thumbfast
|
|
||||||
file = { -- multiple files all going to the same place
|
|
||||||
'thumbfast.lua',
|
|
||||||
'osc.lua'
|
|
||||||
},
|
|
||||||
branch = 'ancient',
|
|
||||||
--[[
|
|
||||||
no need to specify dir as it defaults to ~~/scripts
|
|
||||||
no need to specify url as it is extrapolated from name
|
|
||||||
name expansion can be configured in the opts section
|
|
||||||
]]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
-- options for eat it
|
|
||||||
opts = {
|
|
||||||
bind = 'U',
|
|
||||||
logging = { -- options for logging
|
|
||||||
log = true,
|
|
||||||
logdate = '[%H:%M:%S]:',
|
|
||||||
logfile = '~~/eatit.log',
|
|
||||||
},
|
|
||||||
dl = { -- options for dealing with the git repos
|
|
||||||
dir = '/tmp/mpv-eatit',
|
|
||||||
powerwash = false, -- if true the download dir gets deleted after mpv closes
|
|
||||||
},
|
|
||||||
nameexp = {
|
|
||||||
pre = 'https://',
|
|
||||||
map = {
|
|
||||||
-- shortcut = link
|
|
||||||
gl = 'gitlab.com',
|
|
||||||
cb = 'codeberg.org',
|
|
||||||
sr = 'sr.ht',
|
|
||||||
gh = 'github.com'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
221
eatit.lua
221
eatit.lua
@ -1,221 +0,0 @@
|
|||||||
--[[
|
|
||||||
Eat It - a Mpv plugin manager
|
|
||||||
|
|
||||||
Copyright © 2023 squibid
|
|
||||||
|
|
||||||
This program 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.
|
|
||||||
|
|
||||||
This program 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.
|
|
||||||
]]
|
|
||||||
|
|
||||||
local mp = require('mp')
|
|
||||||
|
|
||||||
-- load the config file
|
|
||||||
dofile(mp.command_native({'expand-path', '~~/eatit-cfg.lua'}))
|
|
||||||
|
|
||||||
-- helper functions --
|
|
||||||
local function tablelength(T)
|
|
||||||
local count = 0
|
|
||||||
for _ in pairs(T) do count = count + 1 end
|
|
||||||
return count
|
|
||||||
end
|
|
||||||
|
|
||||||
local function fileexists(name)
|
|
||||||
local ok, err, code = os.rename(name, name)
|
|
||||||
if not ok then
|
|
||||||
if code == 13 then
|
|
||||||
-- Permission denied, but it exists
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return ok, err
|
|
||||||
end
|
|
||||||
|
|
||||||
local function testforslash(str)
|
|
||||||
if string.match(str, '/') then
|
|
||||||
return string.match(str, '/([^/]+)$')
|
|
||||||
else
|
|
||||||
return str
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function run(cmd)
|
|
||||||
local x = io.popen(cmd)
|
|
||||||
if not x then return 1 end
|
|
||||||
local y = x:read("*a")
|
|
||||||
x:close()
|
|
||||||
return y
|
|
||||||
end
|
|
||||||
|
|
||||||
local function cp(a, b)
|
|
||||||
local i = io.open(a, 'r')
|
|
||||||
if not i then return 1 end
|
|
||||||
local o = io.open(b, 'w')
|
|
||||||
if not o then return 2 end
|
|
||||||
o:write(i:read('*a'))
|
|
||||||
o:close()
|
|
||||||
i:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function getsrc(id)
|
|
||||||
local src
|
|
||||||
if string.find(id, ":") then src = id:match("^[a-z]+[^:]") end
|
|
||||||
local name = id:match([[[^:]*$]])
|
|
||||||
if name then
|
|
||||||
local pre = opts.nameexp.pre or "https://"
|
|
||||||
local map = opts.nameexp.map or {
|
|
||||||
gl = 'gitlab.com',
|
|
||||||
cb = 'codeberg.org',
|
|
||||||
sr = 'sr.ht',
|
|
||||||
gh = 'github.com'
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
link = (pre..map[src]) or false,
|
|
||||||
repo = name
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function openlog()
|
|
||||||
if opts.logging.log then -- log if asked to
|
|
||||||
-- get our logfile's full path
|
|
||||||
fn = mp.command_native({'expand-path', opts.logging.logfile})
|
|
||||||
|
|
||||||
f = io.open(fn, 'a') -- open file buffer
|
|
||||||
if not f then return 1 end
|
|
||||||
io.output(f) -- set it as default
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function logwrite(string)
|
|
||||||
if opts.logging.log then
|
|
||||||
io.write(os.date(opts.logging.logdate)..' '..string..'\n')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function closelog()
|
|
||||||
if opts.logging.log then
|
|
||||||
io.close(f)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get the requested git repos
|
|
||||||
local function clonegit(plugdir, url, branch)
|
|
||||||
logwrite('downloading '..url)
|
|
||||||
|
|
||||||
-- clone the repo
|
|
||||||
-- BUG: logwriting the git command doesn't actually log the output
|
|
||||||
run('git -C '..opts.dl.dir..' clone '..url..' '..plugdir)
|
|
||||||
run('git -C '..plugdir..' checkout -q '..branch)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- check for updates
|
|
||||||
local function checkupdates(plugdir)
|
|
||||||
local localhash = run('git -C '..plugdir..' log -1 --format=format:"%H"')
|
|
||||||
local remotehash = run('git -C '..plugdir..' rev-parse $(git -C '..
|
|
||||||
plugdir..' branch -r) | tail -1')
|
|
||||||
if localhash ~= remotehash then return true else return false end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- start install
|
|
||||||
local function startinstall(i)
|
|
||||||
local src = getsrc(plugins[i][1])
|
|
||||||
local plugin = { -- plugin table spec
|
|
||||||
id = plugins[i][1] or false,
|
|
||||||
url = plugins[i]['url'] or (src['link'].."/"..src['repo']),
|
|
||||||
file = plugins[i]['file'] or false,
|
|
||||||
dir = plugins[i]['dir'] or 'scripts',
|
|
||||||
pin = plugins[i]['pin'] or false,
|
|
||||||
branch = plugins[i]['branch'] or false,
|
|
||||||
}
|
|
||||||
|
|
||||||
-- check if the user has defined a file for the current plugin
|
|
||||||
if not plugin['file'] then
|
|
||||||
logwrite('WARNING! File not configured for '..plugin[1])
|
|
||||||
goto continue
|
|
||||||
end
|
|
||||||
-- skip install of pinned files
|
|
||||||
if plugin['pin'] == true then goto continue end
|
|
||||||
|
|
||||||
-- get the plugins tmp download dir
|
|
||||||
local plugdir = opts.dl.dir..'/'..testforslash(src['repo']):gsub('.git', '')
|
|
||||||
|
|
||||||
-- if no specified branch we use the default
|
|
||||||
plugin['branch'] = plugin['branch'] or testforslash(
|
|
||||||
run('git -C '..plugdir..' symbolic-ref refs/remotes/origin/HEAD')
|
|
||||||
)
|
|
||||||
|
|
||||||
-- check for multiple files
|
|
||||||
if type(plugin['file']) == 'string' then
|
|
||||||
plugin['file'] = {}
|
|
||||||
table.insert(plugin['file'], plugins[i]['file'])
|
|
||||||
end
|
|
||||||
|
|
||||||
-- get the requested file(s)
|
|
||||||
for j = 1, #plugin['file'] or 1 do
|
|
||||||
-- get the file's dir
|
|
||||||
local pluginfile = plugdir..'/'..plugin['file'][j]
|
|
||||||
|
|
||||||
-- get the dest dir
|
|
||||||
local destfile = mp.command_native({'expand-path', '~~/'})..
|
|
||||||
'/'..plugin['dir']..'/'..testforslash(plugin['file'][j])
|
|
||||||
|
|
||||||
if fileexists(plugdir..'/') then
|
|
||||||
-- if we need to update, update
|
|
||||||
if checkupdates(plugdir) then
|
|
||||||
logwrite(plugin['file'][j]..' is updating.')
|
|
||||||
-- make sure we are on the main branch
|
|
||||||
run('git -C '..plugdir..' checkout -q '..plugin['branch'])
|
|
||||||
run('git -C '..plugdir..' pull') -- get the latest commits
|
|
||||||
else
|
|
||||||
logwrite(plugin['file'][j]..' is up to date!')
|
|
||||||
end
|
|
||||||
else
|
|
||||||
clonegit(plugdir, plugin['url'], plugin['branch'])
|
|
||||||
end
|
|
||||||
|
|
||||||
-- copy the file contents over to the desired location
|
|
||||||
cp(pluginfile, destfile)
|
|
||||||
end
|
|
||||||
::continue::
|
|
||||||
end
|
|
||||||
|
|
||||||
local function initupdate()
|
|
||||||
openlog()
|
|
||||||
|
|
||||||
logwrite('# of plugins defined in table: '..tablelength(plugins))
|
|
||||||
os.execute('mkdir -p '..opts.dl.dir) -- make download dir
|
|
||||||
|
|
||||||
-- start the install process
|
|
||||||
logwrite('Starting Download...')
|
|
||||||
mp.osd_message('Downloading plugins!')
|
|
||||||
|
|
||||||
-- start iterating through plugins
|
|
||||||
for i = 1, tablelength(plugins) do
|
|
||||||
local f = coroutine.create(function() startinstall(i) end)
|
|
||||||
coroutine.resume(f)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- closing/removing everything
|
|
||||||
if opts.dl.powerwash == true then
|
|
||||||
logwrite('powerwashing the tmp dir "'..opts.dl.dir..'"')
|
|
||||||
os.execute('rm -rf '..opts.dl.dir)
|
|
||||||
end
|
|
||||||
|
|
||||||
closelog()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- remove logfile on startup
|
|
||||||
if opts.logging.log then
|
|
||||||
openlog()
|
|
||||||
os.remove(fn)
|
|
||||||
closelog()
|
|
||||||
end
|
|
||||||
|
|
||||||
mp.add_key_binding(opts.bind, 'UpdatePlugins', initupdate)
|
|
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)
|
@ -1,28 +0,0 @@
|
|||||||
# Modules
|
|
||||||
Modules are extentions to the EatIt plugin manager that aren't necessary for
|
|
||||||
running it. Every module will be in it's own sub directory in order to keep
|
|
||||||
documentation relative to the individual modules.
|
|
||||||
|
|
||||||
## List of modules
|
|
||||||
- `lssi.lua` Lua Script Script Injector for modifing files post install
|
|
||||||
|
|
||||||
## Installing
|
|
||||||
Installing a module can be done through EatIt like so:
|
|
||||||
```lua
|
|
||||||
plugins = { -- the plugins you want to load
|
|
||||||
{ 'https://git.squi.bid/eat-it',
|
|
||||||
file = 'modules/moddir/module.lua',
|
|
||||||
dir = 'scripts',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## For Devs
|
|
||||||
Please add a table in the global scope called 'mod' as this may be used in the
|
|
||||||
future. It should look like this:
|
|
||||||
```lua
|
|
||||||
mod = {
|
|
||||||
version = 'version',
|
|
||||||
author = 'autor name',
|
|
||||||
}
|
|
||||||
```
|
|
@ -1,16 +0,0 @@
|
|||||||
# Using lssi
|
|
||||||
Any plugin can be modified by lssi by doing the following in the eatit-cfg.lua:
|
|
||||||
```lua
|
|
||||||
plugins = { -- the plugins you want to load
|
|
||||||
{ 'https://git.squi.bid/eat-it',
|
|
||||||
file = 'eatit.lua',
|
|
||||||
dir = 'scripts',
|
|
||||||
lssi = {
|
|
||||||
-- code line
|
|
||||||
{ 'print("hello world")', 'G' },
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
The line option can be 'g' for top of file, 'G' for bottom of file, or any
|
|
||||||
number in between.
|
|
@ -1,133 +0,0 @@
|
|||||||
--[[
|
|
||||||
Eat It - a Mpv plugin manager
|
|
||||||
|
|
||||||
Copyright © 2023 squibid
|
|
||||||
|
|
||||||
This program 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.
|
|
||||||
|
|
||||||
This program 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.
|
|
||||||
]]
|
|
||||||
|
|
||||||
-- NOTE: This is a POC and will most likely be reimplimented using diff files
|
|
||||||
-- with git
|
|
||||||
-- or we might want to generate a diff file from the requested changes
|
|
||||||
-- and check if the diffs match in content
|
|
||||||
|
|
||||||
--[[
|
|
||||||
Lua Script Script Injector
|
|
||||||
Takes an input file and code then, it outputs a file with your code in there.
|
|
||||||
]]--
|
|
||||||
|
|
||||||
local mp = require('mp')
|
|
||||||
|
|
||||||
mod = {
|
|
||||||
version = 'ALPHA 1.1', -- the current version of lssi
|
|
||||||
author = 'squibid',
|
|
||||||
}
|
|
||||||
|
|
||||||
-- load the eatit config file
|
|
||||||
dofile(mp.command_native({'expand-path', '~~/eatit-cfg.lua'}))
|
|
||||||
|
|
||||||
-- helper functions
|
|
||||||
local function tablelength(T)
|
|
||||||
local count = 0
|
|
||||||
for _ in pairs(T) do count = count + 1 end
|
|
||||||
return count
|
|
||||||
end
|
|
||||||
|
|
||||||
local function fileexists(name)
|
|
||||||
local f = io.open(name, 'r')
|
|
||||||
if f ~= nil then io.close(f) return true else return false end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function logwrite(string)
|
|
||||||
if opts.logging.log then
|
|
||||||
io.write(os.date(opts.logging.logdate)..' '..string..'\n')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function openlog()
|
|
||||||
if opts.logging.log then -- log if asked to
|
|
||||||
-- get our logfile's full path
|
|
||||||
fn = mp.command_native({'expand-path', opts.logging.logfile})
|
|
||||||
|
|
||||||
f = io.open(fn, 'a') -- open file buffer
|
|
||||||
if not f then return end
|
|
||||||
io.output(f) -- set it as default
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function closelog()
|
|
||||||
if opts.logging.log then
|
|
||||||
io.close(f)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function inject(infile, l, outfile)
|
|
||||||
local inf = io.open(infile, 'r')
|
|
||||||
local infcont = {}
|
|
||||||
for i in inf:lines() do
|
|
||||||
table.insert(infcont, i)
|
|
||||||
end
|
|
||||||
inf:close()
|
|
||||||
|
|
||||||
-- don't do anything if there is already code injected into the file
|
|
||||||
if string.find(infcont[1], "-- code injected by lssi") then
|
|
||||||
logwrite('code is already injected into '..infile)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
logwrite('Injecting code into '..infile)
|
|
||||||
|
|
||||||
for i in pairs(l) do
|
|
||||||
-- add requested line below existing line
|
|
||||||
if l[i][2] == 'G' then
|
|
||||||
infcont[tablelength(infcont)] = infcont[tablelength(infcont)]..'\n'..l[i][1]
|
|
||||||
elseif l[i][2] == 'g' then
|
|
||||||
infcont[1] = l[i][1]..'\n'..infcont[1]
|
|
||||||
else
|
|
||||||
infcont[l[i][2]] = (infcont[l[i][2]])..'\n'..l[i][1]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local outf = io.open(outfile, 'w')
|
|
||||||
|
|
||||||
-- we inject metadata to prevent writing to the file more than once
|
|
||||||
infcont[1] = "-- code injected by lssi "..mod.version..'\n'..infcont[1]
|
|
||||||
for i, v in ipairs(infcont) do
|
|
||||||
outf:write(v..'\n')
|
|
||||||
end
|
|
||||||
|
|
||||||
io.close(outf)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function checkandinject()
|
|
||||||
openlog()
|
|
||||||
|
|
||||||
for i = 1, tablelength(plugins) do
|
|
||||||
-- check if the plugin has been configured with lssi
|
|
||||||
if plugins[i]['lssi'] ~= nil then
|
|
||||||
-- get the file we want to inject our code into
|
|
||||||
local f = mp.command_native({'expand-path', '~~/'}) ..
|
|
||||||
'/'..(plugins[i]['dir'] or 'scripts') ..
|
|
||||||
'/'..plugins[i]['file']
|
|
||||||
-- and the file we are trying to modify actually exists
|
|
||||||
if fileexists(f) then
|
|
||||||
-- inject it! no going back now
|
|
||||||
inject(f, plugins[i]['lssi'], f)
|
|
||||||
else
|
|
||||||
logwrite('Failed to inject code into "' ..
|
|
||||||
plugins[i]['file']..'" file does not exist')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
closelog()
|
|
||||||
end
|
|
||||||
|
|
||||||
checkandinject()
|
|
85
proc.lua
Normal file
85
proc.lua
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
-- Copyright (c) 2024 squibid, see LICENSE file for more info
|
||||||
|
local mp = require('mp')
|
||||||
|
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
--- run a system binary
|
||||||
|
---@param args table command with it's options
|
||||||
|
---@param env table key value pair of envvars
|
||||||
|
---@param cb function callback
|
||||||
|
function M.exec(args, env, cb)
|
||||||
|
local res_env = {}
|
||||||
|
for i, v in pairs(env) do
|
||||||
|
res_env[#res_env + 1] = i.."="..v
|
||||||
|
end
|
||||||
|
|
||||||
|
--- run callback
|
||||||
|
---@param success boolean if the command ran successfully
|
||||||
|
---@param result table|nil results
|
||||||
|
---@param error string|nil error string or nil
|
||||||
|
local function callback(success, result, error)
|
||||||
|
local output
|
||||||
|
if result then
|
||||||
|
-- combine both stdout and stderr
|
||||||
|
output = result.stdout..result.stderr
|
||||||
|
end
|
||||||
|
cb(not success, output)
|
||||||
|
end
|
||||||
|
|
||||||
|
mp.command_native_async({
|
||||||
|
name = "subprocess",
|
||||||
|
playback_only = false,
|
||||||
|
capture_stdout = true,
|
||||||
|
capture_stderr = true,
|
||||||
|
env = res_env,
|
||||||
|
args = args
|
||||||
|
}, callback)
|
||||||
|
end
|
||||||
|
|
||||||
|
---@type table git environment
|
||||||
|
local git_env = { GIT_TERMINAL_PROMPT = 0 }
|
||||||
|
|
||||||
|
--- git rev parse
|
||||||
|
---@param dir string directory
|
||||||
|
---@param arg string arg
|
||||||
|
---@param cb function callback
|
||||||
|
function M.git_rev_parse(dir, arg, cb)
|
||||||
|
local cmd = { "git", "-C", dir, "rev-parse", "--short", arg }
|
||||||
|
M.exec(cmd, git_env, cb)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- git clone
|
||||||
|
---@param dir string directory
|
||||||
|
---@param url string url
|
||||||
|
---@param branch string branch
|
||||||
|
---@param cb function callback
|
||||||
|
function M.git_clone(dir, url, branch, cb)
|
||||||
|
local cmd = { "git", "clone", "--depth=1", "--recurse-submodules", "--shallow-submodules", url, dir }
|
||||||
|
|
||||||
|
if branch then
|
||||||
|
cmd[#cmd + 1] = "--branch="..branch
|
||||||
|
end
|
||||||
|
|
||||||
|
M.exec(cmd, git_env, cb)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- git fetch
|
||||||
|
---@param dir string directory
|
||||||
|
---@param remote string remote
|
||||||
|
---@param refspec string refspec
|
||||||
|
---@param cb function callback
|
||||||
|
function M.git_fetch(dir, remote, refspec, cb)
|
||||||
|
local cmd = { "git", "-C", dir, "fetch", "--depth=1", "--recurse-submodules", remote, refspec }
|
||||||
|
M.exec(cmd, git_env, cb)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- git reset
|
||||||
|
---@param dir string dir
|
||||||
|
---@param treeish string treeish
|
||||||
|
---@param cb function callback
|
||||||
|
function M.git_reset(dir, treeish, cb)
|
||||||
|
local cmd = { "git", "-C", dir, "reset", "--hard", "--recurse-submodules", treeish, "--" }
|
||||||
|
M.exec(cmd, git_env, cb)
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
Reference in New Issue
Block a user