commit ccbcb236f1619a55597c6beeb21280b97464a7b1 Author: delta Date: Thu Dec 1 15:25:08 2022 +0100 this code is cursed diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..3e2f77f --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,649 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "memchr", +] + +[[package]] +name = "bulb" +version = "0.1.0" +dependencies = [ + "git2", + "lazy_static", + "lenient_semver", + "minreq", + "mlua", + "ron", + "semver", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" + +[[package]] +name = "cc" +version = "1.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "erased-serde" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54558e0ba96fbe24280072642eceb9d7d442e32c7ec0ea9e7ecd7b4ea2cf4e11" +dependencies = [ + "serde", +] + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "git2" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "jobserver" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lenient_semver" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de8de3f4f3754c280ce1c8c42ed8dd26a9c8385c2e5ad4ec5a77e774cea9c1ec" +dependencies = [ + "lenient_semver_parser", + "lenient_version", + "semver", +] + +[[package]] +name = "lenient_semver_parser" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f650c1d024ddc26b4bb79c3076b30030f2cf2b18292af698c81f7337a64d7d6" +dependencies = [ + "lenient_semver_version_builder", + "semver", +] + +[[package]] +name = "lenient_semver_version_builder" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9049f8ff49f75b946f95557148e70230499c8a642bf2d6528246afc7d0282d17" +dependencies = [ + "semver", +] + +[[package]] +name = "lenient_version" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad7b41cc0ad9b8a9f8d8fcb7c2ab6703a6da4b369cbb7e3a63ee0840769b4eb" +dependencies = [ + "lenient_semver_parser", + "lenient_semver_version_builder", + "serde", +] + +[[package]] +name = "libc" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" + +[[package]] +name = "libgit2-sys" +version = "0.14.0+1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47a00859c70c8a4f7218e6d1cc32875c4b55f6799445b842b0d8ed5e4c3d959b" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libssh2-sys" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lua-src" +version = "544.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "708ba3c844d5e9d38def4a09dd871c17c370f519b3c4b7261fbabe4a613a814c" +dependencies = [ + "cc", +] + +[[package]] +name = "luajit-src" +version = "210.4.3+resty8384278" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ee5d5afddf1ec76ffa55ca7c3001f2f8a703834beba53c56a38ea6641cef44" +dependencies = [ + "cc", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "minreq" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c785bc6027fd359756e538541c8624012ba3776d3d3fe123885643092ed4132" +dependencies = [ + "lazy_static", + "log", + "rustls", + "webpki", + "webpki-roots", +] + +[[package]] +name = "mlua" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4351dbcc863fb6249c81b3bd0c8001214e9d4d44d22cabda17026353a77fe612" +dependencies = [ + "bstr", + "cc", + "erased-serde", + "lua-src", + "luajit-src", + "mlua_derive", + "num-traits", + "once_cell", + "pkg-config", + "rustc-hash", + "serde", +] + +[[package]] +name = "mlua_derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9214e60d3cf1643013b107330fcd374ccec1e4ba1eef76e7e5da5e8202e71c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "ron" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff" +dependencies = [ + "base64", + "bitflags", + "serde", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustls" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "semver" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368bfe657969fb01238bb756d351dcade285e0f6fcbd36dcb23359a5169975be" +dependencies = [ + "webpki", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..5b462f0 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "bulb" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +git2 = "0.15.0" +minreq = { version = "2.6.0", features = [ "https" ] } +mlua = { version = "0.8.3", features = [ "vendored", "module", "lua54", "serialize" ] } +serde = { version = "1.0.147", features = ["derive"] } +ron = "0.8.0" +lazy_static = "1.4.0" +semver = { version = "1.0.14", features = [ "serde" ] } +lenient_semver = { version = "0.4.2", features = [ "version_serde" ] } +url = { version = "2.3.1", features = [ "serde" ] } +serde_json = "1.0.89" +# lenient_semver_range = { git = "https://github.com/knutwalker/lenient-semver-range" } + +[lib] +name = "bulb" +crate-type = ["cdylib"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..95fec24 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +

💡 lite-bulb

+

minimalist, vim-plug inspired plugin manager for lite-xl

diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..1f4d1cc --- /dev/null +++ b/init.lua @@ -0,0 +1,36 @@ +--mod-version:3 + +local config = require "core.config" +local common = require "core.common" +local core = require "core" + +package.cpath = package.cpath .. ";" .. USERDIR .. "/plugins/bulb/?.so" + +-- Globals +-- BULB_PLUGIN_DIR = USERDIR .. "/bulb-plugins" +-- BULB_CACHE_DIR = BULB_PLUGIN_DIR .. "/.cache" + +local bulb = require "libbulb" + +config.plugins.bulb = common.merge({ + repos = { + { + url = "https://github.com/lite-xl/lite-xl-plugins", + plugins = { + "plugin1", + "plugin2" + } + } + }, + clean_repos = false, + install_optionals = false +}, config.plugins.bulb) + +local quit_default = core.quit + +function core.quit() + -- bulb.state.clean() + quit_default() +end + +core.log(bulb.init(config.plugins.bulb)) diff --git a/libbulb.so b/libbulb.so new file mode 120000 index 0000000..46c666b --- /dev/null +++ b/libbulb.so @@ -0,0 +1 @@ +target/debug/libbulb.so \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..88dd006 --- /dev/null +++ b/manifest.json @@ -0,0 +1,17 @@ +{ + "plugins": [ + { + "name": "plugin1", + "description": "sus", + "version": "1.2.3" + }, + { + "name": "plugin2", + "description": "sus", + "version": "1.2.3", + "conflicts": { + "plugin1": {} + } + } + ] +} diff --git a/src/actions/install.rs b/src/actions/install.rs new file mode 100644 index 0000000..a2aab9d --- /dev/null +++ b/src/actions/install.rs @@ -0,0 +1,79 @@ +use mlua::prelude::*; +use url::Url; +use git2::Repository; +use std::{ + sync::{ + Mutex, + Arc + } +}; +use crate::{ + manifest::{ + Manifest, + Plugin + }, + globals::{ + BULB_CACHE_PATH, + MOD_VERSION + }, + errors::ErrorWrapper, + State, + Config +}; + +pub fn install(plugin_name: String, repo_url: Url, /*state_mutex: Arc>,*/ config_mutex: Arc>) -> LuaResult<()> { + let bulb_cache_path = BULB_CACHE_PATH.lock().unwrap(); + let mod_version = *MOD_VERSION.lock().unwrap(); + let repo_manifest = Manifest::parse("/home/delta/.config/lite-xl/plugins/bulb/manifest.json", repo_url)?; + //let state = STATE.lock().unwrap(); + let config = config_mutex.lock().unwrap(); + + + // If true, the repository isn't cached yet + // if !state.repos.contains(&repo_url) { + // Repository::clone(repo_url.as_str(), bulb_cache_path).map_err(ErrorWrapper)?; + // state.repos.push(repo_url.clone()); + // } + + // let repo_folder_name = repo_url.path_segments().unwrap().last().unwrap(); + // let mut repo_path = bulb_cache_path.clone(); + // repo_path.push(repo_folder_name); + // repo_manifest = Manifest::parse(repo_path, repo_url)?; + // repo_manifest = Manifest::parse("/home/delta/.config/lite-xl/plugins/bulb/manifest.json", repo_url)?; + println!("{:#?}", &repo_manifest); + + for plugin in repo_manifest.plugins { + println!(".name {}", plugin.name); + println!("_name {}", plugin_name); + if plugin.name == plugin_name { + match plugin.mod_version { + Some(version) => { + if version != mod_version { + return Err(LuaError::external(format!("[bulb] Failed to install plugin \"{}\": mod_version mismatch", plugin_name))); + } + }, + _ => {} + } + + match plugin.conflicts { + Some(conflicts) => { + for possible_conflict in conflicts.keys() { + for config_plugin in config.plugins.iter() { + println!("{}", &possible_conflict); + println!("{}", config_plugin); + + if &possible_conflict == config_plugin { + return Err(LuaError::external(format!("[bulb] Failed to install plugin \"{}\": plugin conflict detected with {}", plugin_name, possible_conflict))); + } + } + } + }, + _ => {} + } + + + } + } + + Ok(()) +} diff --git a/src/actions/mod.rs b/src/actions/mod.rs new file mode 100644 index 0000000..5e886ef --- /dev/null +++ b/src/actions/mod.rs @@ -0,0 +1,2 @@ +pub mod install; +pub mod update; diff --git a/src/actions/uninstall.rs b/src/actions/uninstall.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/actions/uninstall.rs @@ -0,0 +1 @@ + diff --git a/src/actions/update.rs b/src/actions/update.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..a87ce17 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,112 @@ +use serde::Deserialize; +use url::Url; +// use git2::Repository; +use std::{ + // fs::read_dir, + // path::PathBuf, + collections::HashSet, + sync::{ + Mutex, + Arc + } +}; +use crate::{ + globals::{ + BULB_CACHE_PATH + }, + state::State, + actions, + errors::ErrorWrapper +}; +use mlua::{ + prelude::{ + LuaResult, + LuaError, + LuaTable + }, + Lua, + LuaSerdeExt +}; + +#[allow(dead_code)] +#[derive(Deserialize, Debug, Clone, Hash, Eq, PartialEq)] +pub struct Repo { + url: Url, + plugins: Vec +} + +#[derive(Deserialize, Debug)] +// #[serde(transparent)] +pub struct Config<'c> { + pub repos: Vec, + pub clean_repos: bool, + pub install_optionals: bool, + + #[serde(skip)] + pub plugins: Vec<&'c String> +} + +pub struct ConfigLua<'lua> { + pub table: LuaTable<'lua>, + pub lua: &'lua Lua +} + +impl<'lua> TryFrom> for Config<'_> { + type Error = LuaError; + + fn try_from(config_lua: ConfigLua) -> LuaResult { + let config: Config = Lua::from_value(config_lua.lua, mlua::Value::Table(config_lua.table))?; + + Ok(config) + } +} + +impl<'c> Config<'c> { + pub fn parse(&'c mut self, state: State) -> LuaResult<()> { + let bulb_cache_path = BULB_CACHE_PATH.get_mut().unwrap(); + // let state = STATE.lock().unwrap(); + + let state_repos_hash: HashSet<_> = state.repos.iter().collect(); + let state_plugins_hash: HashSet<_> = state.plugins.iter().collect(); + let config_repos_hash: HashSet = self.repos.iter().map(|repo| repo.url.to_string()).collect(); + let config_plugins_hash: HashSet<_>; + + // let mut repo_clone = self.repos.clone(); + let config_plugins_vec: Vec<&'c String> = self.repos.iter() + .map(|repo| &repo.plugins) + .flatten() + .collect(); + + self.plugins = config_plugins_vec.clone(); + + config_plugins_hash = config_plugins_vec.iter().collect(); + + let config_mutex = Arc::new(Mutex::new(&self)); + + /*actions::install::install("plugin1".to_owned(), + Url::parse("https://github.com/lite-xl/lite-xl-plugins").map_err(ErrorWrapper)?, + config_mutex)?;*/ + + // Remove duplicate repos from state + // for repo_config in self.repos { + // state_diff.repos.remove(state_diff.repos.iter().position(|repo| repo == repo_config.url.as_str()).unwrap()); + + // for plugin_config in repo_config.plugins { + + // } + // } + + + + Ok(()) + } + + pub fn new() -> Self { + Self { + repos: Vec::new(), + clean_repos: false, + install_optionals: false, + plugins: Vec::new() + } + } +} diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..7e3b40c --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,49 @@ +use mlua::prelude::LuaError; +use ron::error::SpannedError; + +pub struct JsonError(pub serde_json::Error); +pub struct RonError(pub SpannedError); +// pub struct MutexError(pub PoisonError); +pub struct ErrorWrapper(pub E); + +impl From for JsonError { + fn from(err: serde_json::Error) -> Self { + Self(err) + } +} + +impl From for LuaError { + fn from(err: JsonError) -> Self { + LuaError::external(err.0) + } +} + +impl From for RonError { + fn from(err: ron::error::SpannedError) -> Self { + Self(err) + } +} + +impl From for LuaError { + fn from(err: RonError) -> Self { + LuaError::external(err.0) + } +} + +impl From for ErrorWrapper +where + E: std::error::Error + Send + Sync +{ + fn from(err: E) -> Self { + Self(err) + } +} + +impl From> for LuaError +where + E: std::error::Error + Send + Sync + 'static +{ + fn from(err: ErrorWrapper) -> Self { + LuaError::external(err.0) + } +} diff --git a/src/globals.rs b/src/globals.rs new file mode 100644 index 0000000..5b761a5 --- /dev/null +++ b/src/globals.rs @@ -0,0 +1,23 @@ +use lazy_static::lazy_static; +use std::{ + sync::{ + Mutex, + Once + }, + path::PathBuf +}; +use crate::{ + state::State, + config::Config +}; + +lazy_static! { + pub static ref BULB_PATH: Mutex = Mutex::new(PathBuf::new()); + pub static ref BULB_CACHE_PATH: Mutex = Mutex::new(PathBuf::new()); + pub static ref BULB_STATE_PATH: Mutex = Mutex::new(PathBuf::new()); + + pub static ref MOD_VERSION: Mutex<&'static str> = Mutex::new(""); + + // pub static ref STATE: Mutex = Mutex::new(State::new()); + // pub static ref CONFIG: Mutex> = Mutex::new(Config::new()); +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..9799a79 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,105 @@ +mod actions; +mod config; +mod state; +mod manifest; +mod globals; +mod errors; + +use mlua::prelude::*; +use std::{ + fs::{ + self, + File + }, + // path::{ + // Path, + // PathBuf + // } +}; +use crate::{ + config::{ + ConfigLua, + Config + }, + state::State, + globals::* +}; + +fn init(lua: &Lua, config_table: LuaTable) -> LuaResult<()> { + let bulb_state_path = BULB_STATE_PATH.get_mut().unwrap(); + + let config_lua = ConfigLua { + table: config_table, + lua + }; + + // let manifest = Manifest::parse( + // "/home/delta/.config/lite-xl/plugins/bulb/manifest.json", + // Url::parse("https://github.com/lite-xl/lite-xl-plugins").map_err(ErrorWrapper)? + // )?; + + let state = State::parse(bulb_state_path.to_owned())?; + + let mut config = Config::try_from(config_lua)?; + config.parse(state); + + Ok(()) + + // Ok(format!("{:#?}", config)) +} + +#[mlua::lua_module] +fn libbulb(lua: &Lua) -> LuaResult { + println!("1"); + let lua_globals = lua.globals(); + let user_dir: String = lua_globals.get("USERDIR")?; + let mut bulb_path = BULB_PATH.lock().unwrap(); + let mut bulb_cache_path = BULB_CACHE_PATH.lock().unwrap(); + let mut bulb_state_path = BULB_STATE_PATH.lock().unwrap(); + let mut mod_version = MOD_VERSION.lock().unwrap(); + + // Jank:tm: + // Taken from https://stackoverflow.com/a/30527289 + fn string_to_static_str(s: String) -> &'static str { + Box::leak(s.into_boxed_str()) + } + + bulb_path.push(user_dir); + bulb_path.push("bulb"); + + bulb_cache_path.push(bulb_path.clone()); + bulb_cache_path.push(".cache"); + + bulb_state_path.push(bulb_path.clone()); + bulb_state_path.push(".state.ron"); + + *mod_version = string_to_static_str(lua_globals.get("MOD_VERSION")?); + + println!("2"); + + //*state = State::parse(bulb_state_path.to_owned())?; + + println!("3"); + + if !bulb_path.exists() { + fs::create_dir(bulb_path.to_owned())?; + } + + if !bulb_state_path.exists() { + File::create(bulb_state_path.to_owned())?; + fs::write(bulb_state_path.to_owned(), "(plugins:[],repos:[])")?; + } + + if !bulb_cache_path.exists() { + fs::create_dir(bulb_cache_path.to_owned())?; + } + + let bulb = lua.create_table()?; + + bulb.set("init", lua.create_function(init)?)?; + // bulb.set("state", lua.create_userdata(*state)?)?; + + println!("4"); + + Ok(bulb) +} diff --git a/src/manifest.rs b/src/manifest.rs new file mode 100644 index 0000000..a7cb982 --- /dev/null +++ b/src/manifest.rs @@ -0,0 +1,89 @@ +#![allow(dead_code)] + +use semver::VersionReq; + +use crate::errors::JsonError; +use url::Url; +use serde::Deserialize; +use std::{ + collections::HashMap, + path::{ + PathBuf, + Path + }, + fs +}; +use mlua::prelude::{ + LuaResult, + LuaError +}; + + +#[derive(Deserialize, Debug)] +pub struct Manifest { + #[serde(skip, default = "default_url")] + pub url: Url, + pub plugins: Vec, + pub repos: Option> +} + +#[derive(Deserialize, Debug)] +pub struct PluginReference { + pub optional: Option, + pub version: Option +} + +#[derive(Deserialize, Debug)] +struct File { + pub url: Url, + pub checksum: String, + pub arch: String, + pub path: PathBuf +} + +#[derive(Deserialize, Debug)] +pub struct Plugin { + pub name: String, + pub description: String, + pub version: VersionReq, + pub mod_version: Option, + pub provides: Option>, + pub dependencies: Option>, + pub conflicts: Option>, + pub path: Option, + pub remote: Option, + pub url: Option, + pub checksum: Option, +} + +fn default_url() -> Url { + Url::parse("https://example.com").unwrap() +} + +impl Manifest { + pub fn parse

(path: P, url: Url) -> LuaResult + where + P: AsRef + { + let data = fs::read(path)?; + + let mut manifest: Manifest = serde_json::from_slice(data.as_slice()).map_err(JsonError)?; + + (&mut manifest).url = url; + + // Make sure that a plugin doesn't contain both 'url'/'checksum' and 'remote' + for p in manifest.plugins.iter() { + if p.url.is_some() && p.checksum.is_none() { + return Err(LuaError::external(format!("Could not parse manifest from {}!\nField 'url' depends on field 'checksum'", manifest.url))); + } else if p.url.is_none() && p.checksum.is_some() { + return Err(LuaError::external(format!("Could not parse manifest from {}!\nField 'checksum' depends on field 'url'", manifest.url))); + }; + + if p.remote.is_some() && p.url.is_some() { + return Err(LuaError::external(format!("Could not parse manifest from {}!\nConflicting fields 'remote' and 'url'", manifest.url))); + } + } + + Ok(manifest) + } +} diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..3aded43 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,65 @@ +use mlua::prelude::*; +use url::Url; +use ron::de::from_bytes; +use crate::{ + globals::BULB_STATE_PATH, + errors::RonError +}; +use serde::{ + Serialize, + Deserialize +}; +use std::{ + fs, + path::Path +}; + +#[derive(Serialize, Deserialize, Clone)] +pub struct State { + pub plugins: Vec, + pub repos: Vec +} + +impl State { + pub fn parse

(path: P) -> LuaResult + where + P: AsRef + { + let data = fs::read(path)?; + // let mut manifest: Manifest = serde_json::from_slice(data.as_slice()).map_err(JsonError)?; + let state = from_bytes(data.as_slice()).map_err(RonError)?; + + Ok(state) + } + + pub fn new() -> Self { + Self { + plugins: Vec::new(), + repos: Vec::new() + } + } + + pub fn clean(&self) { + fs::write( + BULB_STATE_PATH.lock().unwrap().to_owned(), + ron::to_string(self).unwrap() + ).expect("Couldn't write state"); + } + + // pub fn clean_lua(_: &Lua, this: &Self, (): ()) -> LuaResult<()> { + // this.clean(); + // Ok(()) + // } +} + +// impl LuaUserData for State { +// fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { +// methods.add_method("clean", State::clean_lua) +// } +// } + +impl Drop for State { + fn drop(&mut self) { + self.clean(); + } +} diff --git a/state-config_diff_model.md b/state-config_diff_model.md new file mode 100644 index 0000000..deddb86 --- /dev/null +++ b/state-config_diff_model.md @@ -0,0 +1,30 @@ ++-------+ +--------+ +| State | | Config | Phase 1 ++-------+ +--------+ + | || + V \/ ++-------+ +-------+ +| Repo1 | | Repo1 | +| Repo2 | | Repo2 | +| Repo3 | | Repo3 | +| Repo4 | | Repo5 | ++-------+ +-------+ + || + || Phase 1.5 + \/ ++-------+ +--------+ +| State | | Config | Phase 2 ++-------+ +--------+ + | || + V \/ ++-------+ +-------+ +| Repo1 | | Repo1 | +| Repo2 | | Repo2 | +| Repo3 | | Repo3 | +| Repo5 | | Repo5 | ++-------+ +-------+ + +Internally in phase 1.5, Config compares itself to State, removes keys that are in State and then installs plugins that are not in State +Config also modifies State by removing the keys that aren't in Config + +Note: Config never modifies itself or State manually, instead delegating that work to the install() and uninstall() functions