initial
This commit is contained in:
commit
60985236c7
16 changed files with 2405 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
target
|
971
Cargo.lock
generated
Normal file
971
Cargo.lock
generated
Normal file
|
@ -0,0 +1,971 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"humantime",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fda788993cc341f69012feba8bf45c0ba4f3291fcc08e214b4d5a7332d88aff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
"libgit2-sys",
|
||||
"log",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"litemap",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_locid_transform_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_locid_transform_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_normalizer_data",
|
||||
"icu_properties",
|
||||
"icu_provider",
|
||||
"smallvec",
|
||||
"utf16_iter",
|
||||
"utf8_iter",
|
||||
"write16",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_normalizer_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
"icu_locid_transform",
|
||||
"icu_properties_data",
|
||||
"icu_provider",
|
||||
"tinystr",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_locid",
|
||||
"icu_provider_macros",
|
||||
"stable_deref_trait",
|
||||
"tinystr",
|
||||
"writeable",
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider_macros"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
|
||||
dependencies = [
|
||||
"idna_adapter",
|
||||
"smallvec",
|
||||
"utf8_iter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna_adapter"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
|
||||
dependencies = [
|
||||
"icu_normalizer",
|
||||
"icu_properties",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iris"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"env_logger",
|
||||
"git2",
|
||||
"log",
|
||||
"serde",
|
||||
"thiserror 2.0.10",
|
||||
"toml",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.18.0+1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1a117465e7e1597e8febea8bb0c410f1c7fb93b1e1cddf34363f8390367ffec"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"libssh2-sys",
|
||||
"libz-sys",
|
||||
"openssl-sys",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libssh2-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"libz-sys",
|
||||
"openssl-sys",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[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.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libredox",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3ac7f54ca534db81081ef1c1e7f6ea8a3ef428d2fc069097c079443d24124d3"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e9465d30713b56a37ede7185763c3492a91be2f5fa68d958c44e41ab9248beb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf16_iter"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
|
||||
|
||||
[[package]]
|
||||
name = "utf8_iter"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39281189af81c07ec09db316b302a3e67bf9bd7cbf6c820b50e35fee9c2fa980"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "write16"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"stable_deref_trait",
|
||||
"yoke-derive",
|
||||
"zerofrom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yoke-derive"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
|
||||
dependencies = [
|
||||
"zerofrom-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerofrom-derive"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
|
||||
dependencies = [
|
||||
"yoke",
|
||||
"zerofrom",
|
||||
"zerovec-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerovec-derive"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
24
Cargo.toml
Normal file
24
Cargo.toml
Normal file
|
@ -0,0 +1,24 @@
|
|||
[package]
|
||||
name = "iris"
|
||||
version = "0.1.0"
|
||||
authors = ["Freya Murphy <contact@freyacat.org>"]
|
||||
edition = "2021"
|
||||
description = "A locking plugin manager for vim"
|
||||
license-file = "LICENSE"
|
||||
|
||||
[lints.rust]
|
||||
unsafe_code = "forbid"
|
||||
|
||||
[lints.clippy]
|
||||
all = "warn"
|
||||
nursery = "warn"
|
||||
|
||||
[dependencies]
|
||||
dirs = "5"
|
||||
env_logger = "0.11.6"
|
||||
git2 = "0.20"
|
||||
log = "0.4"
|
||||
serde = "1"
|
||||
thiserror = "2"
|
||||
toml = "0.8"
|
||||
url = "2"
|
165
LICENSE
Normal file
165
LICENSE
Normal file
|
@ -0,0 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
7
rustfmt.toml
Normal file
7
rustfmt.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
hard_tabs = true
|
||||
tab_spaces = 4
|
||||
max_width = 80
|
||||
|
||||
use_field_init_shorthand = true
|
||||
|
||||
|
49
src/error.rs
Normal file
49
src/error.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
//! Definition of an iris [error][Error].
|
||||
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
macro_rules! error {
|
||||
($($arg:tt)*) => {
|
||||
$crate::error::Error::new(format!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use error;
|
||||
|
||||
/// Errors that can occur in iris
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
/// Occurs when a file could not be read, or could not be written to.
|
||||
#[error(transparent)]
|
||||
Io(#[from] io::Error),
|
||||
/// Occurs when an error was raised from the local git repository
|
||||
#[error(transparent)]
|
||||
Git(#[from] git2::Error),
|
||||
/// Occurs when iris failed to convert its internal structures into the
|
||||
/// config string representation.
|
||||
#[error(transparent)]
|
||||
De(#[from] crate::parse::de::Error),
|
||||
/// Occurs when a provided string representation of an iris structure is
|
||||
/// invalid and could not be converted/parsed.
|
||||
#[error(transparent)]
|
||||
Ser(#[from] crate::parse::ser::Error),
|
||||
/// Generic error message, occurs anywhere
|
||||
#[error("{0}")]
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn new(fmt: impl fmt::Display) -> Self {
|
||||
Self::Custom(fmt.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Error {
|
||||
fn from(msg: &str) -> Self {
|
||||
Self::new(msg)
|
||||
}
|
||||
}
|
||||
|
||||
/// iris result type
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
52
src/lib.rs
Normal file
52
src/lib.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
//! # Iris
|
||||
//! A locking plugin manager for vim
|
||||
|
||||
mod model;
|
||||
pub use model::{config::Config, plugin::Plugin, repo::Repository};
|
||||
|
||||
mod parse;
|
||||
|
||||
mod error;
|
||||
pub use error::{Error, Result};
|
||||
|
||||
pub mod path;
|
||||
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufWriter, Write},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
/// Iris copyright header prepended to all generated files
|
||||
const COPYRIGHT_HEADER: &str = "\
|
||||
IRIS - A locking plugin manager for vim
|
||||
Copyright © 2025 Freya Murphy <contact@freyacat.org>
|
||||
|
||||
This file is part of IRIS
|
||||
|
||||
IRIS 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.
|
||||
|
||||
IRIS 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with IRIS. If not, see <http://www.gnu.org/licenses/>.";
|
||||
|
||||
/// Opens file writer at `path` with copyright header already written
|
||||
pub(crate) fn get_writer<P>(path: P, c: char) -> Result<BufWriter<File>>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let file = File::create(path)?;
|
||||
let mut w = BufWriter::new(file);
|
||||
for line in COPYRIGHT_HEADER.lines() {
|
||||
writeln!(w, "{c}{c}{c} {line}")?;
|
||||
}
|
||||
writeln!(w)?;
|
||||
Ok(w)
|
||||
}
|
193
src/main.rs
Normal file
193
src/main.rs
Normal file
|
@ -0,0 +1,193 @@
|
|||
//! # Iris
|
||||
//! A locking plugin manager for vim
|
||||
|
||||
use iris::{Config, Result};
|
||||
use log::info;
|
||||
use std::{env, process::exit};
|
||||
|
||||
const USAGE: &str = "\
|
||||
Usage: iris [OPTION]... COMMAND [FILE}";
|
||||
|
||||
const HELP: &str = "\
|
||||
A locking plugin manager for vim
|
||||
|
||||
Commands:
|
||||
switch checkout plugins using their current refs and generate autoload
|
||||
file
|
||||
lock update plugin refs to point to the latest commit
|
||||
|
||||
Options:
|
||||
-v, --verbose enable verbose output
|
||||
-q, --quiet disable output
|
||||
-h, --help print the help message
|
||||
-V, --version print the program version
|
||||
";
|
||||
|
||||
/// print the program version
|
||||
fn version() -> ! {
|
||||
println!("iris {}", env!("CARGO_PKG_VERSION"));
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/// print the program's usage
|
||||
fn usage() -> ! {
|
||||
eprintln!("{USAGE}");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/// print the program's help message
|
||||
fn help() -> ! {
|
||||
println!("{USAGE}\n{HELP}");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
struct Options {
|
||||
/// the command to run
|
||||
command: String,
|
||||
/// the file to load instead of defaults
|
||||
file: Option<String>,
|
||||
/// print verbose output
|
||||
verbose: bool,
|
||||
/// silence output
|
||||
quiet: bool,
|
||||
}
|
||||
|
||||
// parse options
|
||||
fn opts() -> Options {
|
||||
let mut args = env::args().into_iter().peekable();
|
||||
let mut quiet = false;
|
||||
let mut verbose = false;
|
||||
|
||||
// skip program name
|
||||
_ = args.next();
|
||||
|
||||
// options
|
||||
while let Some(arg) = args.peek() {
|
||||
// arg is not an option
|
||||
if !arg.starts_with("-") {
|
||||
break;
|
||||
};
|
||||
// grab next
|
||||
let arg = args.next().expect("no arg?!");
|
||||
|
||||
match arg.as_str() {
|
||||
// stop parsing options
|
||||
"--" => break,
|
||||
// quiet
|
||||
"-q" | "--quiet" => {
|
||||
quiet = true;
|
||||
}
|
||||
// verbose
|
||||
"-v" | "--verbose" => {
|
||||
verbose = true;
|
||||
}
|
||||
// version
|
||||
"-V" | "--version" => version(),
|
||||
// help
|
||||
"-h" | "--help" => help(),
|
||||
// invalid
|
||||
_ => {
|
||||
eprintln!("invalid options: '{arg}'");
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// command
|
||||
let Some(command) = args.next() else {
|
||||
usage();
|
||||
};
|
||||
|
||||
// file
|
||||
let file = args.next();
|
||||
|
||||
// force end of arguments
|
||||
if args.next().is_some() {
|
||||
usage();
|
||||
};
|
||||
|
||||
Options {
|
||||
command,
|
||||
file,
|
||||
quiet,
|
||||
verbose,
|
||||
}
|
||||
}
|
||||
|
||||
fn log(opts: &Options) {
|
||||
if !opts.quiet {
|
||||
let level = if opts.verbose {
|
||||
log::LevelFilter::Trace
|
||||
} else {
|
||||
log::LevelFilter::Info
|
||||
};
|
||||
|
||||
env_logger::Builder::from_default_env()
|
||||
.filter_level(level)
|
||||
.format_timestamp(None)
|
||||
.format_module_path(false)
|
||||
.format_source_path(false)
|
||||
.init();
|
||||
}
|
||||
}
|
||||
|
||||
fn switch(opts: &Options) -> Result<()> {
|
||||
let cfg = match &opts.file {
|
||||
Some(path) => Config::read_from_file(path),
|
||||
None => Config::read_from_lock_file()
|
||||
.or_else(|_| Config::read_from_plugin_file()),
|
||||
}?;
|
||||
|
||||
for plugin in &cfg.plugins {
|
||||
plugin.switch()?;
|
||||
info!("switched {}", plugin.id);
|
||||
}
|
||||
|
||||
cfg.write_autoload_file()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lock(opts: &Options) -> Result<()> {
|
||||
let mut cfg = match &opts.file {
|
||||
Some(path) => Config::read_from_file(path),
|
||||
None => Config::read_from_plugin_file(),
|
||||
}?;
|
||||
|
||||
for plugin in &mut cfg.plugins {
|
||||
plugin.lock()?;
|
||||
info!("locked {}", plugin.id);
|
||||
}
|
||||
|
||||
// save lock file
|
||||
cfg.write_to_lock_file()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn inner() -> Result<()> {
|
||||
// parse opts
|
||||
let opts = opts();
|
||||
|
||||
// initalize logger (if not quiet)
|
||||
log(&opts);
|
||||
|
||||
// handle command
|
||||
match opts.command.as_str() {
|
||||
"switch" => switch(&opts)?,
|
||||
"lock" => lock(&opts)?,
|
||||
cmd => {
|
||||
eprintln!("unknown command: '{cmd}'");
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if let Err(err) = inner() {
|
||||
log::error!("{err}");
|
||||
exit(1);
|
||||
}
|
||||
}
|
110
src/model/config.rs
Normal file
110
src/model/config.rs
Normal file
|
@ -0,0 +1,110 @@
|
|||
//! Definition of an iris [config][Config].
|
||||
|
||||
use crate::{get_writer, path, Plugin, Result};
|
||||
|
||||
use log::trace;
|
||||
use std::{fs, io::Write, path::Path};
|
||||
|
||||
/// Iris config
|
||||
#[derive(Debug)]
|
||||
pub struct Config {
|
||||
/// List of iris plugin specifications
|
||||
pub plugins: Vec<Plugin>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Read an iris config from the file system
|
||||
pub fn read_from_file<P>(path: P) -> Result<Self>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
trace!("reading: {}", path.as_ref().display());
|
||||
let contents = fs::read_to_string(&path)?;
|
||||
let iris = Self::parse(&contents)?;
|
||||
Ok(iris)
|
||||
}
|
||||
|
||||
/// Read an iris config from the plugin file path
|
||||
pub fn read_from_plugin_file() -> Result<Self> {
|
||||
trace!("read from plugin file");
|
||||
Self::read_from_file(path::plugin_file())
|
||||
}
|
||||
|
||||
/// Read an iris config from the lock file path
|
||||
pub fn read_from_lock_file() -> Result<Self> {
|
||||
trace!("read from lock file");
|
||||
Self::read_from_file(path::lock_file())
|
||||
}
|
||||
|
||||
/// Write the iris config to the file system.
|
||||
pub fn write_to_file<P>(&self, path: P) -> Result<()>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
trace!("writing: {}", path.as_ref().display());
|
||||
let contents = self.to_string()?;
|
||||
let mut write = get_writer(&path, '#')?;
|
||||
write.write_all(contents.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write the iris config to the plugins file.
|
||||
pub fn write_to_plugin_file(&self) -> Result<()> {
|
||||
self.write_to_file(path::plugin_file())
|
||||
}
|
||||
|
||||
/// Write the iris config to the lock file.
|
||||
pub fn write_to_lock_file(&self) -> Result<()> {
|
||||
self.write_to_file(path::lock_file())
|
||||
}
|
||||
|
||||
/// Write the vim autoload file formed from each plugin.
|
||||
pub fn write_autoload_file(&self) -> Result<()> {
|
||||
let path = path::autoload_file();
|
||||
trace!("writing: {}", path.display());
|
||||
|
||||
let mut f = get_writer(&path, '"')?;
|
||||
|
||||
// BEGIN iris#load
|
||||
writeln!(f, "function! iris#load()")?;
|
||||
// add each plugin to load path
|
||||
for plugin in &self.plugins {
|
||||
// runtime path
|
||||
{
|
||||
let path = plugin.runtime_path().display();
|
||||
writeln!(f, "set runtimepath+={path}")?;
|
||||
}
|
||||
// lua package path
|
||||
if let Some(path) = plugin.lua_package_path() {
|
||||
let path = path.display();
|
||||
writeln!(f, "lua package.path = package.path .. \";{path}\"")?;
|
||||
}
|
||||
// vim source file
|
||||
if let Some(path) = plugin.vim_source_file() {
|
||||
let path = path.display();
|
||||
writeln!(f, "source {path}")?;
|
||||
}
|
||||
// lua source file
|
||||
if let Some(path) = plugin.lua_source_file() {
|
||||
let path = path.display();
|
||||
writeln!(f, "lua dofile('{path}')")?;
|
||||
}
|
||||
}
|
||||
for plugin in &self.plugins {
|
||||
// vim source after file
|
||||
if let Some(path) = plugin.vim_source_after_file() {
|
||||
let path = path.display();
|
||||
writeln!(f, "source {path}")?;
|
||||
}
|
||||
// lua source after file
|
||||
if let Some(path) = plugin.lua_source_after_file() {
|
||||
let path = path.display();
|
||||
writeln!(f, "lua dofile('{path}')")?;
|
||||
}
|
||||
}
|
||||
writeln!(f, "endfunction")?;
|
||||
// END iris#load
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
3
src/model/mod.rs
Normal file
3
src/model/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
pub mod config;
|
||||
pub mod plugin;
|
||||
pub mod repo;
|
283
src/model/plugin.rs
Normal file
283
src/model/plugin.rs
Normal file
|
@ -0,0 +1,283 @@
|
|||
//! Defines of an iris [plugin][Plugin].
|
||||
|
||||
use crate::{error::error, path, Repository, Result};
|
||||
|
||||
use log::{debug, trace, warn};
|
||||
use std::{borrow::Cow, cmp::Ordering, collections::HashSet, path::PathBuf};
|
||||
use url::Url;
|
||||
|
||||
/// Returns the url to the fallback git server. If a repository url is provided
|
||||
/// and it does not contain a git server (just author and repo), this url will
|
||||
/// be used in its absence.
|
||||
fn fallback_git_server() -> &'static Url {
|
||||
use std::sync::OnceLock;
|
||||
static FALLBACK: OnceLock<Url> = OnceLock::new();
|
||||
FALLBACK.get_or_init(|| {
|
||||
Url::parse("https://github.com")
|
||||
.expect("!! IRIS BUG !! invalid fallback git server url")
|
||||
})
|
||||
}
|
||||
|
||||
/// # Plugin
|
||||
///
|
||||
/// A structure representing an iris plugin specification.
|
||||
///
|
||||
/// An iris plugin has two parts.
|
||||
///
|
||||
/// - [id], must be a unique identifier for this plugin and the plugins
|
||||
/// module name
|
||||
/// - [args], a set of arguments to configure this plugin
|
||||
///
|
||||
/// [id]: Self::id
|
||||
/// [args]: Self::args
|
||||
#[derive(Debug, Eq)]
|
||||
pub struct Plugin {
|
||||
/// The plugins unique identifier. Used for the vim module name and
|
||||
/// repository checkout foler.
|
||||
pub id: String,
|
||||
/// The commit oid (if set) that the local repository will be forced to
|
||||
/// track. If not set then the repository will track the latest commit in
|
||||
/// the current tracking branch.
|
||||
pub commit: Option<String>,
|
||||
/// The branch name (if set) that the local repository will be forced to
|
||||
/// track. If not set then the repository will track the repositories
|
||||
/// default branch.
|
||||
pub branch: Option<String>,
|
||||
/// Set of plugin ids this plugin should load before
|
||||
pub run: Option<String>,
|
||||
/// Handle to the local plugin repository.
|
||||
pub before: HashSet<String>,
|
||||
/// Set of plugin ids this plugin should load after
|
||||
pub after: HashSet<String>,
|
||||
/// The command to run when vim starts up
|
||||
repo: Repository,
|
||||
}
|
||||
|
||||
impl Plugin {
|
||||
/// Create a new iris plugin.
|
||||
///
|
||||
/// Creates a plugin from the git repo at `url` with the unique id `id`.
|
||||
/// The plugin will be unlocked meaning it will always track the latest
|
||||
/// commit until locked. A handle to a local repository will be created but
|
||||
/// not loaded until called upon.
|
||||
pub fn new(id: String, url: &str) -> Result<Self> {
|
||||
// resolve and parse url
|
||||
let url = {
|
||||
// try url as is
|
||||
Url::parse(url)
|
||||
// try url with fallback
|
||||
.or_else(|_| fallback_git_server().join(url))
|
||||
// invalid git url!
|
||||
.map_err(|_| error!("invalid git url {url}"))
|
||||
}?;
|
||||
|
||||
// get the path to the local repository checkout
|
||||
let repo_path = path::plugin_dir().join(&id);
|
||||
|
||||
// create repository handle
|
||||
let repo = Repository::new(url, repo_path);
|
||||
|
||||
debug!("found plugin '{id}'");
|
||||
|
||||
Ok(Self {
|
||||
id,
|
||||
commit: None,
|
||||
branch: None,
|
||||
run: None,
|
||||
before: HashSet::new(),
|
||||
after: HashSet::new(),
|
||||
repo,
|
||||
})
|
||||
}
|
||||
|
||||
/// The url to the remote git repository.
|
||||
pub const fn url(&self) -> &Url {
|
||||
&self.repo.url
|
||||
}
|
||||
|
||||
/// The path to the local repository
|
||||
pub const fn repo_path(&self) -> &PathBuf {
|
||||
&self.repo.path
|
||||
}
|
||||
|
||||
/// The commit oid that the plugin repository is currently tracking
|
||||
fn commit(&self) -> Result<Cow<'_, str>> {
|
||||
// returned locked commit if set
|
||||
if let Some(commit) = &self.commit {
|
||||
return Ok(Cow::Borrowed(commit));
|
||||
}
|
||||
|
||||
// get commit from repo
|
||||
let branch = self.branch()?;
|
||||
let commit = self.repo.latest_commit(&branch)?;
|
||||
Ok(Cow::Owned(commit))
|
||||
}
|
||||
|
||||
/// The branch name that the plugin repository is currently tracking
|
||||
fn branch(&self) -> Result<Cow<'_, str>> {
|
||||
// return locked branch if set
|
||||
if let Some(branch) = &self.branch {
|
||||
return Ok(Cow::Borrowed(branch));
|
||||
}
|
||||
|
||||
// get branch from repo
|
||||
let branch = self.repo.default_branch()?;
|
||||
Ok(Cow::Owned(branch))
|
||||
}
|
||||
|
||||
/// Fetches latest changes in the local repository but does not update
|
||||
/// checkout.
|
||||
pub fn fetch(&self) -> Result<()> {
|
||||
trace!("fetching {}", self.id);
|
||||
let branch = self.branch()?;
|
||||
self.repo.fetch(&branch)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Checkout plugin repository using their current refs
|
||||
pub fn switch(&self) -> Result<()> {
|
||||
trace!("switching {}", self.id);
|
||||
let commit = self.commit()?;
|
||||
self.repo.checkout(&commit)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Update plugin ref to point to the latest commit
|
||||
pub fn lock(&mut self) -> Result<()> {
|
||||
trace!("locking {}", self.id);
|
||||
let branch = self.branch()?;
|
||||
self.repo.fetch(&branch)?;
|
||||
let commit = self.repo.latest_commit(&branch)?;
|
||||
self.commit = Some(commit);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Runtime path
|
||||
///
|
||||
/// This this the plugins root directory, and is used by vim/neovim to
|
||||
/// find the vim/lua runtime scripts.
|
||||
///
|
||||
/// vim: set runtimepath+=<path>
|
||||
pub fn runtime_path(&self) -> &PathBuf {
|
||||
self.repo_path()
|
||||
}
|
||||
|
||||
/// Lua package path
|
||||
///
|
||||
/// This is the path to the lua module if the plugin has one. If so
|
||||
/// it needs to be added to the lua package path. The path is located
|
||||
/// in the repos lua directory at /lua/<id>/init.lua or /lua/<id>.lua. If
|
||||
/// both exist the former takes priority.
|
||||
///
|
||||
/// lua: package.path = package.path .. ";<path>"
|
||||
pub fn lua_package_path(&self) -> Option<PathBuf> {
|
||||
let mut lua = self.repo_path().to_owned();
|
||||
lua.push("lua");
|
||||
lua.push(&self.id);
|
||||
// /lua/<id>/init.lua
|
||||
let module = lua.join("init.lua");
|
||||
if module.exists() {
|
||||
return Some(module.with_file_name("?.lua"));
|
||||
}
|
||||
// /lua/<id>/.lua
|
||||
let module = lua.with_extension("lua");
|
||||
if module.exists() {
|
||||
return Some(module.with_file_name("?.lua"));
|
||||
}
|
||||
// no lua package path found
|
||||
None
|
||||
}
|
||||
|
||||
/// Vim source file
|
||||
///
|
||||
/// Path to a vim file in the /plugin directory that needs to be
|
||||
/// sourced. This is located at /plugin/<id>.vim
|
||||
///
|
||||
/// vim: source <path>
|
||||
pub fn vim_source_file(&self) -> Option<PathBuf> {
|
||||
let mut path = self.repo_path().to_owned();
|
||||
path.push("plugin");
|
||||
path.push(&self.id);
|
||||
path.set_extension("vim");
|
||||
Some(path).filter(|path| path.exists())
|
||||
}
|
||||
|
||||
/// Lua source file
|
||||
///
|
||||
/// Path to a lua file in the /plugin directory that needs to be
|
||||
/// sourced. This is located at /plugin/<id>.lua
|
||||
///
|
||||
/// lua: dofile('<path>')
|
||||
pub fn lua_source_file(&self) -> Option<PathBuf> {
|
||||
let mut path = self.repo_path().to_owned();
|
||||
path.push("plugin");
|
||||
path.push(&self.id);
|
||||
path.set_extension("lua");
|
||||
Some(path).filter(|path| path.exists())
|
||||
}
|
||||
|
||||
/// Vim source after file
|
||||
///
|
||||
/// Path to a vim file in the /after/plugin directory that needs to be
|
||||
/// sourced last. This is located at /after/plugin/<id>.vim
|
||||
///
|
||||
/// vim: source <path>
|
||||
pub fn vim_source_after_file(&self) -> Option<PathBuf> {
|
||||
let mut path = self.repo_path().to_owned();
|
||||
path.push("after/plugin");
|
||||
path.push(&self.id);
|
||||
path.set_extension("vim");
|
||||
Some(path).filter(|path| path.exists())
|
||||
}
|
||||
|
||||
/// Lua source after file
|
||||
///
|
||||
/// Path to a lua file in the /after/plugin directory that needs to be
|
||||
/// sourced last. This is located at /after/plugin/<id>.lua
|
||||
///
|
||||
/// lua: dofile('<path>')
|
||||
pub fn lua_source_after_file(&self) -> Option<PathBuf> {
|
||||
let mut path = self.repo_path().to_owned();
|
||||
path.push("after/plugin");
|
||||
path.push(&self.id);
|
||||
path.set_extension("lua");
|
||||
Some(path).filter(|path| path.exists())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Plugin {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id.eq(&other.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Plugin {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
let is_after =
|
||||
other.before.contains(&self.id) || self.after.contains(&other.id);
|
||||
let is_before =
|
||||
other.after.contains(&self.id) || self.before.contains(&other.id);
|
||||
match (is_before, is_after) {
|
||||
// equal, no ordering
|
||||
(false, false) => Some(Ordering::Equal),
|
||||
// before
|
||||
(true, false) => Some(Ordering::Less),
|
||||
// after
|
||||
(false, true) => Some(Ordering::Greater),
|
||||
// cycle detected
|
||||
(true, true) => {
|
||||
warn!(
|
||||
"plugin dependency cycle detected between '{}' and '{}'",
|
||||
&self.id, &other.id
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Plugin {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap_or(Ordering::Equal)
|
||||
}
|
||||
}
|
123
src/model/repo.rs
Normal file
123
src/model/repo.rs
Normal file
|
@ -0,0 +1,123 @@
|
|||
//! Definition of an iris [repo][Repository].
|
||||
|
||||
use crate::{error, Result};
|
||||
|
||||
use log::{debug, trace};
|
||||
use std::{path::PathBuf, sync::OnceLock};
|
||||
use url::Url;
|
||||
|
||||
/// A handle to a locally stored git repository.
|
||||
pub struct Repository {
|
||||
/// The remote url that the git repository is located at.
|
||||
pub url: Url,
|
||||
/// The path on disk that the this repository is/will be located at.
|
||||
pub path: PathBuf,
|
||||
/// The git2 lib handle to the repo
|
||||
inner: OnceLock<git2::Repository>,
|
||||
}
|
||||
|
||||
impl Repository {
|
||||
/// Creates a new handle to a local git repository.
|
||||
pub const fn new(url: Url, path: PathBuf) -> Self {
|
||||
Self {
|
||||
url,
|
||||
path,
|
||||
inner: OnceLock::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the handle to the local repository
|
||||
fn repo(&self) -> Result<&git2::Repository> {
|
||||
// we only need to initalize once
|
||||
if let Some(repo) = self.inner.get() {
|
||||
return Ok(repo);
|
||||
}
|
||||
|
||||
trace!("loading repo");
|
||||
|
||||
// repository not loaded, try loading it
|
||||
let repo = if self.path.exists() {
|
||||
// repo exists on file system, just open it
|
||||
git2::Repository::open(&self.path)?
|
||||
} else {
|
||||
// repo needs to be cloned
|
||||
git2::Repository::clone(self.url.as_str(), &self.path)?
|
||||
};
|
||||
|
||||
// save and return repo
|
||||
Ok(self.inner.get_or_init(|| repo))
|
||||
}
|
||||
|
||||
/// Gets the current remote in the git repository
|
||||
fn remote(&self) -> Result<git2::Remote> {
|
||||
let repo = self.repo()?;
|
||||
let remote_name = "origin";
|
||||
let mut remote = repo.find_remote(remote_name)?;
|
||||
|
||||
// make sure that out remote is connected before
|
||||
// we do anything with it. otherwise things will
|
||||
// fail!
|
||||
if !remote.connected() {
|
||||
trace!("connecting to remote");
|
||||
remote.connect(git2::Direction::Fetch)?;
|
||||
}
|
||||
|
||||
Ok(remote)
|
||||
}
|
||||
|
||||
/// Fetches the latest commits in the provided branch.
|
||||
pub fn fetch(&self, branch: &str) -> Result<()> {
|
||||
let mut remote = self.remote()?;
|
||||
trace!("fetching '{branch}");
|
||||
remote.fetch(&[branch], None, None)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the default branch of the git repositroy.
|
||||
pub fn default_branch(&self) -> Result<String> {
|
||||
let remote = self.remote()?;
|
||||
let buf = remote.default_branch()?;
|
||||
let name = buf
|
||||
.as_str()
|
||||
.and_then(|s| s.strip_prefix("refs/heads/"))
|
||||
.map(String::from)
|
||||
.ok_or_else(|| error::error!("cannot get default branch"))?;
|
||||
debug!("default branch is '{name}'");
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
/// Returns the latest fetched commit in `branch`.
|
||||
pub fn latest_commit(&self, branch: &str) -> Result<String> {
|
||||
let repo = self.repo()?;
|
||||
let refr_name = format!("refs/remotes/origin/{branch}");
|
||||
let refr = repo.find_reference(&refr_name)?;
|
||||
let commit = refr.peel_to_commit()?;
|
||||
let oid = commit.id().to_string();
|
||||
Ok(oid)
|
||||
}
|
||||
|
||||
/// Checks out the local repository to the given commit and detaches
|
||||
/// HEAD to that commit.
|
||||
pub fn checkout(&self, commit: &str) -> Result<()> {
|
||||
let repo = self.repo()?;
|
||||
trace!("checkout to '{commit}'");
|
||||
let oid = git2::Oid::from_str(commit)?;
|
||||
let commit = repo.find_commit(oid)?;
|
||||
repo.reset(commit.as_object(), git2::ResetType::Hard, None)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Repository {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "_")
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Repository {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.url.eq(&other.url) && self.path.eq(&other.path)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Repository {}
|
291
src/parse/de.rs
Normal file
291
src/parse/de.rs
Normal file
|
@ -0,0 +1,291 @@
|
|||
//! Deserialize an iris structure from a string.
|
||||
|
||||
use crate::{Config, Plugin};
|
||||
|
||||
use serde::de;
|
||||
use std::collections::HashSet;
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// Errors that can occur when deserializing a type
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
/// Occurs when toml could not be deserialized
|
||||
#[error(transparent)]
|
||||
Toml(#[from] toml::de::Error),
|
||||
}
|
||||
|
||||
macro_rules! error {
|
||||
($($arg:tt)*) => {
|
||||
de::Error::custom(format!($($arg)*))
|
||||
};
|
||||
}
|
||||
|
||||
struct PluginIDsVisitor;
|
||||
impl<'de> de::Visitor<'de> for PluginIDsVisitor {
|
||||
type Value = Vec<String>;
|
||||
|
||||
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "single or list of plugin ids")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
self.visit_string(v.to_string())
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Ok(vec![v])
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::SeqAccess<'de>,
|
||||
{
|
||||
let mut values =
|
||||
seq.size_hint().map_or_else(Vec::new, Vec::with_capacity);
|
||||
while let Some(value) = seq.next_element::<String>()? {
|
||||
values.push(value);
|
||||
}
|
||||
Ok(values)
|
||||
}
|
||||
}
|
||||
|
||||
struct PluginIDsSeed;
|
||||
impl<'de> de::DeserializeSeed<'de> for PluginIDsSeed {
|
||||
type Value = HashSet<String>;
|
||||
|
||||
fn deserialize<D>(self, d: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
{
|
||||
let values = d.deserialize_any(PluginIDsVisitor)?;
|
||||
Ok(HashSet::from_iter(values))
|
||||
}
|
||||
}
|
||||
|
||||
// plugin visitor with seeded plugin id
|
||||
struct PluginVisitor(Option<String>);
|
||||
impl<'de> de::Visitor<'de> for PluginVisitor {
|
||||
type Value = Plugin;
|
||||
|
||||
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match &self.0 {
|
||||
Some(id) => write!(f, "arguments for plugin '{id}'"),
|
||||
None => write!(f, "plugin id and arguments"),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
self.visit_string(v.to_string())
|
||||
}
|
||||
|
||||
fn visit_borrowed_str<E>(self, v: &'_ str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
self.visit_string(v.to_string())
|
||||
}
|
||||
|
||||
fn visit_string<E>(self, url: String) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
let Some(id) = self.0 else {
|
||||
return Err(de::Error::missing_field("id"));
|
||||
};
|
||||
Self::Value::new(id, &url).map_err(E::custom)
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::MapAccess<'de>,
|
||||
{
|
||||
// parse each map value as a possbile field for the plugin
|
||||
let mut id = self.0; // plugin id (required)
|
||||
let mut url = None; // repository url (required)
|
||||
let mut commit = None; // commit to lock to
|
||||
let mut branch = None; // branch to lock to
|
||||
let mut run = None; // command to run on launch
|
||||
let mut before = HashSet::new(); // plugins to load before
|
||||
let mut after = HashSet::new(); // plugins to load after
|
||||
|
||||
while let Some(key) = map.next_key::<String>()? {
|
||||
match key.as_str() {
|
||||
// plugin id
|
||||
"id" => {
|
||||
id = Some(map.next_value::<String>()?);
|
||||
}
|
||||
// repo url
|
||||
"url" => {
|
||||
url = Some(map.next_value::<String>()?);
|
||||
}
|
||||
// locked commit
|
||||
"commit" => {
|
||||
commit = Some(map.next_value::<String>()?);
|
||||
}
|
||||
// locked branch
|
||||
"branch" => {
|
||||
branch = Some(map.next_value::<String>()?);
|
||||
}
|
||||
// vim command to run on launch
|
||||
"run" => {
|
||||
run = Some(map.next_value::<String>()?);
|
||||
}
|
||||
// plugins to load before
|
||||
"before" => {
|
||||
before = map.next_value_seed(PluginIDsSeed)?;
|
||||
}
|
||||
// plugins to load after
|
||||
"after" => {
|
||||
after = map.next_value_seed(PluginIDsSeed)?;
|
||||
}
|
||||
// invalid key!
|
||||
key => return Err(error!("unknown plugin field '{key}'")),
|
||||
};
|
||||
}
|
||||
|
||||
// id is a required field
|
||||
let Some(id) = id else {
|
||||
return Err(de::Error::missing_field("id"));
|
||||
};
|
||||
|
||||
// url is a required field
|
||||
let Some(url) = url else {
|
||||
return Err(de::Error::missing_field("url"));
|
||||
};
|
||||
|
||||
let mut plugin =
|
||||
Self::Value::new(id, &url).map_err(de::Error::custom)?;
|
||||
plugin.commit = commit;
|
||||
plugin.branch = branch;
|
||||
plugin.run = run;
|
||||
plugin.before = before;
|
||||
plugin.after = after;
|
||||
Ok(plugin)
|
||||
}
|
||||
}
|
||||
|
||||
// deserialize plugin with possible id
|
||||
struct PluginSeed(Option<String>);
|
||||
impl<'de> de::DeserializeSeed<'de> for PluginSeed {
|
||||
type Value = Plugin;
|
||||
|
||||
fn deserialize<D>(self, d: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
{
|
||||
d.deserialize_any(PluginVisitor(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
// plugins visitor
|
||||
struct PluginsVisitor;
|
||||
impl<'de> de::Visitor<'de> for PluginsVisitor {
|
||||
type Value = Vec<Plugin>;
|
||||
|
||||
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("map of plugin id's to their arguments")
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::MapAccess<'de>,
|
||||
{
|
||||
let mut plugins =
|
||||
map.size_hint().map_or_else(Vec::new, Vec::with_capacity);
|
||||
while let Some(id) = map.next_key()? {
|
||||
let plugin = map.next_value_seed(PluginSeed(Some(id)))?;
|
||||
plugins.push(plugin);
|
||||
}
|
||||
Ok(plugins)
|
||||
}
|
||||
|
||||
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::SeqAccess<'de>,
|
||||
{
|
||||
let mut plugins =
|
||||
seq.size_hint().map_or_else(Vec::new, Vec::with_capacity);
|
||||
while let Some(plugin) = seq.next_element_seed(PluginSeed(None))? {
|
||||
plugins.push(plugin);
|
||||
}
|
||||
Ok(plugins)
|
||||
}
|
||||
}
|
||||
|
||||
// plugins seed
|
||||
struct PluginsSeed;
|
||||
impl<'de> de::DeserializeSeed<'de> for PluginsSeed {
|
||||
type Value = Vec<Plugin>;
|
||||
|
||||
fn deserialize<D>(self, d: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
{
|
||||
d.deserialize_any(PluginsVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
// config visitor
|
||||
struct ConfigVisitor;
|
||||
impl<'de> de::Visitor<'de> for ConfigVisitor {
|
||||
type Value = Config;
|
||||
|
||||
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("iris config value")
|
||||
}
|
||||
|
||||
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||
where
|
||||
A: de::MapAccess<'de>,
|
||||
{
|
||||
let mut plugins = None; // list of plugins (required)
|
||||
while let Some(key) = map.next_key::<String>()? {
|
||||
match key.as_str() {
|
||||
"plugins" => {
|
||||
plugins = Some(map.next_value_seed(PluginsSeed)?);
|
||||
}
|
||||
key => return Err(error!("unknown config field '{key}'")),
|
||||
};
|
||||
}
|
||||
// plugins is a required field
|
||||
let Some(mut plugins) = plugins else {
|
||||
return Err(de::Error::missing_field("plugins"));
|
||||
};
|
||||
plugins.sort();
|
||||
Ok(Config { plugins })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> de::Deserialize<'de> for Config {
|
||||
fn deserialize<D>(d: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
{
|
||||
d.deserialize_map(ConfigVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn parse(s: &str) -> crate::Result<Self> {
|
||||
toml::from_str(s)
|
||||
.map_err(Error::from)
|
||||
.map_err(crate::Error::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Config {
|
||||
type Err = crate::Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::parse(s)
|
||||
}
|
||||
}
|
2
src/parse/mod.rs
Normal file
2
src/parse/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod de;
|
||||
pub mod ser;
|
62
src/parse/ser.rs
Normal file
62
src/parse/ser.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
//! Serialize an iris structure into a string.
|
||||
|
||||
use crate::{Config, Plugin};
|
||||
|
||||
use serde::ser;
|
||||
|
||||
/// Errors that can occur when serializing a type
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
/// Occurs when toml could not be eserialized
|
||||
#[error(transparent)]
|
||||
Toml(#[from] toml::ser::Error),
|
||||
}
|
||||
|
||||
impl ser::Serialize for Plugin {
|
||||
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: ser::Serializer,
|
||||
{
|
||||
use ser::SerializeMap;
|
||||
let mut s = s.serialize_map(None)?;
|
||||
s.serialize_entry("id", &self.id)?;
|
||||
s.serialize_entry("url", self.url().as_str())?;
|
||||
if let Some(commit) = &self.commit {
|
||||
s.serialize_entry("commit", commit)?;
|
||||
}
|
||||
if let Some(branch) = &self.branch {
|
||||
s.serialize_entry("branch", branch)?;
|
||||
}
|
||||
if let Some(run) = &self.run {
|
||||
s.serialize_entry("run", run)?;
|
||||
}
|
||||
s.serialize_entry("before", &self.before)?;
|
||||
s.serialize_entry("after", &self.after)?;
|
||||
s.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl ser::Serialize for Config {
|
||||
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: ser::Serializer,
|
||||
{
|
||||
use ser::SerializeMap;
|
||||
let mut s = s.serialize_map(Some(1))?;
|
||||
|
||||
// plugins
|
||||
s.serialize_key("plugins")?;
|
||||
s.serialize_value(&self.plugins)?;
|
||||
|
||||
s.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Serializes a string from the iris config
|
||||
pub fn to_string(&self) -> crate::Result<String> {
|
||||
toml::to_string(self)
|
||||
.map_err(Error::from)
|
||||
.map_err(crate::Error::from)
|
||||
}
|
||||
}
|
69
src/path.rs
Normal file
69
src/path.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
//! Directory and file paths used by iris.
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Root of the data directory
|
||||
fn base_config_dir() -> PathBuf {
|
||||
dirs::config_local_dir().expect("could not locate config directory")
|
||||
}
|
||||
|
||||
/// Root of the config directory
|
||||
fn base_data_dir() -> PathBuf {
|
||||
dirs::data_local_dir().expect("could not locate data directory")
|
||||
}
|
||||
|
||||
/// Path to the current diectort
|
||||
pub fn current_dir() -> PathBuf {
|
||||
std::env::current_dir().expect("could not locate current directory")
|
||||
}
|
||||
|
||||
/// Path to iris's config directory.
|
||||
///
|
||||
/// This is the directory where iris will look and save it's config files.
|
||||
pub fn config_dir() -> PathBuf {
|
||||
base_config_dir().join("iris")
|
||||
}
|
||||
|
||||
/// Default path to iris's plugin file
|
||||
pub fn default_plugin_file() -> PathBuf {
|
||||
config_dir().join("iris.toml")
|
||||
}
|
||||
|
||||
/// Path to iris's plugin file
|
||||
pub fn plugin_file() -> PathBuf {
|
||||
[current_dir(), config_dir()]
|
||||
.into_iter()
|
||||
.map(|dir| dir.join("iris.toml"))
|
||||
.find(|path| path.exists())
|
||||
.unwrap_or_else(default_plugin_file)
|
||||
}
|
||||
|
||||
/// Path to iris's lock file
|
||||
pub fn lock_file() -> PathBuf {
|
||||
plugin_file().with_file_name("iris.lock")
|
||||
}
|
||||
|
||||
/// Path to iris's data directory.
|
||||
pub fn data_dir() -> PathBuf {
|
||||
base_data_dir().join("iris")
|
||||
}
|
||||
|
||||
/// Path to iris's plugin directory.
|
||||
///
|
||||
/// This is where each checkout for each plugin repository will be saved.
|
||||
pub fn plugin_dir() -> PathBuf {
|
||||
data_dir().join("plugins")
|
||||
}
|
||||
|
||||
/// Path to iris's transaction lock file.
|
||||
///
|
||||
/// The transaction lock ensures that only one process is operating on iris's
|
||||
/// data directory at a time.
|
||||
pub fn transaction_lock_file() -> PathBuf {
|
||||
data_dir().join("lock")
|
||||
}
|
||||
|
||||
/// Destination path for iris's vim autoload file.
|
||||
pub fn autoload_file() -> PathBuf {
|
||||
base_data_dir().join("nvim/site/autoload/iris.vim")
|
||||
}
|
Loading…
Add table
Reference in a new issue