aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--LICENSE (renamed from LISCENSE)2
-rw-r--r--README.md70
-rw-r--r--bootstrap.lua8
-rw-r--r--eatit-cfg.lua76
-rw-r--r--eatit.lua221
-rw-r--r--main.lua247
-rw-r--r--modules/README.md28
-rw-r--r--modules/lssi/LSSI.md16
-rw-r--r--modules/lssi/lssi.lua133
-rw-r--r--proc.lua85
10 files changed, 387 insertions, 499 deletions
diff --git a/LISCENSE b/LICENSE
index 7a5b006..7359842 100644
--- a/LISCENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
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
it under the terms of the GNU General Public License as published by
diff --git a/README.md b/README.md
index 8d86744..c52bd30 100644
--- a/README.md
+++ b/README.md
@@ -1,25 +1,63 @@
# Eat It
-Eat It is a plugin manager for mpv which allows you to declare what files you
-want from git repos.
+Preface - eatit is a "plugin manager" for mpv it's sole purpose is to provide a
+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.comand_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
-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):
-
-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
+ -- [string] Overrides the url of the git repo to clone
+ -- by default eatit tries https://github.com/user/package.git
+ url = "",
-### Bootstraping
-The included bootstrap script will install and load eatit as soon as mpv starts.
-## FAQ
-Q: Where does the name 'Eat It' come from?
-A: The plugin manager eats all the useless files and keeps the ones you want,
-*and Weird Al is a funny guy*
+ -- [boolean] whether to ignore updates
+ pin = true,
+
+ -- [string] git branch to clone
+ branch = "",
-## TODO
+ -- [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
+Q: Where does the name "Eat It" come from?
+A: The plugin manager eats all the useless files and keeps the ones you want,
+~~also a refrence to Weird Al's song "Eat It"~~
## 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)
diff --git a/bootstrap.lua b/bootstrap.lua
deleted file mode 100644
index 89b62fb..0000000
--- a/bootstrap.lua
+++ /dev/null
@@ -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')
diff --git a/eatit-cfg.lua b/eatit-cfg.lua
deleted file mode 100644
index 1b28bfc..0000000
--- a/eatit-cfg.lua
+++ /dev/null
@@ -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'
- }
- }
-}
diff --git a/eatit.lua b/eatit.lua
deleted file mode 100644
index b18e56d..0000000
--- a/eatit.lua
+++ /dev/null
@@ -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)
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)
diff --git a/modules/README.md b/modules/README.md
deleted file mode 100644
index 614a9b2..0000000
--- a/modules/README.md
+++ /dev/null
@@ -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',
-}
-```
diff --git a/modules/lssi/LSSI.md b/modules/lssi/LSSI.md
deleted file mode 100644
index 5bcd65d..0000000
--- a/modules/lssi/LSSI.md
+++ /dev/null
@@ -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.
diff --git a/modules/lssi/lssi.lua b/modules/lssi/lssi.lua
deleted file mode 100644
index 21f9536..0000000
--- a/modules/lssi/lssi.lua
+++ /dev/null
@@ -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()
diff --git a/proc.lua b/proc.lua
new file mode 100644
index 0000000..306cb2e
--- /dev/null
+++ b/proc.lua
@@ -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