Compare commits
3 Commits
e17db09859
...
renovate/a
| Author | SHA1 | Date | |
|---|---|---|---|
| c33ab5d833 | |||
| 5027930d36 | |||
| c4c1288fe9 |
4
.drone.yml
Normal file
4
.drone.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
kind: template
|
||||
load: bust_gobin_default_template.yaml
|
||||
name: char
|
||||
data: {}
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1 @@
|
||||
target/
|
||||
.vscode/
|
||||
dist/
|
||||
|
||||
527
Cargo.lock
generated
527
Cargo.lock
generated
@@ -1,527 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "char"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"color-eyre",
|
||||
"eyre",
|
||||
"serde",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap_lex",
|
||||
"is-terminal",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color-eyre"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"color-spantrace",
|
||||
"eyre",
|
||||
"indenter",
|
||||
"once_cell",
|
||||
"owo-colors",
|
||||
"tracing-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color-spantrace"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"owo-colors",
|
||||
"tracing-core",
|
||||
"tracing-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eyre"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
|
||||
dependencies = [
|
||||
"indenter",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.27.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indenter"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"io-lifetimes",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.30.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b8c786513eb403643f2a88c244c2aaa270ef2153f55094587d0c48a3cf22a83"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-error"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
||||
dependencies = [
|
||||
"sharded-slab",
|
||||
"thread_local",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[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-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
||||
13
Cargo.toml
13
Cargo.toml
@@ -1,13 +0,0 @@
|
||||
[package]
|
||||
name = "char"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
clap = "4.1.1"
|
||||
color-eyre = "0.6.2"
|
||||
eyre = "0.6.8"
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
toml = { version = "0.5.11", features = ["preserve_order"] }
|
||||
26
README.md
Normal file
26
README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Char
|
||||
|
||||
Char is an organizations best friend, it helps with code sharing when either
|
||||
using a multi-repo strategy or mono repo. The goal of the project is to
|
||||
facilitate sharing of presets and plugins to reduce the required complexity
|
||||
developers have to take on.
|
||||
|
||||
This project is best suited with a standard library of plugins (which serves the
|
||||
function of libraries), as well `kjuulh/bust` which is a platform agnostic
|
||||
CI/task setup
|
||||
|
||||
This is in very early stages, and for now it officially supports scaffolding.
|
||||
|
||||
## Example
|
||||
|
||||
The `examples` folder shows how to load plugins, though presets are still
|
||||
pending.
|
||||
|
||||
```yaml
|
||||
# file: .char.yml
|
||||
registry: git.front.kjuulh.io
|
||||
plugins:
|
||||
"kjuulh/char#/plugins/gocli":
|
||||
vars:
|
||||
name: "char"
|
||||
```
|
||||
67
cmd/char/do.go
Normal file
67
cmd/char/do.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package char
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"git.front.kjuulh.io/kjuulh/char/pkg/charcontext"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type RequiredArg struct {
|
||||
Required bool
|
||||
Value string
|
||||
}
|
||||
|
||||
func NewDoCommand(charctx *charcontext.CharContext) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "do",
|
||||
}
|
||||
about, err := charctx.About(context.Background())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, a := range about {
|
||||
for _, c := range a.Commands {
|
||||
requiredArgs := make(map[string]*RequiredArg, len(c.Args))
|
||||
for _, arg := range c.Args {
|
||||
requiredArgs[arg] = &RequiredArg{
|
||||
Required: false,
|
||||
}
|
||||
}
|
||||
for _, required := range c.Required {
|
||||
if _, ok := requiredArgs[required]; ok {
|
||||
requiredArg := requiredArgs[required]
|
||||
requiredArg.Required = true
|
||||
}
|
||||
}
|
||||
|
||||
doCmd := &cobra.Command{
|
||||
Use: c.Name,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if err := cmd.ParseFlags(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := charctx.Do(cmd.Context(), a.ClientName, c.Name, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
for argName, argValue := range requiredArgs {
|
||||
doCmd.PersistentFlags().StringVar(&argValue.Value, argName, "", "")
|
||||
if argValue.Required {
|
||||
doCmd.MarkPersistentFlagRequired(argName)
|
||||
}
|
||||
}
|
||||
|
||||
cmd.AddCommand(doCmd)
|
||||
}
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
13
cmd/char/limitedroot.go
Normal file
13
cmd/char/limitedroot.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package char
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewLimitedCharCmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "char",
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
64
cmd/char/ls.go
Normal file
64
cmd/char/ls.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package char
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.front.kjuulh.io/kjuulh/char/pkg/charcontext"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewLsCommand(charctx *charcontext.CharContext) *cobra.Command {
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "ls",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
about, err := charctx.About(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, a := range about {
|
||||
fmt.Printf("plugin: %s\n", a.Name)
|
||||
fmt.Printf("\tversion: %s\n", a.Version)
|
||||
fmt.Printf("\tabout: %s\n", a.About)
|
||||
if len(a.Vars) > 0 {
|
||||
fmt.Println("\tVars:")
|
||||
for _, av := range a.Vars {
|
||||
fmt.Printf("\t\t%s\n", av)
|
||||
}
|
||||
}
|
||||
if len(a.Commands) > 0 {
|
||||
fmt.Println("\tCommands:")
|
||||
for _, ac := range a.Commands {
|
||||
fmt.Printf("\t\t%s\n", ac.Name)
|
||||
if len(ac.Args) == 0 {
|
||||
continue
|
||||
}
|
||||
fmt.Println("\t\tArgs")
|
||||
for _, aca := range ac.Args {
|
||||
isrequired := false
|
||||
for _, acr := range ac.Required {
|
||||
if acr == aca {
|
||||
isrequired = true
|
||||
}
|
||||
}
|
||||
if isrequired {
|
||||
fmt.Printf("\t\t\t%s: required\n", aca)
|
||||
} else {
|
||||
fmt.Printf("\t\t\t%s\n", aca)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
19
cmd/char/root.go
Normal file
19
cmd/char/root.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package char
|
||||
|
||||
import (
|
||||
"git.front.kjuulh.io/kjuulh/char/pkg/charcontext"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewCharCmd(charctx *charcontext.CharContext) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "char",
|
||||
}
|
||||
|
||||
cmd.AddCommand(
|
||||
NewLsCommand(charctx),
|
||||
NewDoCommand(charctx),
|
||||
)
|
||||
|
||||
return cmd
|
||||
}
|
||||
4
examples/basic/.char.yml
Normal file
4
examples/basic/.char.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
registry: git.front.kjuulh.io
|
||||
plugins:
|
||||
"kjuulh/char#plugins/gocli": {}
|
||||
"kjuulh/char#plugins/rust": {}
|
||||
2
examples/basic/.gitignore
vendored
Normal file
2
examples/basic/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.char/plugins/
|
||||
char
|
||||
21
examples/basic/benchmark.sh
Executable file
21
examples/basic/benchmark.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
go build -o char ../../main.go
|
||||
|
||||
function devcharls() {
|
||||
CHAR_DEV_MODE=true ./char ls 2&> /dev/null
|
||||
}
|
||||
|
||||
function charls() {
|
||||
./char ls 2&> /dev/null
|
||||
}
|
||||
|
||||
echo "scratch"
|
||||
time devcharls
|
||||
echo ""
|
||||
|
||||
echo "ready"
|
||||
time charls
|
||||
echo ""
|
||||
7
examples/basic/test.sh
Executable file
7
examples/basic/test.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
go build -o char ../../main.go
|
||||
|
||||
CHAR_DEV_MODE=true ./char ls
|
||||
13
examples/basic/testdo.sh
Executable file
13
examples/basic/testdo.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
go build -o char ../../main.go
|
||||
|
||||
echo "base"
|
||||
CHAR_DEV_MODE=true ./char do -h
|
||||
|
||||
echo
|
||||
echo "--------"
|
||||
echo "local_up"
|
||||
CHAR_DEV_MODE=false ./char do local_up --fish something
|
||||
@@ -1,55 +0,0 @@
|
||||
[char]
|
||||
plan = "plans/base/"
|
||||
dependencies = ["plans/extension"]
|
||||
|
||||
[char.overrides]
|
||||
org = "overrides/org"
|
||||
|
||||
[application]
|
||||
name = "service"
|
||||
|
||||
[config]
|
||||
# provides both local and k8s by default can also be set using:
|
||||
# config.k8s.rabbitmq = true
|
||||
# config.docker-compose.rabbitmq = true
|
||||
rabbitmq = true
|
||||
postgres = true
|
||||
|
||||
[config.org]
|
||||
squad = "kjuulh"
|
||||
domain = "tooling"
|
||||
|
||||
[config.pipeline]
|
||||
path = "char/ci/" # most of these are default, showing them here as a showcase
|
||||
|
||||
[config.actions]
|
||||
path = "char/actions"
|
||||
|
||||
[config.releaser]
|
||||
type = "rust-releaser"
|
||||
|
||||
[config.cargo]
|
||||
crates = ["crates/service_core", "crates/service_util"]
|
||||
|
||||
[config.rust_bin]
|
||||
name = "service"
|
||||
logging = { pretty = true }
|
||||
|
||||
[config.environments.local]
|
||||
type = "docker-compose" # technically default
|
||||
|
||||
[config.environments.local.env]
|
||||
"env" = "local"
|
||||
"db.hostname" = "postgres"
|
||||
"db.secret" = "postgres"
|
||||
|
||||
[config.k8s]
|
||||
monitoring = true
|
||||
|
||||
[config.environments.dev]
|
||||
type = "k8s"
|
||||
|
||||
[config.environments.local.dev]
|
||||
"env" = "local"
|
||||
"db.hostname" = "service-db"
|
||||
"db.secret" = { type = "secret" }
|
||||
@@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "actions"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
@@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
7
examples/service/char/overrides/org/Cargo.lock
generated
7
examples/service/char/overrides/org/Cargo.lock
generated
@@ -1,7 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "org"
|
||||
version = "0.1.0"
|
||||
@@ -1,8 +0,0 @@
|
||||
[package]
|
||||
name = "org"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
@@ -1,3 +0,0 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"rustc_fingerprint":13769919407148446586,"outputs":{"10376369925670944939":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n/Users/kah/.rustup/toolchains/stable-aarch64-apple-darwin\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_arch=\"aarch64\"\ntarget_endian=\"little\"\ntarget_env=\"\"\ntarget_family=\"unix\"\ntarget_feature=\"aes\"\ntarget_feature=\"crc\"\ntarget_feature=\"dit\"\ntarget_feature=\"dotprod\"\ntarget_feature=\"dpb\"\ntarget_feature=\"dpb2\"\ntarget_feature=\"fcma\"\ntarget_feature=\"fhm\"\ntarget_feature=\"flagm\"\ntarget_feature=\"fp16\"\ntarget_feature=\"frintts\"\ntarget_feature=\"jsconv\"\ntarget_feature=\"lor\"\ntarget_feature=\"lse\"\ntarget_feature=\"neon\"\ntarget_feature=\"paca\"\ntarget_feature=\"pacg\"\ntarget_feature=\"pan\"\ntarget_feature=\"pmuv3\"\ntarget_feature=\"ras\"\ntarget_feature=\"rcpc\"\ntarget_feature=\"rcpc2\"\ntarget_feature=\"rdm\"\ntarget_feature=\"sb\"\ntarget_feature=\"sha2\"\ntarget_feature=\"sha3\"\ntarget_feature=\"ssbs\"\ntarget_feature=\"vh\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"macos\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"apple\"\nunix\n","stderr":""},"15697416045686424142":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.dylib\nlib___.dylib\nlib___.a\nlib___.dylib\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.66.0 (69f9c33d7 2022-12-12)\nbinary: rustc\ncommit-hash: 69f9c33d71c871fc16ac445211281c6e7a340943\ncommit-date: 2022-12-12\nhost: aarch64-apple-darwin\nrelease: 1.66.0\nLLVM version: 15.0.2\n","stderr":""}},"successes":{}}
|
||||
@@ -1,3 +0,0 @@
|
||||
Signature: 8a477f597d28d172789f06886806bc55
|
||||
# This file is a cache directory tag created by cargo.
|
||||
# For information about cache directory tags see https://bford.info/cachedir/
|
||||
@@ -1 +0,0 @@
|
||||
baa57697ce65b314
|
||||
@@ -1 +0,0 @@
|
||||
{"rustc":15520539443732555526,"features":"[]","target":10808372008975436347,"profile":11736316127369858332,"path":1684066648322511884,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/org-2413d5d1cd4f3ae1/dep-bin-org"}}],"rustflags":[],"metadata":7797948686568424061,"config":2202906307356721367,"compile_kind":0}
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
This file has an mtime of when this was started.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,5 +0,0 @@
|
||||
/Users/kah/git/git.front.kjuulh.io/kjuulh/char/examples/service/char/overrides/org/target/debug/deps/org-2413d5d1cd4f3ae1: src/main.rs
|
||||
|
||||
/Users/kah/git/git.front.kjuulh.io/kjuulh/char/examples/service/char/overrides/org/target/debug/deps/org-2413d5d1cd4f3ae1.d: src/main.rs
|
||||
|
||||
src/main.rs:
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
/Users/kah/git/git.front.kjuulh.io/kjuulh/char/examples/service/char/overrides/org/target/debug/org: /Users/kah/git/git.front.kjuulh.io/kjuulh/char/examples/service/char/overrides/org/src/main.rs
|
||||
@@ -1,5 +0,0 @@
|
||||
[char]
|
||||
|
||||
[plan]
|
||||
|
||||
name = "base"
|
||||
33
go.mod
Normal file
33
go.mod
Normal file
@@ -0,0 +1,33 @@
|
||||
module git.front.kjuulh.io/kjuulh/char
|
||||
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/hashicorp/go-hclog v1.6.3
|
||||
github.com/hashicorp/go-plugin v1.7.0
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/stretchr/testify v1.11.1
|
||||
golang.org/x/sync v0.19.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fatih/color v1.13.0 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/hashicorp/yamux v0.1.2 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 // indirect
|
||||
github.com/oklog/run v1.1.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/spf13/pflag v1.0.9 // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
||||
google.golang.org/grpc v1.61.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
)
|
||||
170
go.sum
Normal file
170
go.sum
Normal file
@@ -0,0 +1,170 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/hashicorp/go-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU=
|
||||
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-hclog v1.3.1 h1:vDwF1DFNZhntP4DAjuTpOw3uEgMUpXh1pB5fW9DqHpo=
|
||||
github.com/hashicorp/go-hclog v1.3.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-hclog v1.4.0 h1:ctuWFGrhFha8BnnzxqeRGidlEcQkDyL5u8J8t5eA11I=
|
||||
github.com/hashicorp/go-hclog v1.4.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
|
||||
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
|
||||
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-plugin v1.4.5 h1:oTE/oQR4eghggRg8VY7PAz3dr++VwDNBGCcOfIvHpBo=
|
||||
github.com/hashicorp/go-plugin v1.4.5/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
|
||||
github.com/hashicorp/go-plugin v1.4.6 h1:MDV3UrKQBM3du3G7MApDGvOsMYy3JQJ4exhSoKBAeVA=
|
||||
github.com/hashicorp/go-plugin v1.4.6/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
|
||||
github.com/hashicorp/go-plugin v1.4.9 h1:ESiK220/qE0aGxWdzKIvRH69iLiuN/PjoLTm69RoWtU=
|
||||
github.com/hashicorp/go-plugin v1.4.9/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
|
||||
github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA=
|
||||
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
|
||||
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
|
||||
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
||||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg=
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
|
||||
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
|
||||
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
|
||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
|
||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0=
|
||||
google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
1
go.work.sum
Normal file
1
go.work.sum
Normal file
@@ -0,0 +1 @@
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
29
main.go
Normal file
29
main.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"git.front.kjuulh.io/kjuulh/char/cmd/char"
|
||||
"git.front.kjuulh.io/kjuulh/char/pkg/charcontext"
|
||||
)
|
||||
|
||||
func main() {
|
||||
charctx, err := charcontext.NewCharContext(context.Background())
|
||||
if err != nil {
|
||||
if errors.Is(err, charcontext.ErrNoContextFound) {
|
||||
log.Print("you are not in a char context, as such you will be presented with limited options")
|
||||
if err := char.NewLimitedCharCmd().Execute(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
defer charctx.Close()
|
||||
|
||||
if err := char.NewCharCmd(charctx).Execute(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
70
pkg/charcontext/char_context.go
Normal file
70
pkg/charcontext/char_context.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package charcontext
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"git.front.kjuulh.io/kjuulh/char/pkg/plugins/provider"
|
||||
"git.front.kjuulh.io/kjuulh/char/pkg/register"
|
||||
"git.front.kjuulh.io/kjuulh/char/pkg/schema"
|
||||
)
|
||||
|
||||
type CharContext struct {
|
||||
contextPath string
|
||||
pluginRegister *register.PluginRegister
|
||||
schema *schema.CharSchema
|
||||
}
|
||||
|
||||
func NewCharContext(ctx context.Context) (*CharContext, error) {
|
||||
localPath, err := FindLocalRoot(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gpp := provider.NewGitPluginProvider()
|
||||
|
||||
s, err := schema.ParseFile(ctx, ".char.yml")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
plugins, err := s.GetPlugins(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = gpp.FetchPlugins(ctx, s.Registry, plugins)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
builder := register.NewPluginRegisterBuilder()
|
||||
|
||||
for name, plugin := range plugins {
|
||||
builder = builder.Add(name.Hash(), plugin.Opts.Path)
|
||||
}
|
||||
|
||||
r, err := builder.Build(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &CharContext{
|
||||
contextPath: localPath,
|
||||
pluginRegister: r,
|
||||
schema: s,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (cc *CharContext) Close() {
|
||||
if err := cc.pluginRegister.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (cc *CharContext) About(ctx context.Context) ([]register.AboutItem, error) {
|
||||
return cc.pluginRegister.About(ctx)
|
||||
}
|
||||
|
||||
func (cc *CharContext) Do(ctx context.Context, clientName string, commandName string, args map[string]string) error {
|
||||
return cc.pluginRegister.Do(ctx, clientName, commandName, args)
|
||||
}
|
||||
57
pkg/charcontext/context_root.go
Normal file
57
pkg/charcontext/context_root.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package charcontext
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
var ErrNoContextFound = errors.New("could not find project root")
|
||||
|
||||
const CharFileName = ".char.yml"
|
||||
|
||||
func FindLocalRoot(ctx context.Context) (string, error) {
|
||||
curdir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return recursiveFindLocalRoot(ctx, curdir)
|
||||
|
||||
//output, err := exec.Command("git", "rev-parse", "--show-toplevel").CombinedOutput()
|
||||
//if err != nil {
|
||||
// return "", err
|
||||
//}
|
||||
//if len(output) == 0 {
|
||||
// return "", errors.New("could not find absolute path")
|
||||
//}
|
||||
//if _, err := os.Stat(string(output)); errors.Is(err, os.ErrNotExist) {
|
||||
// return "", fmt.Errorf("path does not exist %s", string(output))
|
||||
//}
|
||||
|
||||
//return string(output), nil
|
||||
}
|
||||
|
||||
func recursiveFindLocalRoot(ctx context.Context, localpath string) (string, error) {
|
||||
entries, err := os.ReadDir(localpath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if entry.Name() == CharFileName {
|
||||
return localpath, nil
|
||||
}
|
||||
}
|
||||
|
||||
if localpath == "/" {
|
||||
return "", ErrNoContextFound
|
||||
}
|
||||
|
||||
return recursiveFindLocalRoot(ctx, path.Dir(localpath))
|
||||
}
|
||||
|
||||
func ChangeToPath(_ context.Context, path string) error {
|
||||
return os.Chdir(path)
|
||||
}
|
||||
107
pkg/plugins/provider/git.go
Normal file
107
pkg/plugins/provider/git.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.front.kjuulh.io/kjuulh/char/pkg/schema"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type GitPluginProvider struct{}
|
||||
|
||||
func NewGitPluginProvider() *GitPluginProvider {
|
||||
return &GitPluginProvider{}
|
||||
}
|
||||
|
||||
func (gpp *GitPluginProvider) FetchPlugins(ctx context.Context, registry string, plugins schema.CharSchemaPlugins) error {
|
||||
errgroup, ctx := errgroup.WithContext(ctx)
|
||||
baseDir := ".char/plugins"
|
||||
if os.Getenv("CHAR_DEV_MODE") == "true" {
|
||||
if err := os.RemoveAll(baseDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := os.MkdirAll(baseDir, 0755); err != nil {
|
||||
return fmt.Errorf("path already exists cannot create: %w", err)
|
||||
}
|
||||
|
||||
for n, plugin := range plugins {
|
||||
n, plugin := n, plugin
|
||||
errgroup.Go(func() error {
|
||||
dest := fmt.Sprintf(
|
||||
"%s/%s",
|
||||
strings.TrimRight(baseDir, "/"), n.Hash(),
|
||||
)
|
||||
fileinfo, err := os.Stat(dest)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
log.Printf("fetching git plugin repo: %s", n)
|
||||
return gpp.FetchPlugin(
|
||||
ctx,
|
||||
registry,
|
||||
plugin,
|
||||
dest,
|
||||
)
|
||||
}
|
||||
if fileinfo.ModTime().Add(time.Hour * 1).Before(time.Now()) {
|
||||
log.Printf("fetching git plugin repo: %s as it is stale", n)
|
||||
return gpp.FetchPlugin(
|
||||
ctx,
|
||||
registry,
|
||||
plugin,
|
||||
dest,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
if err := errgroup.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gpp *GitPluginProvider) FetchPlugin(ctx context.Context, registry string, plugin *schema.CharSchemaPlugin, dest string) error {
|
||||
cloneUrl, err := plugin.Opts.GetCloneUrl(
|
||||
ctx,
|
||||
registry,
|
||||
&schema.CloneUrlOpt{
|
||||
Protocol: schema.GitProtocolSsh,
|
||||
SshUser: "git",
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(dest); !errors.Is(err, os.ErrNotExist) {
|
||||
if err = os.RemoveAll(dest); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
output, err := exec.Command(
|
||||
"git",
|
||||
"clone",
|
||||
"--depth=1",
|
||||
cloneUrl,
|
||||
dest,
|
||||
).CombinedOutput()
|
||||
if len(output) > 0 {
|
||||
log.Print(string(output))
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
29
pkg/register/plugin.go
Normal file
29
pkg/register/plugin.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package register
|
||||
|
||||
import "context"
|
||||
|
||||
type AboutCommand struct {
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Args []string `json:"args" yaml:"args"`
|
||||
Required []string `json:"required" yaml:"required"`
|
||||
}
|
||||
|
||||
type About struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
About string `json:"about"`
|
||||
Vars []string `json:"vars"`
|
||||
Commands []*AboutCommand `json:"commands"`
|
||||
}
|
||||
|
||||
type DoCommand struct {
|
||||
CommandName string `json:"commandName"`
|
||||
Args map[string]string `json:"args"`
|
||||
}
|
||||
|
||||
type Plugin interface {
|
||||
About(ctx context.Context) (*About, error)
|
||||
Do(ctx context.Context, cmd *DoCommand) error
|
||||
}
|
||||
|
||||
const PluginKey = "plugin"
|
||||
20
pkg/register/plugin_api.go
Normal file
20
pkg/register/plugin_api.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package register
|
||||
|
||||
import (
|
||||
"net/rpc"
|
||||
|
||||
"github.com/hashicorp/go-plugin"
|
||||
)
|
||||
|
||||
type PluginAPI struct {
|
||||
path string
|
||||
Impl Plugin
|
||||
}
|
||||
|
||||
func (pa *PluginAPI) Server(*plugin.MuxBroker) (any, error) {
|
||||
return &PluginServer{Impl: pa.Impl}, nil
|
||||
}
|
||||
|
||||
func (*PluginAPI) Client(b *plugin.MuxBroker, c *rpc.Client) (any, error) {
|
||||
return &PluginClient{client: c}, nil
|
||||
}
|
||||
48
pkg/register/plugin_builder.go
Normal file
48
pkg/register/plugin_builder.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package register
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
)
|
||||
|
||||
type PluginBuilder struct {
|
||||
serveConfig *plugin.ServeConfig
|
||||
}
|
||||
|
||||
func NewPluginBuilder(p Plugin) *PluginBuilder {
|
||||
logger := hclog.New(&hclog.LoggerOptions{
|
||||
Level: hclog.Debug,
|
||||
Output: os.Stderr,
|
||||
JSONFormat: false,
|
||||
})
|
||||
|
||||
var pluginMap = map[string]plugin.Plugin{
|
||||
PluginKey: &PluginAPI{
|
||||
Impl: p,
|
||||
},
|
||||
}
|
||||
|
||||
serveConfig := &plugin.ServeConfig{
|
||||
HandshakeConfig: plugin.HandshakeConfig{
|
||||
ProtocolVersion: 1,
|
||||
MagicCookieKey: "BASIC_PLUGIN",
|
||||
MagicCookieValue: "char",
|
||||
},
|
||||
Plugins: pluginMap,
|
||||
Logger: logger,
|
||||
}
|
||||
|
||||
return &PluginBuilder{
|
||||
serveConfig: serveConfig,
|
||||
}
|
||||
}
|
||||
|
||||
func (pr *PluginBuilder) Serve(ctx context.Context) error {
|
||||
plugin.Serve(
|
||||
pr.serveConfig,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
39
pkg/register/plugin_client.go
Normal file
39
pkg/register/plugin_client.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package register
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/rpc"
|
||||
)
|
||||
|
||||
type PluginClient struct {
|
||||
client *rpc.Client
|
||||
}
|
||||
|
||||
// Do implements Plugin
|
||||
func (pc *PluginClient) Do(ctx context.Context, cmd *DoCommand) error {
|
||||
err := pc.client.Call("Plugin.Do", cmd, new(string))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ Plugin = &PluginClient{}
|
||||
|
||||
func (pc *PluginClient) About(ctx context.Context) (*About, error) {
|
||||
var resp string
|
||||
err := pc.client.Call("Plugin.About", new(any), &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var about About
|
||||
err = json.Unmarshal([]byte(resp), &about)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &about, nil
|
||||
}
|
||||
248
pkg/register/plugin_register.go
Normal file
248
pkg/register/plugin_register.go
Normal file
@@ -0,0 +1,248 @@
|
||||
package register
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
type PluginRegisterBuilder struct {
|
||||
plugins map[string]PluginAPI
|
||||
}
|
||||
|
||||
func NewPluginRegisterBuilder() *PluginRegisterBuilder {
|
||||
return &PluginRegisterBuilder{
|
||||
plugins: make(map[string]PluginAPI),
|
||||
}
|
||||
}
|
||||
|
||||
func (pr *PluginRegisterBuilder) Add(name, path string) *PluginRegisterBuilder {
|
||||
pr.plugins[name] = PluginAPI{
|
||||
path: path,
|
||||
}
|
||||
|
||||
return pr
|
||||
}
|
||||
|
||||
func (pr *PluginRegisterBuilder) Build(ctx context.Context) (*PluginRegister, error) {
|
||||
clients := make(map[string]*pluginClientWrapper, 0)
|
||||
errgroup, _ := errgroup.WithContext(ctx)
|
||||
|
||||
if err := os.MkdirAll(".char/plugins/", 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for name, p := range pr.plugins {
|
||||
name, p := name, p
|
||||
|
||||
errgroup.Go(func() error {
|
||||
pluginPath := fmt.Sprintf(".char/plugins/%s/dist/plugin", name)
|
||||
|
||||
_, err := os.Stat(pluginPath)
|
||||
if err != nil || os.Getenv("CHAR_DEV_MODE") == "true" {
|
||||
log.Printf("building: %s", name)
|
||||
cmd := exec.Command(
|
||||
"sh",
|
||||
"-c",
|
||||
fmt.Sprintf(
|
||||
"(cd .char/plugins/%s; go build -o dist/plugin %s/main.go)",
|
||||
name,
|
||||
strings.TrimSuffix(
|
||||
strings.TrimSuffix(
|
||||
p.path,
|
||||
"main.go",
|
||||
),
|
||||
"/",
|
||||
),
|
||||
),
|
||||
)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if len(output) > 0 {
|
||||
log.Println(string(output))
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not build plugin: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
client := plugin.NewClient(&plugin.ClientConfig{
|
||||
HandshakeConfig: plugin.HandshakeConfig{
|
||||
ProtocolVersion: 1,
|
||||
MagicCookieKey: "BASIC_PLUGIN",
|
||||
MagicCookieValue: "char",
|
||||
},
|
||||
Logger: hclog.New(&hclog.LoggerOptions{
|
||||
Name: "char",
|
||||
Output: os.Stdout,
|
||||
Level: hclog.Debug,
|
||||
}),
|
||||
Cmd: exec.Command(
|
||||
fmt.Sprintf(
|
||||
".char/plugins/%s/dist/plugin",
|
||||
name,
|
||||
),
|
||||
),
|
||||
Plugins: map[string]plugin.Plugin{
|
||||
PluginKey: &p,
|
||||
},
|
||||
})
|
||||
|
||||
rpcClient, err := client.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
raw, err := rpcClient.Dispense("plugin")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pluginApi, ok := raw.(Plugin)
|
||||
if !ok {
|
||||
return errors.New("could not cast as plugin")
|
||||
}
|
||||
|
||||
clients[name] = &pluginClientWrapper{
|
||||
plugin: pluginApi,
|
||||
client: client,
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
err := errgroup.Wait()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &PluginRegister{
|
||||
clients: clients,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
type pluginClientWrapper struct {
|
||||
plugin Plugin
|
||||
client *plugin.Client
|
||||
}
|
||||
|
||||
func (pcw *pluginClientWrapper) Close() {
|
||||
pcw.client.Kill()
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
type PluginRegister struct {
|
||||
clients map[string]*pluginClientWrapper
|
||||
}
|
||||
|
||||
func (pr *PluginRegister) Close() error {
|
||||
errgroup, _ := errgroup.WithContext(context.Background())
|
||||
|
||||
for _, c := range pr.clients {
|
||||
c := c
|
||||
|
||||
errgroup.Go(func() error {
|
||||
c.Close()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if err := errgroup.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CommandAboutItem struct {
|
||||
Name string
|
||||
Args []string
|
||||
Required []string
|
||||
}
|
||||
|
||||
type CommandAboutItems []*CommandAboutItem
|
||||
|
||||
func FromAboutCommands(commands []*AboutCommand) CommandAboutItems {
|
||||
cai := make(CommandAboutItems, 0)
|
||||
for _, command := range commands {
|
||||
cai = append(cai, &CommandAboutItem{
|
||||
Name: command.Name,
|
||||
Args: command.Args,
|
||||
Required: command.Required,
|
||||
})
|
||||
}
|
||||
return cai
|
||||
}
|
||||
|
||||
type AboutItem struct {
|
||||
Name string
|
||||
Version string
|
||||
About string
|
||||
Vars []string
|
||||
Commands CommandAboutItems
|
||||
ClientName string
|
||||
}
|
||||
|
||||
func (pr *PluginRegister) About(ctx context.Context) ([]AboutItem, error) {
|
||||
list := make([]AboutItem, 0)
|
||||
|
||||
errgroup, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
for name, c := range pr.clients {
|
||||
name, c := name, c
|
||||
errgroup.Go(func() error {
|
||||
about, err := c.plugin.About(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
list = append(list, AboutItem{
|
||||
Name: about.Name,
|
||||
Version: about.Version,
|
||||
About: about.About,
|
||||
Vars: about.Vars,
|
||||
Commands: FromAboutCommands(about.Commands),
|
||||
ClientName: name,
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if err := errgroup.Wait(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (pr *PluginRegister) Do(ctx context.Context, clientName string, commandName string, args map[string]string) error {
|
||||
errgroup, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
client, ok := pr.clients[clientName]
|
||||
if !ok {
|
||||
return fmt.Errorf("plugin was not found: %s", clientName)
|
||||
}
|
||||
|
||||
errgroup.Go(func() error {
|
||||
return client.plugin.Do(ctx, &DoCommand{
|
||||
CommandName: commandName,
|
||||
Args: args,
|
||||
})
|
||||
})
|
||||
|
||||
if err := errgroup.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
44
pkg/register/plugin_server.go
Normal file
44
pkg/register/plugin_server.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package register
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type PluginServer struct {
|
||||
Impl Plugin
|
||||
}
|
||||
|
||||
func (ps *PluginServer) Do(args *DoCommand, resp *string) error {
|
||||
//rawReq, ok := args.(string)
|
||||
//if !ok {
|
||||
// return errors.New("args is not a string")
|
||||
//}
|
||||
|
||||
//var doReq DoRequest
|
||||
//if err := json.Unmarshal([]byte(rawReq), &doReq); err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
if err := ps.Impl.Do(context.Background(), args); err != nil {
|
||||
return err
|
||||
}
|
||||
*resp = ""
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ps *PluginServer) About(args any, resp *string) error {
|
||||
r, err := ps.Impl.About(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
respB, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*resp = string(respB)
|
||||
return nil
|
||||
}
|
||||
50
pkg/schema/schema.go
Normal file
50
pkg/schema/schema.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type CharSchema struct {
|
||||
Registry string `json:"registry" yaml:"registry"`
|
||||
Plugins CharSchemaPlugins `json:"plugins" yaml:"plugins"`
|
||||
}
|
||||
|
||||
func ParseFile(ctx context.Context, path string) (*CharSchema, error) {
|
||||
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
|
||||
return nil, fmt.Errorf("could not parse file, as it is not found or permitted: %s", path)
|
||||
}
|
||||
|
||||
file, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read file: %w", err)
|
||||
}
|
||||
|
||||
return Parse(file)
|
||||
}
|
||||
|
||||
func Parse(content []byte) (*CharSchema, error) {
|
||||
var schema CharSchema
|
||||
if err := yaml.Unmarshal(content, &schema); err != nil {
|
||||
return nil, fmt.Errorf("could not deserialize yaml into CharSchema: %w", err)
|
||||
}
|
||||
|
||||
return &schema, nil
|
||||
}
|
||||
|
||||
func (cs *CharSchema) GetPlugins(ctx context.Context) (CharSchemaPlugins, error) {
|
||||
plugins := make(map[CharSchemaPluginName]*CharSchemaPlugin, len(cs.Plugins))
|
||||
for n, plugin := range cs.Plugins {
|
||||
po, err := n.Get()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
plugin.Opts = po
|
||||
plugins[n] = plugin
|
||||
}
|
||||
return plugins, nil
|
||||
}
|
||||
104
pkg/schema/schema_plugin.go
Normal file
104
pkg/schema/schema_plugin.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package schema
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CharSchemaPluginName string
|
||||
|
||||
func (cspn CharSchemaPluginName) Hash() string {
|
||||
bytes := sha256.Sum256([]byte(cspn))
|
||||
return hex.EncodeToString(bytes[:])
|
||||
}
|
||||
|
||||
type PluginOps struct {
|
||||
Org string
|
||||
RepositoryName string
|
||||
Path string
|
||||
Version string
|
||||
}
|
||||
|
||||
type GitProtocol string
|
||||
|
||||
const (
|
||||
GitProtocolHttps GitProtocol = "https"
|
||||
GitProtocolSsh = "ssh"
|
||||
)
|
||||
|
||||
type CloneUrlOpt struct {
|
||||
Protocol GitProtocol
|
||||
SshUser string
|
||||
}
|
||||
|
||||
func (po *PluginOps) GetCloneUrl(ctx context.Context, registry string, opt *CloneUrlOpt) (string, error) {
|
||||
if opt == nil {
|
||||
return "", errors.New("opt is required")
|
||||
}
|
||||
switch opt.Protocol {
|
||||
case GitProtocolHttps:
|
||||
return fmt.Sprintf("https://%s/%s/%s.git", registry, po.Org, po.RepositoryName), nil
|
||||
case GitProtocolSsh:
|
||||
return fmt.Sprintf("%s@%s:%s/%s.git", opt.SshUser, registry, po.Org, po.RepositoryName), nil
|
||||
default:
|
||||
return "", errors.New("protocol not allowed")
|
||||
}
|
||||
}
|
||||
|
||||
var memo = map[string]*PluginOps{}
|
||||
|
||||
func (cspn CharSchemaPluginName) Get() (*PluginOps, error) {
|
||||
if m, ok := memo[string(cspn)]; ok {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
po := &PluginOps{}
|
||||
reg := regexp.MustCompile(
|
||||
`(?P<org>[\d\w\-_\.]+)\/(?P<repo>[\d\w\-_\.]+)(?P<path>#[\d\w\-_\.\/]+)?(?P<version>@[\d\w\-_\.\/]+)?(?P<path>#[\d\w\-_\.\/]+)?`,
|
||||
)
|
||||
matches := reg.FindStringSubmatch(string(cspn))
|
||||
tags := reg.SubexpNames()
|
||||
|
||||
matchTags := make(map[string]string, len(matches))
|
||||
for i, match := range matches {
|
||||
tag := tags[i]
|
||||
if existingTag, ok := matchTags[tag]; !ok || existingTag == "" {
|
||||
matchTags[tag] = match
|
||||
}
|
||||
}
|
||||
|
||||
if org, ok := matchTags["org"]; ok {
|
||||
po.Org = org
|
||||
}
|
||||
if repo, ok := matchTags["repo"]; ok {
|
||||
po.RepositoryName = repo
|
||||
}
|
||||
if path, ok := matchTags["path"]; ok {
|
||||
po.Path = strings.TrimLeft(path, "#")
|
||||
}
|
||||
if version, ok := matchTags["version"]; ok {
|
||||
po.Version = strings.TrimLeft(version, "@")
|
||||
}
|
||||
|
||||
if po.Org == "" || po.RepositoryName == "" {
|
||||
return nil, errors.New("could not find org or repository name")
|
||||
}
|
||||
|
||||
memo[string(cspn)] = po
|
||||
|
||||
return po, nil
|
||||
}
|
||||
|
||||
type CharSchemaPlugins map[CharSchemaPluginName]*CharSchemaPlugin
|
||||
type CharSchemaPluginVarName string
|
||||
type CharSchemaPluginVars map[CharSchemaPluginVarName]string
|
||||
|
||||
type CharSchemaPlugin struct {
|
||||
Opts *PluginOps
|
||||
Vars CharSchemaPluginVars `json:"vars"`
|
||||
}
|
||||
126
pkg/schema/schema_plugin_test.go
Normal file
126
pkg/schema/schema_plugin_test.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package schema_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"git.front.kjuulh.io/kjuulh/char/pkg/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSchemaNameCanParse(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tt := []struct {
|
||||
name string
|
||||
inputString schema.CharSchemaPluginName
|
||||
expected schema.PluginOps
|
||||
}{
|
||||
{
|
||||
name: "default string",
|
||||
inputString: `kju123K_-ulh/someRepo-._123`,
|
||||
expected: schema.PluginOps{
|
||||
Org: "kju123K_-ulh",
|
||||
RepositoryName: "someRepo-._123",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "default string with path",
|
||||
inputString: `kju123K_-ulh/someRepo-._123#somepath/sometoherpath/somethridpath`,
|
||||
expected: schema.PluginOps{
|
||||
Org: "kju123K_-ulh",
|
||||
RepositoryName: "someRepo-._123",
|
||||
Path: "somepath/sometoherpath/somethridpath",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "default string with version",
|
||||
inputString: `kju123K_-ulh/someRepo-._123@12l3.jk1lj`,
|
||||
expected: schema.PluginOps{
|
||||
Org: "kju123K_-ulh",
|
||||
RepositoryName: "someRepo-._123",
|
||||
Version: "12l3.jk1lj",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "default string with version and path",
|
||||
inputString: `kju123K_-ulh/someRepo-._123@12l3.jk1lj#somepath/sometoherpath/somethridpath`,
|
||||
expected: schema.PluginOps{
|
||||
Org: "kju123K_-ulh",
|
||||
RepositoryName: "someRepo-._123",
|
||||
Version: "12l3.jk1lj",
|
||||
Path: "somepath/sometoherpath/somethridpath",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "default string with path and version",
|
||||
inputString: `kju123K_-ulh/someRepo-._123#somepath/sometoherpath/somethridpath@12l3.jk1lj`,
|
||||
expected: schema.PluginOps{
|
||||
Org: "kju123K_-ulh",
|
||||
RepositoryName: "someRepo-._123",
|
||||
Version: "12l3.jk1lj",
|
||||
Path: "somepath/sometoherpath/somethridpath",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
actual, _ := tc.inputString.Get()
|
||||
require.Equal(t, tc.expected, *actual)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluginOpt(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tt := []struct {
|
||||
name string
|
||||
pluginOpt schema.PluginOps
|
||||
cloneUrlOpt schema.CloneUrlOpt
|
||||
registry string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "ssh values",
|
||||
pluginOpt: schema.PluginOps{
|
||||
Org: "kjuulh",
|
||||
RepositoryName: "char",
|
||||
Path: "",
|
||||
Version: "",
|
||||
},
|
||||
cloneUrlOpt: schema.CloneUrlOpt{
|
||||
Protocol: schema.GitProtocolSsh,
|
||||
SshUser: "git",
|
||||
},
|
||||
registry: "git.front.kjuulh.io",
|
||||
expected: "git@git.front.kjuulh.io:kjuulh/char.git",
|
||||
},
|
||||
{
|
||||
name: "https values",
|
||||
pluginOpt: schema.PluginOps{
|
||||
Org: "kjuulh",
|
||||
RepositoryName: "char",
|
||||
Path: "",
|
||||
Version: "",
|
||||
},
|
||||
cloneUrlOpt: schema.CloneUrlOpt{
|
||||
Protocol: schema.GitProtocolHttps,
|
||||
},
|
||||
registry: "git.front.kjuulh.io",
|
||||
expected: "https://git.front.kjuulh.io/kjuulh/char.git",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
url, err := tc.pluginOpt.GetCloneUrl(context.Background(), tc.registry, &tc.cloneUrlOpt)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.expected, url)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
93
pkg/schema/schema_test.go
Normal file
93
pkg/schema/schema_test.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package schema_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"git.front.kjuulh.io/kjuulh/char/pkg/schema"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSchemaParse(t *testing.T) {
|
||||
t.Parallel()
|
||||
tt := []struct {
|
||||
name string
|
||||
input string
|
||||
expected *schema.CharSchema
|
||||
}{
|
||||
{
|
||||
name: "with plugins",
|
||||
input: `
|
||||
registry: git.front.kjuulh.io
|
||||
plugins:
|
||||
"kjuulh/char#plugins/gocli": {}
|
||||
"kjuulh/char#plugins/rust": {}
|
||||
`,
|
||||
expected: &schema.CharSchema{
|
||||
Registry: "git.front.kjuulh.io",
|
||||
Plugins: map[schema.CharSchemaPluginName]*schema.CharSchemaPlugin{
|
||||
"kjuulh/char#plugins/gocli": {},
|
||||
"kjuulh/char#plugins/rust": {},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
s, err := schema.Parse([]byte(tc.input))
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.expected, s)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPlugins(t *testing.T) {
|
||||
t.Parallel()
|
||||
tt := []struct {
|
||||
name string
|
||||
input string
|
||||
expected schema.CharSchemaPlugins
|
||||
}{
|
||||
{
|
||||
name: "with plugins",
|
||||
input: `
|
||||
registry: git.front.kjuulh.io
|
||||
plugins:
|
||||
"kjuulh/char#plugins/gocli@v1.9.0": {}
|
||||
"kjuulh/char#plugins/rust": {}
|
||||
`,
|
||||
expected: map[schema.CharSchemaPluginName]*schema.CharSchemaPlugin{
|
||||
"kjuulh/char#plugins/gocli@v1.9.0": {
|
||||
Opts: &schema.PluginOps{
|
||||
Org: "kjuulh",
|
||||
RepositoryName: "char",
|
||||
Path: "plugins/gocli",
|
||||
Version: "v1.9.0",
|
||||
},
|
||||
},
|
||||
"kjuulh/char#plugins/rust": {
|
||||
Opts: &schema.PluginOps{
|
||||
Org: "kjuulh",
|
||||
RepositoryName: "char",
|
||||
Path: "plugins/rust",
|
||||
Version: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
s, err := schema.Parse([]byte(tc.input))
|
||||
require.NoError(t, err)
|
||||
|
||||
plugins, err := s.GetPlugins(context.Background())
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, tc.expected, plugins)
|
||||
})
|
||||
}
|
||||
}
|
||||
47
plugins/gocli/main.go
Normal file
47
plugins/gocli/main.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"git.front.kjuulh.io/kjuulh/char/pkg/register"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
type GoCliPlugin struct{}
|
||||
|
||||
// Do implements register.Plugin
|
||||
func (*GoCliPlugin) Do(ctx context.Context, cmd *register.DoCommand) error {
|
||||
hclog.L().Info("received command", "commandName", cmd.CommandName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*GoCliPlugin) About(ctx context.Context) (*register.About, error) {
|
||||
return ®ister.About{
|
||||
Name: "gocli",
|
||||
Version: "v0.0.1",
|
||||
About: "golang cli provides a set of actions and presets supporting golang development",
|
||||
Vars: []string{
|
||||
"dev.mode",
|
||||
},
|
||||
Commands: []*register.AboutCommand{
|
||||
{
|
||||
Name: "local_up",
|
||||
Args: []string{"fish"},
|
||||
Required: []string{"fish"},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
var _ register.Plugin = &GoCliPlugin{}
|
||||
|
||||
func main() {
|
||||
if err := register.
|
||||
NewPluginBuilder(
|
||||
&GoCliPlugin{},
|
||||
).
|
||||
Serve(context.Background()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
37
plugins/rust/main.go
Normal file
37
plugins/rust/main.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"git.front.kjuulh.io/kjuulh/char/pkg/register"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
type GoCliPlugin struct{}
|
||||
|
||||
// Do implements register.Plugin
|
||||
func (*GoCliPlugin) Do(ctx context.Context, cmd *register.DoCommand) error {
|
||||
hclog.L().Info("received command", "commandName", cmd.CommandName)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*GoCliPlugin) About(ctx context.Context) (*register.About, error) {
|
||||
return ®ister.About{
|
||||
Name: "rust",
|
||||
Version: "v0.0.1",
|
||||
About: "rust cli provides a set of actions and presets supporting rust development",
|
||||
}, nil
|
||||
}
|
||||
|
||||
var _ register.Plugin = &GoCliPlugin{}
|
||||
|
||||
func main() {
|
||||
if err := register.
|
||||
NewPluginBuilder(
|
||||
&GoCliPlugin{},
|
||||
).
|
||||
Serve(context.Background()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
3
renovate.json
Normal file
3
renovate.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||
}
|
||||
44
src/cli.rs
44
src/cli.rs
@@ -1,44 +0,0 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{
|
||||
deps,
|
||||
resolvers::{install, Resolver},
|
||||
};
|
||||
|
||||
pub struct Cli {
|
||||
deps: deps::Deps,
|
||||
install: Box<dyn Resolver + Send + Sync>,
|
||||
}
|
||||
|
||||
impl Cli {
|
||||
pub fn new(deps: deps::Deps) -> eyre::Result<Self> {
|
||||
Ok(Self {
|
||||
deps: deps.clone(),
|
||||
install: install::Install::new(deps),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn matches(self, args: &[&str]) -> eyre::Result<()> {
|
||||
let mut cli = clap::Command::new("char")
|
||||
.arg(clap::Arg::new("path").long("path").short('p'))
|
||||
.subcommand(self.install.cmd()?);
|
||||
|
||||
let matches = cli.clone().get_matches_from(args);
|
||||
|
||||
let path = matches.get_one::<String>("path");
|
||||
if let Some(p) = path {
|
||||
let path = PathBuf::from(p);
|
||||
if !path.exists() {
|
||||
eyre::bail!("no char.toml exists at --path")
|
||||
}
|
||||
self.deps.parser.set_path(path);
|
||||
}
|
||||
|
||||
match matches.subcommand() {
|
||||
Some(("install", args)) => self.install.matches(args)?,
|
||||
_ => cli.print_help()?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
use crate::models::Char;
|
||||
|
||||
pub struct Context {}
|
||||
|
||||
impl Context {
|
||||
pub fn new(chars: Vec<Char>) -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ContextBuilder {
|
||||
chars: Vec<Char>,
|
||||
}
|
||||
|
||||
impl ContextBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self { chars: vec![] }
|
||||
}
|
||||
|
||||
pub fn add_char(mut self, char: &Char) -> Self {
|
||||
self.chars.push(char.clone());
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Context {
|
||||
Context::new(self.chars)
|
||||
}
|
||||
}
|
||||
33
src/deps.rs
33
src/deps.rs
@@ -1,33 +0,0 @@
|
||||
use std::{ops::Deref, sync::Arc};
|
||||
|
||||
use crate::{parser::Parser, services::downloader::Downloader};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Deps {
|
||||
inner: Arc<InnerDeps>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InnerDeps {
|
||||
pub parser: Parser,
|
||||
pub downloader: Downloader,
|
||||
}
|
||||
|
||||
impl Default for Deps {
|
||||
fn default() -> Self {
|
||||
let parser = Parser::default();
|
||||
let downloader = Downloader::new(parser.clone());
|
||||
|
||||
Self {
|
||||
inner: Arc::new(InnerDeps { parser, downloader }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Deps {
|
||||
type Target = Arc<InnerDeps>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
32
src/main.rs
32
src/main.rs
@@ -1,32 +0,0 @@
|
||||
pub mod cli;
|
||||
mod deps;
|
||||
mod models;
|
||||
mod parser;
|
||||
mod resolvers;
|
||||
mod services;
|
||||
mod context;
|
||||
|
||||
fn main() -> eyre::Result<()> {
|
||||
color_eyre::install()?;
|
||||
|
||||
let args = std::env::args();
|
||||
|
||||
let deps = deps::Deps::default();
|
||||
|
||||
let c = cli::Cli::new(deps)?;
|
||||
c.matches(
|
||||
args.collect::<Vec<String>>()
|
||||
.iter()
|
||||
.map(|s| s.as_str())
|
||||
.collect::<Vec<&str>>()
|
||||
.as_slice(),
|
||||
)?;
|
||||
|
||||
let p = std::path::PathBuf::from("examples/service/char.toml");
|
||||
|
||||
let char = std::fs::read_to_string(p)?.parse::<models::Char>()?;
|
||||
|
||||
dbg!(char);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
type Overrides = BTreeMap<String, String>;
|
||||
type Dependencies = Vec<String>;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct Conf {
|
||||
pub plan: String,
|
||||
pub dependencies: Option<Dependencies>,
|
||||
pub overrides: Option<Overrides>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct Application {
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct Plan {
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(untagged)]
|
||||
pub enum Char {
|
||||
Application {
|
||||
char: Option<Conf>,
|
||||
application: Application,
|
||||
config: BTreeMap<String, toml::Value>,
|
||||
},
|
||||
Plan {
|
||||
char: Option<Conf>,
|
||||
plan: Plan,
|
||||
config: BTreeMap<String, toml::Value>,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::str::FromStr for Char {
|
||||
type Err = eyre::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let t: Char = toml::from_str(s)?;
|
||||
|
||||
Ok(t)
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
use std::{
|
||||
path::PathBuf,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
use eyre::Context;
|
||||
|
||||
use crate::models::{self, Char};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Parser {
|
||||
path: Arc<RwLock<Option<PathBuf>>>,
|
||||
}
|
||||
|
||||
impl Parser {
|
||||
pub fn new(path: PathBuf) -> Self {
|
||||
Self {
|
||||
path: Arc::new(RwLock::new(Some(path))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_path(&self, path: PathBuf) {
|
||||
let mut writer = self.path.write().unwrap();
|
||||
*writer = Some(path);
|
||||
}
|
||||
|
||||
pub fn get_path(&self) -> eyre::Result<PathBuf> {
|
||||
let read_path = self.path.read().unwrap();
|
||||
let path = match read_path.clone() {
|
||||
Some(p) => p,
|
||||
None => todo!(), // find using git later on
|
||||
};
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
pub fn parse(&self) -> eyre::Result<models::Char> {
|
||||
let mut path = self.get_path()?;
|
||||
if !path.ends_with("char.toml") {
|
||||
path.push("char.toml")
|
||||
}
|
||||
let contents =
|
||||
std::fs::read_to_string(&path).context("char.toml doesn't exist at that path")?;
|
||||
|
||||
contents.parse::<Char>()
|
||||
}
|
||||
|
||||
pub fn parse_from(&self, path: &PathBuf) -> eyre::Result<models::Char> {
|
||||
let contents =
|
||||
std::fs::read_to_string(path).context("char.toml doesn't exist at that path")?;
|
||||
|
||||
contents.parse::<Char>()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Parser {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
path: Arc::new(RwLock::new(None)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
use crate::deps;
|
||||
|
||||
use super::{DynResolver, Resolver};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Install {
|
||||
deps: deps::Deps,
|
||||
}
|
||||
|
||||
impl Install {
|
||||
pub fn new(deps: deps::Deps) -> DynResolver {
|
||||
Box::new(Self { deps })
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolver for Install {
|
||||
fn cmd(&self) -> eyre::Result<clap::Command> {
|
||||
let install = clap::Command::new("install");
|
||||
|
||||
Ok(install)
|
||||
}
|
||||
|
||||
fn matches(&self, _args: &clap::ArgMatches) -> eyre::Result<()> {
|
||||
self.deps.downloader.download()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
pub(crate) mod install;
|
||||
|
||||
pub trait Resolver {
|
||||
fn cmd(&self) -> eyre::Result<clap::Command>;
|
||||
fn matches(&self, args: &clap::ArgMatches) -> eyre::Result<()>;
|
||||
}
|
||||
|
||||
pub type DynResolver = Box<dyn Resolver + Send + Sync>;
|
||||
@@ -1,96 +0,0 @@
|
||||
use std::{fs::canonicalize, path::PathBuf};
|
||||
|
||||
use crate::{
|
||||
context::{Context, ContextBuilder},
|
||||
models::{Char, Conf},
|
||||
parser::Parser,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Downloader {
|
||||
parser: Parser,
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
impl Downloader {
|
||||
pub fn new(parser: Parser) -> Self {
|
||||
Self { parser }
|
||||
}
|
||||
|
||||
/// Unfolds char
|
||||
/// 1. Download path
|
||||
/// 2. Parse char in downloaded path
|
||||
/// 3. Repeat from 1. until there are no more parents
|
||||
pub fn download(&self) -> eyre::Result<Context> {
|
||||
let mut context_builder = ContextBuilder::new();
|
||||
|
||||
let char = self.parser.parse()?;
|
||||
context_builder = context_builder.add_char(&char);
|
||||
let first_char_path = self.parser.get_path()?;
|
||||
|
||||
let mut root = std::env::current_dir()?;
|
||||
root = root.join(&first_char_path);
|
||||
root.push(".char");
|
||||
let output = self.create_output_dir(&root)?;
|
||||
|
||||
let mut parent_char = char;
|
||||
let path = first_char_path;
|
||||
loop {
|
||||
parent_char = match &parent_char {
|
||||
Char::Application {
|
||||
char,
|
||||
application: _,
|
||||
config: _,
|
||||
} => match char {
|
||||
Some(c) => self.download_plan(c, &path, &output)?,
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
},
|
||||
Char::Plan {
|
||||
char,
|
||||
plan: _,
|
||||
config: _,
|
||||
} => match char {
|
||||
Some(_c) => todo!(),
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(context_builder.build())
|
||||
}
|
||||
|
||||
fn download_plan(
|
||||
&self,
|
||||
conf: &Conf,
|
||||
path: &PathBuf,
|
||||
output_path: &PathBuf,
|
||||
) -> eyre::Result<Char> {
|
||||
let plan = &conf.plan;
|
||||
|
||||
// TODO: decide whether it is a file or a git repo
|
||||
// TODO: Starting with files only, as such implement git repo later
|
||||
|
||||
let path_buf = std::path::PathBuf::from(plan);
|
||||
let path = path.join(path_buf);
|
||||
if !path.exists() {
|
||||
eyre::bail!("path doesn't exist: {}", path.to_string_lossy())
|
||||
}
|
||||
let path = canonicalize(path)?;
|
||||
|
||||
dbg!(path);
|
||||
dbg!(output_path);
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn create_output_dir(&self, root: &PathBuf) -> eyre::Result<PathBuf> {
|
||||
let mut output = root.clone();
|
||||
output.push("plans");
|
||||
std::fs::create_dir_all(&output)?;
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod downloader;
|
||||
Reference in New Issue
Block a user