File kubie-0.26.0.obscpio of Package kubie
07070100000000000041ED00000000000000000000000268642C2300000000000000000000000000000000000000000000001500000000kubie-0.26.0/.github07070100000001000081A400000000000000000000000168642C2300000268000000000000000000000000000000000000002400000000kubie-0.26.0/.github/dependabot.yml# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "cargo" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"
groups:
all:
patterns:
- "*"
update-types:
- "minor"
- "patch"
07070100000002000041ED00000000000000000000000268642C2300000000000000000000000000000000000000000000001F00000000kubie-0.26.0/.github/workflows07070100000003000081A400000000000000000000000168642C2300000E6E000000000000000000000000000000000000002B00000000kubie-0.26.0/.github/workflows/release.ymlname: Release
on:
push:
tags:
- '*'
jobs:
build-linux-amd64-static:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: x86_64-unknown-linux-musl
- run: sudo apt-get update && sudo apt-get install -y musl-tools
- uses: actions-rs/cargo@v1
with:
command: build
args: --release --target x86_64-unknown-linux-musl
- uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: target/x86_64-unknown-linux-musl/release/kubie
asset_name: kubie-linux-amd64
tag: ${{ github.ref }}
build-linux-arm32-static:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: arm-unknown-linux-musleabi
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target arm-unknown-linux-musleabi
- uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: target/arm-unknown-linux-musleabi/release/kubie
asset_name: kubie-linux-arm32
tag: ${{ github.ref }}
build-linux-arm64-static:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-unknown-linux-musl
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: build
args: --release --target aarch64-unknown-linux-musl
- uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: target/aarch64-unknown-linux-musl/release/kubie
asset_name: kubie-linux-arm64
tag: ${{ github.ref }}
build-macos-amd64:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: x86_64-apple-darwin
- run: SDKROOT=$(xcrun --sdk macosx --show-sdk-path) MACOSX_DEPLOYMENT_TARGET=11.0 cargo build --release --target x86_64-apple-darwin
- uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: target/x86_64-apple-darwin/release/kubie
asset_name: kubie-darwin-amd64
tag: ${{ github.ref }}
build-macos-arm64:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-apple-darwin
- run: SDKROOT=$(xcrun --sdk macosx --show-sdk-path) MACOSX_DEPLOYMENT_TARGET=11.0 cargo build --release --target aarch64-apple-darwin
- uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: target/aarch64-apple-darwin/release/kubie
asset_name: kubie-darwin-arm64
tag: ${{ github.ref }}
publish-crates-io:
name: Publish to crates.io
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v3
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- run: cargo publish --token ${CRATES_TOKEN}
env:
CRATES_TOKEN: ${{ secrets.CRATES_TOKEN }}
07070100000004000081A400000000000000000000000168642C230000078E000000000000000000000000000000000000002800000000kubie-0.26.0/.github/workflows/test.ymlname: Test
on:
push:
branches:
- master
pull_request:
jobs:
test-linux-amd64:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- uses: actions-rs/cargo@v1
with:
command: test
args: --all-features
test-linux-arm32:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: arm-unknown-linux-musleabi
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: test
args: --all-features --target arm-unknown-linux-musleabi
test-linux-arm64:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-unknown-linux-musl
override: true
- uses: actions-rs/cargo@v1
with:
use-cross: true
command: test
args: --all-features --target aarch64-unknown-linux-musl
test-macos-amd64:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- uses: actions-rs/cargo@v1
with:
command: test
args: --all-features
# We use an amd64 machine to cross compile for arm64. We cannot run the tests,
# only verify that the project compiles well.
build-macos-arm64:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: aarch64-apple-darwin
- run: SDKROOT=$(xcrun --sdk macosx --show-sdk-path) MACOSX_DEPLOYMENT_TARGET=11.0 cargo build --all-features --target aarch64-apple-darwin
07070100000005000081A400000000000000000000000168642C230000001D000000000000000000000000000000000000001800000000kubie-0.26.0/.gitignore/target
**/*.rs.bk
/binaries
07070100000006000081A400000000000000000000000168642C230000D768000000000000000000000000000000000000001800000000kubie-0.26.0/Cargo.lock# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "adler2"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[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.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
dependencies = [
"anstyle",
"once_cell",
"windows-sys 0.59.0",
]
[[package]]
name = "anyhow"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "arrayvec"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "attohttpc"
version = "0.29.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48404d931ab11b3a7a5267291b3b8f3590f09b86181381f8e82a7e562ed832c0"
dependencies = [
"base64",
"flate2",
"http",
"log",
"rustls",
"rustls-native-certs",
"serde",
"serde_json",
"url",
]
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "aws-lc-fips-sys"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29003a681b2b9465c1139bfb726da452a841a8b025f35953f3bce71139f10b21"
dependencies = [
"bindgen",
"cc",
"cmake",
"dunce",
"fs_extra",
"paste",
"regex",
]
[[package]]
name = "aws-lc-rs"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7"
dependencies = [
"aws-lc-fips-sys",
"aws-lc-sys",
"zeroize",
]
[[package]]
name = "aws-lc-sys"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079"
dependencies = [
"bindgen",
"cc",
"cmake",
"dunce",
"fs_extra",
]
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "beef"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
[[package]]
name = "bindgen"
version = "0.69.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
dependencies = [
"bitflags 2.8.0",
"cexpr",
"clang-sys",
"itertools",
"lazy_static",
"lazycell",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn",
"which 4.4.2",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "bstr"
version = "1.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
dependencies = [
"memchr",
"regex-automata",
"serde",
]
[[package]]
name = "bumpalo"
version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
[[package]]
name = "cc"
version = "1.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c736e259eea577f443d5c86c304f9f4ae0295c43f3ba05c21f1d66b5f06001af"
dependencies = [
"jobserver",
"libc",
"shlex",
]
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
version = "0.4.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-link",
]
[[package]]
name = "clang-sys"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "clap"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_complete"
version = "4.5.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aad5b1b4de04fead402672b48897030eec1f3bfe1550776322f59f6d6e6a5677"
dependencies = [
"clap",
]
[[package]]
name = "clap_derive"
version = "4.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
dependencies = [
"anstyle",
"heck",
"proc-macro2",
"pulldown-cmark",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
[[package]]
name = "cmake"
version = "0.1.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
dependencies = [
"cc",
]
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "core-foundation"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "crc32fast"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if",
]
[[package]]
name = "crossbeam"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-epoch",
"crossbeam-queue",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-queue"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "darling"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.20.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [
"darling_core",
"quote",
"syn",
]
[[package]]
name = "defer-drop"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f613ec9fa66a6b28cdb1842b27f9adf24f39f9afc4dcdd9fdecee4aca7945c57"
dependencies = [
"crossbeam-channel",
"once_cell",
]
[[package]]
name = "deranged"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
dependencies = [
"powerfmt",
]
[[package]]
name = "derive_builder"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
dependencies = [
"derive_builder_macro",
]
[[package]]
name = "derive_builder_core"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "derive_builder_macro"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
dependencies = [
"derive_builder_core",
"syn",
]
[[package]]
name = "dirs"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
dependencies = [
"libc",
"option-ext",
"redox_users 0.5.0",
"windows-sys 0.59.0",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users 0.4.6",
"winapi",
]
[[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 = "dunce"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[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_home"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
[[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.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [
"libc",
"windows-sys 0.59.0",
]
[[package]]
name = "fastrand"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "flate2"
version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[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 = "fs2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "fs_extra"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
[[package]]
name = "fuzzy-matcher"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94"
dependencies = [
"thread_local",
]
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
dependencies = [
"cfg-if",
"libc",
"wasi 0.13.3+wasi-0.2.2",
"windows-targets",
]
[[package]]
name = "glob"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "home"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "http"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "iana-time-zone"
version = "0.1.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[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 = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[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.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "jobserver"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
dependencies = [
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "kubie"
version = "0.26.0"
dependencies = [
"anyhow",
"attohttpc",
"aws-lc-rs",
"cfg-if",
"clap",
"dirs",
"fs2",
"glob",
"lazy_static",
"libc",
"serde",
"serde_json",
"serde_yaml",
"signal-hook",
"skim",
"tempfile",
"which 7.0.2",
"wildmatch",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]]
name = "libloading"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets",
]
[[package]]
name = "libredox"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags 2.8.0",
"libc",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9"
[[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.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "miniz_oxide"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
dependencies = [
"adler2",
]
[[package]]
name = "nix"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags 2.8.0",
"cfg-if",
"cfg_aliases",
"libc",
]
[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
dependencies = [
"memchr",
"minimal-lexical",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
[[package]]
name = "openssl-probe"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "percent-encoding"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
dependencies = [
"zerocopy 0.7.35",
]
[[package]]
name = "prettyplease"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "proc-macro2"
version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
[[package]]
name = "pulldown-cmark"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0"
dependencies = [
"bitflags 2.8.0",
"memchr",
"unicase",
]
[[package]]
name = "quote"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [
"rand_chacha",
"rand_core",
"zerocopy 0.8.23",
]
[[package]]
name = "rand_chacha"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
dependencies = [
"getrandom 0.3.1",
]
[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "redox_users"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom 0.2.15",
"libredox",
"thiserror 1.0.69",
]
[[package]]
name = "redox_users"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
dependencies = [
"getrandom 0.2.15",
"libredox",
"thiserror 2.0.11",
]
[[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 = "ring"
version = "0.17.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
dependencies = [
"cc",
"cfg-if",
"getrandom 0.2.15",
"libc",
"untrusted",
"windows-sys 0.52.0",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
"bitflags 2.8.0",
"errno",
"libc",
"linux-raw-sys 0.4.15",
"windows-sys 0.59.0",
]
[[package]]
name = "rustix"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825"
dependencies = [
"bitflags 2.8.0",
"errno",
"libc",
"linux-raw-sys 0.9.2",
"windows-sys 0.59.0",
]
[[package]]
name = "rustls"
version = "0.23.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395"
dependencies = [
"aws-lc-rs",
"log",
"once_cell",
"rustls-pki-types",
"rustls-webpki",
"subtle",
"zeroize",
]
[[package]]
name = "rustls-native-certs"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3"
dependencies = [
"openssl-probe",
"rustls-pki-types",
"schannel",
"security-framework",
]
[[package]]
name = "rustls-pki-types"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
[[package]]
name = "rustls-webpki"
version = "0.102.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
dependencies = [
"aws-lc-rs",
"ring",
"rustls-pki-types",
"untrusted",
]
[[package]]
name = "rustversion"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
[[package]]
name = "ryu"
version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
[[package]]
name = "schannel"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "security-framework"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316"
dependencies = [
"bitflags 2.8.0",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
]
[[package]]
name = "shell-quote"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb502615975ae2365825521fa1529ca7648fd03ce0b0746604e0683856ecd7e4"
dependencies = [
"bstr",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
dependencies = [
"libc",
]
[[package]]
name = "skim"
version = "0.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19a285c48e203135e5d58eb0fc632e3303c127f2056c8e50c8a11c504b7132b4"
dependencies = [
"beef",
"bitflags 1.3.2",
"chrono",
"clap",
"clap_complete",
"crossbeam",
"defer-drop",
"derive_builder",
"env_logger",
"fuzzy-matcher",
"indexmap",
"log",
"nix",
"rand",
"rayon",
"regex",
"shell-quote",
"shlex",
"skim-common",
"skim-tuikit",
"time",
"timer",
"unicode-width",
"vte",
"which 7.0.2",
]
[[package]]
name = "skim-common"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8312ae7ca1a5883e68042b9c6bce05bfc12f06b814ecfda06c34abfb6c88175"
[[package]]
name = "skim-tuikit"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fa16dc8ef0aa72471eb80bf1d43b62e841abf1cd2429216c44cdfd886545f0"
dependencies = [
"bitflags 1.3.2",
"lazy_static",
"log",
"nix",
"skim-common",
"term",
"unicode-width",
]
[[package]]
name = "smallvec"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
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 = "tempfile"
version = "3.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
dependencies = [
"fastrand",
"getrandom 0.3.1",
"once_cell",
"rustix 1.0.2",
"windows-sys 0.59.0",
]
[[package]]
name = "term"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
dependencies = [
"dirs-next",
"rustversion",
"winapi",
]
[[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.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc"
dependencies = [
"thiserror-impl 2.0.11",
]
[[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.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
dependencies = [
"cfg-if",
"once_cell",
]
[[package]]
name = "time"
version = "0.3.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
dependencies = [
"deranged",
"num-conv",
"powerfmt",
"serde",
"time-core",
]
[[package]]
name = "time-core"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
[[package]]
name = "timer"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31d42176308937165701f50638db1c31586f183f1aab416268216577aec7306b"
dependencies = [
"chrono",
]
[[package]]
name = "tinystr"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
dependencies = [
"displaydoc",
"zerovec",
]
[[package]]
name = "unicase"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
[[package]]
name = "unicode-ident"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
[[package]]
name = "unicode-width"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
[[package]]
name = "unsafe-libyaml"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "untrusted"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[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 = "vte"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5924018406ce0063cd67f8e008104968b74b563ee1b85dde3ed1f7cb87d3dbd"
dependencies = [
"arrayvec",
"memchr",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasi"
version = "0.13.3+wasi-0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
dependencies = [
"wit-bindgen-rt",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix 0.38.44",
]
[[package]]
name = "which"
version = "7.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2774c861e1f072b3aadc02f8ba886c26ad6321567ecc294c935434cad06f1283"
dependencies = [
"either",
"env_home",
"rustix 0.38.44",
"winsafe",
]
[[package]]
name = "wildmatch"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ce1ab1f8c62655ebe1350f589c61e505cf94d385bc6a12899442d9081e71fd"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-link"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[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.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[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.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[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.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winsafe"
version = "0.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
[[package]]
name = "wit-bindgen-rt"
version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
dependencies = [
"bitflags 2.8.0",
]
[[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 = "zerocopy"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"byteorder",
"zerocopy-derive 0.7.35",
]
[[package]]
name = "zerocopy"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6"
dependencies = [
"zerocopy-derive 0.8.23",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[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 = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
[[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",
]
07070100000007000081A400000000000000000000000168642C2300000511000000000000000000000000000000000000001800000000kubie-0.26.0/Cargo.toml[package]
authors = ["Simon Bernier St-Pierre <git@sbstp.ca>"]
categories = ["command-line-utilities", "development-tools"]
description = "A more powerful alternative to kubectx and kubens."
documentation = "https://github.com/sbstp/kubie/blob/master/README.md"
edition = "2021"
exclude = ["releases/**/*"]
homepage = "https://github.com/sbstp/kubie"
keywords = ["kubernetes", "kubectx", "kubens"]
license = "Zlib"
name = "kubie"
readme = "README.md"
repository = "https://github.com/sbstp/kubie"
version = "0.26.0"
[dependencies]
anyhow = "1"
clap = { version = "4.5.37", features = ["derive"] }
cfg-if = "1"
dirs = "6"
fs2 = "0.4"
glob = "0.3"
lazy_static = "1"
libc = "0.2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_yaml = "0.9"
signal-hook = "0.3"
tempfile = "3"
which = "7"
wildmatch = "2"
skim = "0.20"
[target.arm-unknown-linux-musleabi.dependencies]
aws-lc-rs = { version = "1.13", default-features = false, features = [
"aws-lc-sys",
"prebuilt-nasm",
"bindgen",
] }
[dependencies.attohttpc]
default-features = false
features = ["compress", "json", "tls-rustls-native-roots"]
version = "0.29.2"
optional = true
[features]
update = ["attohttpc"]
default = ["update"]
[profile.release]
codegen-units = 1
lto = true
opt-level = "s"
strip = true
07070100000008000081A400000000000000000000000168642C230000035E000000000000000000000000000000000000001500000000kubie-0.26.0/LICENSECopyright (c) 2020 Simon Bernier St-Pierre
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
07070100000009000081A400000000000000000000000168642C2300001EA7000000000000000000000000000000000000001700000000kubie-0.26.0/README.md# Kubie
<img src="./assets/logo.svg" align="right"/>
`kubie` is an alternative to `kubectx`, `kubens` and the `k on` prompt modification script. It offers context switching,
namespace switching and prompt modification in a way that makes each shell independent from others. It also has
support for split configuration files, meaning it can load Kubernetes contexts from multiple files. You can configure
the paths where kubie will look for contexts, see the [settings](#settings) section.
Kubie also has other nice features such as `kubie exec` which allows you to execute commands in a context and a
namespace without having to spawn a shell and `kubie lint` which scans your k8s config files for issues and informs
you of what they are.
* [Installation](#installation)
* [Usage](#usage)
* [Settings](#settings)
* [Future plans](#future-plans)
Thanks to [@ahermant](https://github.com/ahermant) for the lovely logo!
## Installation
### Binary
You can download a binary for Linux or OS X on the [GitHub releases page](https://github.com/sbstp/kubie/releases). You
can use `curl` or `wget` to download it. Don't forget to `chmod +x` the file!
### Cargo
You can build `kubie` from source using `cargo` and crates.io. If you do not have a Rust compiler installed, go to
[rustup.rs](https://rustup.rs) to get one. Then you can run `cargo install kubie` and kubie will be downloaded from
crates.io and then built.
### Homebrew
You can install `kubie` from Homebrew by running `brew install kubie`.
### MacPorts
You can also install `kubie` from [MacPorts](https://www.macports.org) by running `sudo port install kubie`.
### Nix
There is a `kubie` Nix package maintained by @illiusdope that you can install.
### Arch Linux
`kubie` is available in the [extra repository](https://archlinux.org/packages/extra/x86_64/kubie/) and it can be installed by running `pacman -S kubie`.
### Autocompletion
#### Bash
If you want autocompletion for `kubie ctx`, `kubie ns` and `kubie exec`, please install this script:
```bash
sudo cp ./completion/kubie.bash /etc/bash_completion.d/kubie
```
Then spawn new shell or source copied file:
```bash
. /etc/bash_completion.d/kubie
```
#### Fish
Install the completions script [kubie.fish](completion/kubie.fish) by copying it, eg.:
```bash
cp completion/kubie.fish ~/.config/fish/completions/
```
Then reopen fish or source the file.
## Usage
Selectable menus will be available when using `kubie ctx` and `kubie ns`.
---
* `kubie ctx` display a selectable menu of contexts
* `kubie ctx <context>` switch the current shell to the given context (spawns a shell if not a kubie shell)
* `kubie ctx -` switch back to the previous context
* `kubie ctx <context> -r` spawn a recursive shell in the given context
* `kubie ctx <context> -n <namespace>` spawn a shell in the given context and namespace
* `kubie ns` display a selectable menu of namespaces
* `kubie ns <namespace>` switch the current shell to the given namespace
* `kubie ns -` switch back to the previous namespace
* `kubie ns <namespace> -r` spawn a recursive shell in the given namespace
* `kubie exec <context> <namespace> <cmd> <args>...` execute a command in the given context and namespace
* `kubie exec <wildcard> <namespace> <cmd> <args>...` execute a command in all the contexts matched by the wildcard and
in the given namespace
* `kubie exec <wildcard> <namespace> -e <cmd> <args>...` execute a command in all the contexts matched by the wildcard and
in the given namespace but fail early if any of the commands executed return a non-zero exit code
* `kubie export <context> <namespace>` prints the path to an isolated config file for a context and namespace
* `kubie edit` display a selectable menu of contexts to edit
* `kubie edit <context>` edit the file that contains this context
* `kubie edit-config` edit kubie's own config file
* `kubie lint` lint k8s config files for issues
* `kubie info ctx` print name of current context
* `kubie info ns` print name of current namespace
* `kubie info depth` print depth of recursive contexts
* `kubie update` will check the latest kubie version and update your local installation if needed
## Settings
You can customize kubie's behavior with the `~/.kube/kubie.yaml` file. The settings available and their defaults are
available below.
```yaml
# Force kubie to use a particular shell, if unset detect shell currently in use.
# Possible values: bash, dash, fish, xonsh, zsh
# Default: unset
shell: bash
# For the commands `kubie edit/edit-config`
# Possible values: Any installed text editor
# Default: unset
default_editor: vim
# Configure where to look for kubernetes config files.
configs:
# Include these globs.
# Default: values listed below.
include:
- ~/.kube/config
- ~/.kube/*.yml
- ~/.kube/*.yaml
- ~/.kube/configs/*.yml
- ~/.kube/configs/*.yaml
- ~/.kube/kubie/*.yml
- ~/.kube/kubie/*.yaml
# Exclude these globs.
# Default: values listed below.
# Note: kubie's own config file is always excluded.
exclude:
- ~/.kube/kubie.yaml
# Prompt settings.
prompt:
# Disable kubie's custom prompt inside of a kubie shell. This is useful
# when you already have a prompt displaying kubernetes information.
# Default: false
disable: false
# When using recursive contexts, show depth when larger than 1.
# Default: true
show_depth: true
# When using zsh, show context and namespace on the right-hand side using RPS1.
# Default: false
zsh_use_rps1: false
# When using fish, show context and namespace on the right-hand side.
# Default: false
fish_use_rprompt: false
# When using xonsh, show context and namespace on the right-hand side.
# Default: false
xonsh_use_right_prompt: false
# Behavior
behavior:
# Namespace validation and switching behavior. Set to "false" if you do not have
# the right to list namespaces.
# Valid values:
# true: Make sure the namespace exists with `kubectl get namespaces`.
# false: Switch namespaces without validation.
# partial: Check for partial matches when running `kubie ns <namespace>`
# and no exact match is found:
# - if exactly one namespace partially matches, switch to that namespace
# - if multiple namespaces partially match, select from those
# Default: true
validate_namespaces: true
# Enable or disable the printing of the 'CONTEXT => ...' headers when running
# `kubie exec`.
# Valid values:
# auto: Prints context headers only if stdout is a TTY. Piping/redirecting
# kubie output will auto-disable context headers.
# always: Always prints context headers, even if stdout is not a TTY.
# never: Never prints context headers.
# Default: auto
print_context_in_exec: auto
# Optional start and stop hooks
hooks:
# A command hook to run when a CTX is started.
# This example re-labels your terminal window
# Default: none
start_ctx: >
echo -en "\033]1; `kubie info ctx`|`kubie info ns` \007"
# A command hook to run when a CTX is stopped
# This example sets the terminal back to the shell name
# Default: none
stop_ctx: >
echo -en "\033]1; $SHELL \007"
```
## For distro maintainers
Since `0.19.0`, the self update functionality is behind a feature. You can use `cargo build --release --no-default-features`
to produce a binary without the self update functionality. It's probably better if people rely on the distro's package
manager for updates over this functionality. The binary produced is also quite smaller since it has fewer dependencies.
## Future plans
* Integration with vault to automatically download k8s configs from a vault server
* Import/edit configs
0707010000000A000041ED00000000000000000000000268642C2300000000000000000000000000000000000000000000001400000000kubie-0.26.0/assets0707010000000B000081A400000000000000000000000168642C230000170E000000000000000000000000000000000000001D00000000kubie-0.26.0/assets/logo.svg<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="224.867px" height="293.305px" viewBox="0 0 216.851 292.237" enable-background="new 0 0 216.851 292.237" xml:space="preserve">
<polygon fill="#FFFFFF" points="36.165,255.828 18.273,273.78 28.915,291.53 69.415,273.78 "/>
<path fill="#E2E2E2" d="M202.316,265.806c-2.75,1.643,1.352,15.305-24.692,14.3c0,0,9.405,2.765,16.854,2.118
C206.001,281.224,204.726,264.367,202.316,265.806z"/>
<polygon fill="#FFFFFF" points="181,245.61 159.735,275.034 186.834,285.11 204.966,269.61 "/>
<path fill="#FFFFFF" d="M5.543,183.106c3.945,57.104,46.364,93.156,103.602,93.156c57.238,0,95.518-35.688,101.129-92.652
c8.226-83.496-8.068-104.009-38.728-135.139c-4.587-4.657-1.097-42.523-6.04-46.191c-5.07-3.763-21.583,26.7-26.919,24.12
c-9.906-4.79-20.172-7.416-30.441-7.416c-10.166,0-20.273,2.794-29.996,7.822c-4.835,2.5-21.041-27.773-25.644-24.238
c-5.611,4.311,0.447,42.664-4.688,48.286C17.943,83.562,0.5,110.11,5.543,183.106z"/>
<path fill="#FBAE5E" d="M139.946,26.734c0,0-5.129,62.843-20.066,75.379c-20.649,17.33-111.434,9.246-111.434,9.246l14.843-34.692
L41,53.61l7.946-49.975l29.934,24.389l29.266-9.041L139.946,26.734z"/>
<path fill="#E89549" d="M93.125,26.027c0,0,0.618,12.75,0,16.583c-0.231,1.432-3.176,3.441-4.625,3.5
c-1.628,0.066-5.244-1.891-5.5-3.5c-0.584-3.666,0-9.812,0-13.083c0,0,1.083-1,4.667-2.25
C91.465,25.952,93.125,26.027,93.125,26.027z"/>
<path fill="#E89549" d="M122.683,26.027c0,0-0.618,12.75,0,16.583c0.23,1.432,3.176,3.441,4.625,3.5
c1.628,0.066,5.243-1.891,5.499-3.5c0.584-3.666,0-9.812,0-13.083c0,0-1.083-1-4.667-2.25
C124.342,25.952,122.683,26.027,122.683,26.027z"/>
<path fill="#E89549" d="M112.75,24.277c0,0-0.133,15.167-0.75,19c-0.231,1.432-2.416,3.585-5.5,3.583
c-1.63-0.001-5.244-1.891-5.5-3.5c-0.584-3.666-0.26-15.812-0.26-19.083c0,0,2.673-0.551,5.96-0.583
C111.417,23.648,112.75,24.277,112.75,24.277z"/>
<path fill="#E2E2E2" d="M146,265.723c-30.475,6.294-60.125,3.137-72.474,3.26c0,0,29.154,6.694,36.619,6.279
C129.132,274.208,153.003,264.277,146,265.723z"/>
<path fill="#E2E2E2" d="M20.003,274.02c1.593,11.693,20.497,10.055,20.497,10.055s-15.404,7.82-20.645,2.487
C16.377,283.022,19.669,271.568,20.003,274.02z"/>
<path fill="none" stroke="#97633D" stroke-width="7" stroke-miterlimit="10" d="M3.5,164.11c0,85.5,47.901,111.694,105.14,111.694
c57.238,0,101.36-35.194,104.334-102.887c2.566-58.399-7.689-90.678-38.35-121.808c-4.587-4.657-4.681-43.62-9.624-47.288
c-5.07-3.763-21.583,26.7-26.919,24.12c-9.906-4.79-20.172-7.416-30.441-7.416c-10.166,0-20.273,2.794-29.996,7.822
C72.81,30.848,56.603,0.575,52,4.11c-5.611,4.311-5.866,43.878-11,49.5C11.125,86.318,3.5,115.741,3.5,164.11z"/>
<polygon fill="#965F3A" points="57.5,20.61 67.5,32.11 57.5,42.61 "/>
<g id="Layer_2">
<polygon fill="#965F3A" points="160.5,42.61 160.5,20.61 150.5,31.61 "/>
</g>
<line fill="none" stroke="#955F3B" stroke-width="3" stroke-miterlimit="10" x1="46.5" y1="110.11" x2="26" y2="101.214"/>
<line fill="none" stroke="#955F3B" stroke-width="3" stroke-miterlimit="10" x1="41" y1="129.056" x2="15.5" y2="127.619"/>
<line fill="none" stroke="#955F3B" stroke-width="3" stroke-miterlimit="10" x1="202.5" y1="128.338" x2="177.5" y2="128.338"/>
<line fill="none" stroke="#955F3B" stroke-width="3" stroke-miterlimit="10" x1="194.861" y1="100.115" x2="172.5" y2="109.36"/>
<line fill="none" stroke="#955F3B" stroke-width="3" stroke-miterlimit="10" x1="199.922" y1="113.985" x2="176.379" y2="118.485"/>
<line fill="none" stroke="#955F3B" stroke-width="3" stroke-miterlimit="10" x1="41" y1="118.485" x2="17.521" y2="113.985"/>
<path fill="#2A8635" d="M74.693,96.376c-4.249,0-7.693-3.444-7.693-7.693c0-1.335,0.371-2.572,0.969-3.667
C61.866,85.295,57,90.317,57,96.489c0,6.352,5.148,11.5,11.5,11.5c6.352,0,11.5-5.148,11.5-11.5c0-0.716-0.074-1.413-0.199-2.092
C78.439,95.614,76.663,96.376,74.693,96.376z"/>
<path fill="none" stroke="#955F3B" stroke-width="6" stroke-miterlimit="10" d="M45.791,145.11c0,0-1.831,33.781,0.709,43.5
c3.25,12.438,8.995,13.253,13.5,12.407c7.5-1.407,10.207-7.201,11.5-10.407c4.314-10.698,2.75-24.465,2.75-36"/>
<path fill="none" stroke="#955F3B" stroke-width="6" stroke-miterlimit="10" d="M174.606,141.098c0,0,0.194,37.852-0.708,42.961
c-1.398,7.912-7.34,12.595-11.92,12.424c-3.455-0.128-7.521-0.43-11.478-6.623c-5.75-9-4.352-27.987-4.352-39.379"/>
<path fill="#955F3B" d="M99.125,98.61c-0.123-5.5,17.375-7.851,19,0c0.639,3.087-6.413,8.704-9.485,7.992
C104.082,105.546,99.195,101.762,99.125,98.61z"/>
<path fill="none" stroke="#955F3B" stroke-miterlimit="10" d="M124.5,113.985c-2.225,3.166-15.25,2.625-15.25,2.625
s-15.2,1.354-16.125-2.625"/>
<line fill="none" stroke="#955F3B" stroke-miterlimit="10" x1="109.125" y1="106.664" x2="109.25" y2="116.61"/>
<path fill="#2A8635" d="M157.693,96.439c-4.249,0-7.693-3.444-7.693-7.693c0-1.335,0.371-2.572,0.969-3.667
C144.866,85.358,140,90.38,140,96.552c0,6.352,5.148,11.5,11.5,11.5c6.352,0,11.5-5.148,11.5-11.5c0-0.716-0.074-1.413-0.199-2.092
C161.439,95.677,159.663,96.439,157.693,96.439z"/>
<path fill="none" stroke="#97633D" stroke-width="7" stroke-miterlimit="10" d="M36.194,252.569c0,0-16.177,14.565-18.673,20.468
c-0.993,2.349-2.521,8.573,2,13.073c3.34,3.324,12.059,2.786,16.729,2.152C44.886,287.09,74.5,271.1,74.5,271.1"/>
<path fill="none" stroke="#97633D" stroke-width="7" stroke-miterlimit="10" d="M184.622,247.265c0,0,11.568,10.651,17.694,18.541
c1.563,2.014,6.03,11.194-2.021,16c-1.585,0.946-10.295,3.183-18.729,1.152c-5.08-1.223-35.25-13.162-35.25-13.162"/>
<polygon fill="#FFFFFF" points="45.153,248.373 27.261,266.325 37.903,284.075 78.403,266.325 "/>
<polygon fill="#FFFFFF" points="170.5,238.11 184.375,251.942 174.624,276.803 133.066,261.11 "/>
</svg>
0707010000000C000041ED00000000000000000000000268642C2300000000000000000000000000000000000000000000001800000000kubie-0.26.0/completion0707010000000D000081A400000000000000000000000168642C23000005CF000000000000000000000000000000000000002300000000kubie-0.26.0/completion/kubie.bash#Kubie completion script
_kubiecomplete()
{
local cur prev
cur=${COMP_WORDS[COMP_CWORD]}
prev=${COMP_WORDS[COMP_CWORD-1]}
{ \unalias command; \unset -f command; } >/dev/null 2>&1 || true
case ${COMP_CWORD} in
1)
cmds="ctx edit edit-config exec help info lint ns"
COMPREPLY=($(command printf "%s\n" $cmds | command grep -e "^$cur" | command xargs))
;;
2)
case ${prev} in
ctx)
COMPREPLY=($(command kubie ctx | command grep -e "^$cur" | command xargs))
;;
edit)
COMPREPLY=($(command kubie ctx | command grep -e "^$cur" | command xargs))
;;
exec)
COMPREPLY=($(command kubie ctx | command grep -e "^$cur" | command xargs))
;;
ns)
COMPREPLY=($(command kubie ns | command grep -e "^$cur" | command xargs))
;;
esac
;;
3)
prevprev=${COMP_WORDS[COMP_CWORD-2]}
case ${prevprev} in
exec)
COMPREPLY=($(command kubie exec ${prev} default kubectl get namespaces|command tail -n+2|command awk '{print $1}'| command grep -e "^$cur" |command xargs))
;;
esac
;;
*)
COMPREPLY=()
;;
esac
}
complete -F _kubiecomplete kubie
0707010000000E000081A400000000000000000000000168642C2300000973000000000000000000000000000000000000002300000000kubie-0.26.0/completion/kubie.fishset -l commands ctx edit edit-config exec help info lint ns update
complete -c kubie --no-files
complete -c kubie \
--condition "not __fish_seen_subcommand_from $commands" \
--arguments "$commands"
set -l cmd __fish_seen_subcommand_from
complete -c kubie -n "not $cmd exec; or not __kubie_got_two_args" -l help -s h
complete -c kubie -n "not $cmd $commands" -l version -s V
complete -c kubie -n "$cmd help" -a "$commands"
# FIXME: This should take --kubeconfig into account
complete -c kubie -n "$cmd ctx delete edit exec; and __kubie_at_arg 1" -d 'context' \
-a '(kubie ctx 2> /dev/null)'
complete -c kubie -n "$cmd ctx ns" -l recursive -s r -d 'spawn a new recursive shell'
complete -c kubie -n "$cmd ctx; and __kubie_at_arg 1" -a '-' -d 'switch back'
complete -c kubie -n "$cmd ctx" -l kubeconfig -s f -r -d 'load contexts from file'
complete -c kubie -n "$cmd ctx" -l namespace -s n -d 'namespace' \
-xa '(kubie exec -e (__kubie_get_first_arg) default -- kubie ns 2>/dev/null)'
complete -c kubie -n "$cmd exec; and __kubie_at_arg 1" -a '"*"' -d 'exec in all contexts'
complete -c kubie -n "$cmd exec; and not __kubie_got_two_args" -l exit-early -e
complete -c kubie -n "$cmd exec; and not __kubie_got_two_args" -l context-headers \
-xa "Auto Always Never" -d 'print context?'
complete -c kubie -n "$cmd exec; and __kubie_at_arg 2" -d 'namespace' \
-a '(kubie exec -e (__kubie_get_first_arg) default -- kubie ns 2>/dev/null)'
complete -c kubie -n "$cmd exec; and __kubie_got_two_args" \
-a '(__fish_complete_subcommand --commandline (__kubie_positionals)[4..-1])'
complete -c kubie -n "$cmd info" -a "ctx depth help ns"
complete -c kubie -n "$cmd ns" -l unset -s u
complete -c kubie -n "$cmd ns" -d 'namespace' -a '(kubie ns 2>/dev/null)'
complete -c kubie -n "$cmd ns" -a '-' -d 'switch back'
# Strip the cmdline from options and flags, used for ctx and exec completions
function __kubie_positionals
set -l cmd (commandline -poc)[2..-1] (commandline -ct)
argparse r/recursive f/kubeconfig= n/namespace= e/exit-early c-context-headers= -- $cmd 2>&1
for x in $argv; echo $x; end
end
function __kubie_get_first_arg
# 2 because first elem is subcmd name
echo (__kubie_positionals)[2]
end
function __kubie_at_arg
test (count (__kubie_positionals)) = (math $argv[1] + 1)
end
function __kubie_got_two_args
test (count (__kubie_positionals)) -ge 4
end
0707010000000F000081A400000000000000000000000168642C2300000010000000000000000000000000000000000000001A00000000kubie-0.26.0/rustfmt.tomlmax_width = 120
07070100000010000041ED00000000000000000000000268642C2300000000000000000000000000000000000000000000001100000000kubie-0.26.0/src07070100000011000041ED00000000000000000000000268642C2300000000000000000000000000000000000000000000001500000000kubie-0.26.0/src/cmd07070100000012000081A400000000000000000000000168642C2300000A28000000000000000000000000000000000000002000000000kubie-0.26.0/src/cmd/context.rsuse anyhow::{Context, Result};
use skim::SkimOptions;
use crate::cmd::{select_or_list_context, SelectResult};
use crate::kubeconfig::{self, Installed};
use crate::kubectl;
use crate::session::Session;
use crate::settings::Settings;
use crate::shell::spawn_shell;
use crate::state::State;
use crate::vars;
fn enter_context(
settings: &Settings,
installed: Installed,
context_name: &str,
namespace_name: Option<&str>,
recursive: bool,
) -> Result<()> {
let state = State::load()?;
let mut session = Session::load()?;
let namespace_name =
namespace_name.or_else(|| state.namespace_history.get(context_name).and_then(|s| s.as_deref()));
let kubeconfig = if context_name == "-" {
let previous_ctx = session
.get_last_context()
.context("There is no previous context to switch to.")?;
installed.make_kubeconfig_for_context(&previous_ctx.context, previous_ctx.namespace.as_deref())?
} else {
installed.make_kubeconfig_for_context(context_name, namespace_name)?
};
session.add_history_entry(
&kubeconfig.contexts[0].name,
kubeconfig.contexts[0].context.namespace.as_deref(),
);
if settings.behavior.validate_namespaces.can_list_namespaces() {
if let Some(namespace_name) = namespace_name {
let namespaces = kubectl::get_namespaces(Some(&kubeconfig))?;
if !namespaces.iter().any(|x| x == namespace_name) {
eprintln!("Warning: namespace {namespace_name} does not exist.");
}
}
}
if vars::is_kubie_active() && !recursive {
let path = kubeconfig::get_kubeconfig_path()?;
kubeconfig.write_to_file(path.as_path())?;
session.save(None)?;
} else {
spawn_shell(settings, kubeconfig, &session)?;
}
Ok(())
}
pub fn context(
settings: &Settings,
skim_options: &SkimOptions,
context_name: Option<String>,
namespace_name: Option<String>,
kubeconfigs: Vec<String>,
recursive: bool,
) -> Result<()> {
let mut installed = if kubeconfigs.is_empty() {
kubeconfig::get_installed_contexts(settings)?
} else {
kubeconfig::get_kubeconfigs_contexts(&kubeconfigs)?
};
let context_name = match context_name {
Some(context_name) => context_name,
None => match select_or_list_context(skim_options, &mut installed)? {
SelectResult::Selected(x) => x,
_ => return Ok(()),
},
};
enter_context(settings, installed, &context_name, namespace_name.as_deref(), recursive)
}
07070100000013000081A400000000000000000000000168642C230000028B000000000000000000000000000000000000001F00000000kubie-0.26.0/src/cmd/delete.rsuse anyhow::Result;
use skim::SkimOptions;
use crate::cmd::{select_or_list_context, SelectResult};
use crate::kubeconfig;
use crate::settings::Settings;
pub fn delete_context(settings: &Settings, skim_options: &SkimOptions, context_name: Option<String>) -> Result<()> {
let mut installed = kubeconfig::get_installed_contexts(settings)?;
let context_name = match context_name {
Some(context_name) => context_name,
None => match select_or_list_context(skim_options, &mut installed)? {
SelectResult::Selected(x) => x,
_ => return Ok(()),
},
};
installed.delete_context(&context_name)
}
07070100000014000081A400000000000000000000000168642C2300000782000000000000000000000000000000000000001D00000000kubie-0.26.0/src/cmd/edit.rsuse std::env;
use std::path::PathBuf;
use std::process::Command;
use anyhow::{anyhow, Result};
use skim::SkimOptions;
use which::which;
use crate::cmd::{select_or_list_context, SelectResult};
use crate::kubeconfig;
use crate::settings::Settings;
fn get_editor(settings: &Settings) -> Result<PathBuf> {
if let Some(default_editor) = &settings.default_editor {
if let Ok(path) = which(default_editor) {
return Ok(path);
}
}
env::var("EDITOR")
.ok()
.and_then(|editor| which(editor).ok())
.or_else(|| {
for editor in &["nvim", "vim", "emacs", "vi", "nano"] {
if let Ok(path) = which(editor) {
return Some(path);
}
}
None
})
.ok_or_else(|| anyhow!("Could not find any editor to use"))
}
pub fn edit_context(settings: &Settings, skim_options: &SkimOptions, context_name: Option<String>) -> Result<()> {
let mut installed = kubeconfig::get_installed_contexts(settings)?;
installed.contexts.sort_by(|a, b| a.item.name.cmp(&b.item.name));
let context_name = match context_name {
Some(context_name) => context_name,
None => match select_or_list_context(skim_options, &mut installed)? {
SelectResult::Selected(x) => x,
_ => return Ok(()),
},
};
let context_src = installed
.find_context_by_name(&context_name)
.ok_or_else(|| anyhow!("Could not find context {}", context_name))?;
let editor = get_editor(settings)?;
let mut job = Command::new(editor).arg(context_src.source.as_ref()).spawn()?;
job.wait()?;
Ok(())
}
pub fn edit_config(settings: &Settings) -> Result<()> {
let editor = get_editor(settings)?;
let settings_path = Settings::path();
let mut job = Command::new(editor).arg(settings_path).spawn()?;
job.wait()?;
Ok(())
}
07070100000015000081A400000000000000000000000168642C2300000A25000000000000000000000000000000000000001D00000000kubie-0.26.0/src/cmd/exec.rsuse std::process::Command;
use std::thread;
use anyhow::{anyhow, Result};
use signal_hook::consts::signal::*;
use signal_hook::iterator::Signals;
use crate::kubeconfig::{self, KubeConfig};
use crate::settings::{ContextHeaderBehavior, Settings};
use crate::vars;
fn run_in_context(kubeconfig: &KubeConfig, args: &[String]) -> anyhow::Result<i32> {
let temp_config_file = tempfile::Builder::new()
.prefix("kubie-config")
.suffix(".yaml")
.tempfile()?;
kubeconfig.write_to_file(temp_config_file.path())?;
let depth = vars::get_depth();
let next_depth = depth + 1;
let mut signals = Signals::new([SIGHUP, SIGTERM, SIGINT, SIGQUIT, SIGWINCH, SIGUSR1, SIGUSR2])
.expect("could not install signal handler");
let mut child = Command::new(&args[0])
.args(&args[1..])
.env("KUBECONFIG", temp_config_file.path())
.env("KUBIE_KUBECONFIG", temp_config_file.path())
.env("KUBIE_ACTIVE", "1")
.env("KUBIE_DEPTH", next_depth.to_string())
.spawn()?;
let child_pid = child.id();
thread::spawn(move || {
for sig in signals.forever() {
unsafe {
libc::kill(child_pid as libc::pid_t, sig as libc::c_int);
}
}
});
let status = child.wait()?;
Ok(status.code().unwrap_or(0))
}
pub fn exec(
settings: &Settings,
context_name: String,
namespace_name: String,
exit_early: bool,
context_headers_flag: Option<ContextHeaderBehavior>,
args: Vec<String>,
) -> Result<()> {
if args.is_empty() {
return Ok(());
}
let installed = kubeconfig::get_installed_contexts(settings)?;
let mut matching = installed.get_contexts_matching(&context_name);
matching.sort_by(|a, b| a.item.name.cmp(&b.item.name));
if matching.is_empty() {
return Err(anyhow!("No context matching {}", context_name));
}
let print_context = context_headers_flag
.as_ref()
.unwrap_or(&settings.behavior.print_context_in_exec)
.should_print_headers();
for context_src in matching {
if print_context {
println!("CONTEXT => {}", context_src.item.name);
}
let kubeconfig = installed.make_kubeconfig_for_context(&context_src.item.name, Some(&namespace_name))?;
let return_code = run_in_context(&kubeconfig, &args)?;
if print_context {
println!("{}", "-".repeat(20));
}
if return_code != 0 && exit_early {
std::process::exit(return_code);
}
}
std::process::exit(0);
}
07070100000016000081A400000000000000000000000168642C2300000386000000000000000000000000000000000000001F00000000kubie-0.26.0/src/cmd/export.rsuse anyhow::{anyhow, Result};
use crate::kubeconfig;
use crate::settings::Settings;
pub fn export(settings: &Settings, context_name: String, namespace_name: String) -> Result<()> {
let installed = kubeconfig::get_installed_contexts(settings)?;
let matching = installed.get_contexts_matching(&context_name);
if matching.is_empty() {
return Err(anyhow!("No context matching {}", context_name));
}
for context_src in matching {
let kubeconfig = installed.make_kubeconfig_for_context(&context_src.item.name, Some(&namespace_name))?;
let temp_config_file = tempfile::Builder::new()
.prefix("kubie-config")
.suffix(".yaml")
.tempfile()?;
kubeconfig.write_to_file(temp_config_file.path())?;
let (_, path) = temp_config_file.keep()?;
println!("{}", path.display());
}
std::process::exit(0);
}
07070100000017000081A400000000000000000000000168642C230000031E000000000000000000000000000000000000001D00000000kubie-0.26.0/src/cmd/info.rsuse anyhow::Result;
use crate::cmd::meta::{KubieInfo, KubieInfoKind};
use crate::kubeconfig;
use crate::vars;
pub fn info(info: KubieInfo) -> Result<()> {
match info.kind {
KubieInfoKind::Context => {
vars::ensure_kubie_active()?;
let conf = kubeconfig::get_current_config()?;
println!("{}", conf.current_context.as_deref().unwrap_or(""));
}
KubieInfoKind::Namespace => {
vars::ensure_kubie_active()?;
let conf = kubeconfig::get_current_config()?;
println!("{}", conf.contexts[0].context.namespace.as_deref().unwrap_or("default"));
}
KubieInfoKind::Depth => {
vars::ensure_kubie_active()?;
println!("{}", vars::get_depth());
}
};
Ok(())
}
07070100000018000081A400000000000000000000000168642C2300000C8F000000000000000000000000000000000000001D00000000kubie-0.26.0/src/cmd/lint.rsuse std::collections::HashSet;
use std::path::Path;
use anyhow::Result;
use crate::kubeconfig::{self, Installed};
use crate::settings::Settings;
fn lint_clusters(installed: &Installed) {
let mut set: HashSet<(&str, &Path)> = HashSet::new();
for cluster_src in &installed.clusters {
let named = &cluster_src.item;
if installed
.find_contexts_by_cluster(&named.name, &cluster_src.source)
.is_empty()
{
println!(
"Cluster '{}' has no context referencing it in file {}",
named.name,
cluster_src.source.display(),
);
}
if set.contains(&(&named.name, &cluster_src.source)) {
println!(
"A cluster named '{}' appears more than once in file {}",
named.name,
cluster_src.source.display(),
);
} else {
set.insert((&named.name, &cluster_src.source));
}
}
}
fn lint_users(installed: &Installed) {
let mut set: HashSet<(&str, &Path)> = HashSet::new();
for user_src in &installed.users {
let named = &user_src.item;
if installed
.find_contexts_by_user(&named.name, &user_src.source)
.is_empty()
{
println!(
"User '{}' has no context referencing it in file {}",
named.name,
user_src.source.display(),
);
}
if set.contains(&(&named.name, &user_src.source)) {
println!(
"A user named '{}' appears more than once in file {}",
named.name,
user_src.source.display(),
);
} else {
set.insert((&named.name, &user_src.source));
}
}
}
fn lint_contexts(installed: &Installed) {
let mut set = HashSet::new();
for context_src in &installed.contexts {
let named = &context_src.item;
if installed
.find_cluster_by_name(&named.context.cluster, &context_src.source)
.is_none()
{
println!(
"Context '{}' references unknown cluster '{}' in file {}",
named.name,
named.context.cluster,
context_src.source.display(),
);
}
if installed
.find_user_by_name(&named.context.user, &context_src.source)
.is_none()
{
println!(
"Context '{}' references unknown users '{}' in file {}",
named.name,
named.context.user,
context_src.source.display(),
);
}
if set.contains(&named.name) {
println!(
"A context name '{}' appears more than once in file {}",
named.name,
context_src.source.display()
);
} else {
set.insert(&named.name);
}
}
}
pub fn lint(settings: &Settings) -> Result<()> {
let installed = kubeconfig::get_installed_contexts(settings)?;
lint_clusters(&installed);
lint_users(&installed);
lint_contexts(&installed);
Ok(())
}
07070100000019000081A400000000000000000000000168642C2300000FB8000000000000000000000000000000000000001D00000000kubie-0.26.0/src/cmd/meta.rsuse clap::Parser;
use crate::settings::ContextHeaderBehavior;
#[derive(Debug, Parser)]
#[clap(version)]
pub enum Kubie {
/// Spawn a shell in the given context. The shell is isolated from other shells.
/// Kubie shells can be spawned recursively without any issue.
#[clap(name = "ctx")]
Context {
/// Specify in which namespace of the context the shell is spawned.
#[clap(short = 'n', long = "namespace")]
namespace_name: Option<String>,
/// Specify files from which to load contexts instead of using the installed ones.
#[clap(short = 'f', long = "kubeconfig")]
kubeconfigs: Vec<String>,
/// Enter the context by spawning a new recursive shell.
#[clap(short = 'r', long = "recursive")]
recursive: bool,
/// Name of the context to enter. Use '-' to switch back to the previous context.
context_name: Option<String>,
},
/// Change the namespace in which the current shell operates. The namespace change does
/// not affect other shells.
#[clap(name = "ns")]
Namespace {
/// Enter the namespace by spawning a new recursive shell.
#[clap(short = 'r', long = "recursive")]
recursive: bool,
/// Unsets the namespace in the currently active context.
#[clap(short = 'u', long = "unset")]
unset: bool,
/// Name of the namespace to enter. Use '-' to switch back to the previous namespace.
namespace_name: Option<String>,
},
/// View info about the current kubie shell, such as the context name and the
/// current namespace.
#[clap(name = "info")]
Info(KubieInfo),
/// Execute a command inside of the given context and namespace.
#[clap(name = "exec", trailing_var_arg = true)]
Exec {
/// Name of the context in which to run the command.
context_name: String,
/// Namespace in which to run the command. This is mandatory to avoid potential errors.
namespace_name: String,
/// Exit early if a command fails when using a wildcard context.
#[clap(short = 'e', long = "exit-early")]
exit_early: bool,
/// Overrides behavior.print_context_in_exec in Kubie settings file.
#[clap(value_enum, long = "context-headers")]
context_headers_flag: Option<ContextHeaderBehavior>,
/// Command to run as well as its arguments.
args: Vec<String>,
},
/// Prints the path to an isolated configuration file for a context and namespace.
#[clap(name = "export")]
Export {
/// Name of the context to export.
context_name: String,
/// Name of the namespace in the context. This is mandatory to avoid potential errors.
namespace_name: String,
},
/// Check the Kubernetes config files for issues.
#[clap(name = "lint")]
Lint,
/// Edit the given context.
#[clap(name = "edit")]
Edit {
/// Name of the context to edit.
context_name: Option<String>,
},
/// Edit kubie's config file.
#[clap(name = "edit-config")]
EditConfig,
/// Check for a Kubie update and replace Kubie's binary if needed.
/// This function can ask for sudo-mode.
#[clap(name = "update")]
#[cfg(feature = "update")]
Update,
/// Delete a context. Automatic garbage collection will be performed.
/// Dangling users and clusters will be removed.
#[clap(name = "delete")]
Delete {
/// Name of the context to edit.
context_name: Option<String>,
},
}
#[derive(Debug, Parser)]
pub struct KubieInfo {
#[clap(subcommand)]
pub kind: KubieInfoKind,
}
/// Type of info the user is requesting.
#[derive(Debug, Parser)]
pub enum KubieInfoKind {
/// Get the current shell's context name.
#[clap(name = "ctx")]
Context,
/// Get the current shell's namespace name.
#[clap(name = "ns")]
Namespace,
/// Get the current depth of contexts.
#[clap(name = "depth")]
Depth,
}
0707010000001A000081A400000000000000000000000168642C2300000B55000000000000000000000000000000000000001C00000000kubie-0.26.0/src/cmd/mod.rsuse std::io::{self, Cursor, IsTerminal};
use anyhow::{bail, Result};
use skim::prelude::{Key, SkimItemReader};
use skim::{Skim, SkimOptions};
use crate::kubeconfig::Installed;
use crate::kubectl;
pub mod context;
pub mod delete;
pub mod edit;
pub mod exec;
pub mod export;
pub mod info;
pub mod lint;
pub mod meta;
pub mod namespace;
#[cfg(feature = "update")]
pub mod update;
pub enum SelectResult {
Cancelled,
Listed,
Selected(String),
}
pub fn select_or_list_context(skim_options: &SkimOptions, installed: &mut Installed) -> Result<SelectResult> {
installed.contexts.sort_by(|a, b| a.item.name.cmp(&b.item.name));
let mut context_names: Vec<_> = installed.contexts.iter().map(|c| c.item.name.clone()).collect();
if context_names.is_empty() {
bail!("No contexts found");
}
if context_names.len() == 1 {
return Ok(SelectResult::Selected(context_names[0].clone()));
}
if io::stdout().is_terminal() {
// NOTE: skim shows the list of context names in reverse order
context_names.reverse();
let item_reader = SkimItemReader::default();
let items = item_reader.of_bufread(Cursor::new(context_names.join("\n")));
let selected_items = Skim::run_with(skim_options, Some(items))
.map(|out| match out.final_key {
Key::Enter => out.selected_items,
_ => Vec::new(),
})
.unwrap_or_default();
if selected_items.is_empty() {
return Ok(SelectResult::Cancelled);
}
Ok(SelectResult::Selected(selected_items[0].output().to_string()))
} else {
for c in context_names {
println!("{c}");
}
Ok(SelectResult::Listed)
}
}
pub fn select_or_list_namespace(skim_options: &SkimOptions, namespaces: Option<Vec<String>>) -> Result<SelectResult> {
let mut namespaces = namespaces.unwrap_or_else(|| kubectl::get_namespaces(None).expect("could not get namespaces"));
namespaces.sort();
if namespaces.is_empty() {
bail!("No namespaces found");
}
if io::stdout().is_terminal() {
// NOTE: skim shows the list of namespaces in reverse order
namespaces.reverse();
let item_reader = SkimItemReader::default();
let items = item_reader.of_bufread(Cursor::new(namespaces.join("\n")));
let selected_items = Skim::run_with(skim_options, Some(items))
.map(|out| match out.final_key {
Key::Enter => out.selected_items,
_ => Vec::new(),
})
.unwrap_or_default();
if selected_items.is_empty() {
return Ok(SelectResult::Cancelled);
}
Ok(SelectResult::Selected(selected_items[0].output().to_string()))
} else {
for n in namespaces {
println!("{n}");
}
Ok(SelectResult::Listed)
}
}
0707010000001B000081A400000000000000000000000168642C2300000E0D000000000000000000000000000000000000002200000000kubie-0.26.0/src/cmd/namespace.rsuse anyhow::{anyhow, Context, Result};
use skim::SkimOptions;
use crate::cmd::{select_or_list_namespace, SelectResult};
use crate::kubeconfig;
use crate::kubectl;
use crate::session::Session;
use crate::settings::{Settings, ValidateNamespacesBehavior};
use crate::shell::spawn_shell;
use crate::state::State;
use crate::vars;
pub fn namespace(
settings: &Settings,
skim_options: &SkimOptions,
namespace_name: Option<String>,
recursive: bool,
unset: bool,
) -> Result<()> {
vars::ensure_kubie_active()?;
let mut session = Session::load().context("Could not load session file")?;
if namespace_name.is_none() && unset {
return enter_namespace(settings, &mut session, recursive, None);
}
let namespace_name = match namespace_name {
Some(s) if s == "-" => Some(
session
.get_last_namespace()
.context("There is not previous namespace to switch to")?
.to_string(),
),
Some(s) => match settings.behavior.validate_namespaces {
ValidateNamespacesBehavior::False => Some(s),
ValidateNamespacesBehavior::True => {
let namespaces = kubectl::get_namespaces(None)?;
if !namespaces.contains(&s) {
return Err(anyhow!("'{}' is not a valid namespace for the context", s));
}
Some(s)
}
ValidateNamespacesBehavior::Partial => {
let namespaces = kubectl::get_namespaces(None)?;
if namespaces.contains(&s) {
Some(s)
} else {
let ns_partial_matches: Vec<String> =
namespaces.iter().filter(|&ns| ns.contains(&s)).cloned().collect();
match ns_partial_matches.len() {
0 => return Err(anyhow!("'{}' is not a valid namespace for the context", s)),
1 => Some(ns_partial_matches[0].clone()),
_ => match select_or_list_namespace(skim_options, Some(ns_partial_matches))? {
SelectResult::Selected(s) => Some(s),
_ => return Ok(()),
},
}
}
}
},
None => match select_or_list_namespace(skim_options, None)? {
SelectResult::Selected(s) => Some(s),
_ => return Ok(()),
},
};
enter_namespace(settings, &mut session, recursive, namespace_name)
}
fn enter_namespace(
settings: &Settings,
session: &mut Session,
recursive: bool,
namespace_name: Option<String>,
) -> Result<()> {
let mut config = kubeconfig::get_current_config()?;
config.contexts[0].context.namespace = namespace_name.clone();
let context_name = &config.contexts[0].name;
// Update the state, set the last namespace used for the context.
// We take out a file lock here to avoid concurrent kubie processes
// corrupting the state file
State::modify(|state| {
state
.namespace_history
.insert(context_name.into(), namespace_name.clone());
Ok(())
})?;
// Update the history, add the context and namespace to it.
session.add_history_entry(context_name, namespace_name);
if recursive {
spawn_shell(settings, config, session)?;
} else {
let config_file = kubeconfig::get_kubeconfig_path()?;
config.write_to_file(config_file.as_path())?;
session.save(None)?;
}
Ok(())
}
0707010000001C000081A400000000000000000000000168642C2300000ECB000000000000000000000000000000000000001F00000000kubie-0.26.0/src/cmd/update.rsuse std::env;
use std::fs;
use std::fs::Permissions;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use anyhow::{Context, Result};
use cfg_if::cfg_if;
use serde::Deserialize;
const VERSION: &str = env!("CARGO_PKG_VERSION");
const LATEST_RELEASE_URL: &str = "https://api.github.com/repos/sbstp/kubie/releases/latest";
#[derive(Debug, Deserialize)]
pub struct Release {
tag_name: String,
assets: Vec<Asset>,
}
impl Release {
pub fn get_latest() -> Result<Release> {
let latest_release = attohttpc::get(LATEST_RELEASE_URL).send()?.json()?;
Ok(latest_release)
}
// Get the right binary name based on which OS and architecture kubie was built-on.
// Names match the GitHub releases: https://github.com/sbstp/kubie/releases
fn get_binary_name() -> Option<&'static str> {
cfg_if! {
if #[cfg(all(target_os = "linux", target_arch = "x86_64"))] {
Some("kubie-linux-amd64")
} else if #[cfg(all(target_os = "linux", target_arch = "arm"))] {
Some("kubie-linux-arm32")
} else if #[cfg(all(target_os = "linux", target_arch = "aarch64"))] {
Some("kubie-linux-arm64")
} else if #[cfg(all(target_os = "macos", target_arch = "x86_64"))] {
Some("kubie-darwin-amd64")
} else if #[cfg(all(target_os = "macos", target_arch = "aarch64"))] {
Some("kubie-darwin-arm64")
} else {
None
}
}
}
pub fn get_binary_url(&self) -> Option<&str> {
let binary_name = Self::get_binary_name()?;
for asset in self.assets.iter() {
if asset.browser_download_url.contains(binary_name) {
return Some(&asset.browser_download_url);
}
}
None
}
}
#[derive(Debug, Deserialize)]
struct Asset {
browser_download_url: String,
}
pub fn update() -> Result<()> {
let latest_release = Release::get_latest()?;
if latest_release.tag_name == format!("v{VERSION}") {
println!("Kubie is up-to-date : v{VERSION}");
} else {
println!(
"A new version of Kubie is available ({}), the new version will be installed by replacing this binary.",
latest_release.tag_name
);
let download_url = latest_release.get_binary_url().context("Sorry, this release has no build for your OS, please create an issue : https://github.com/sbstp/kubie/issues")?;
println!("Download url is: {download_url}");
let resp = attohttpc::get(download_url).send()?;
if resp.is_success() {
let temp_file = tempfile::Builder::new().prefix("kubie").tempfile()?;
resp.write_to(&temp_file)?;
let old_file = env::current_exe().expect("Could not get own binary path");
replace_file(&old_file, temp_file.path()).context("Update failed. Consider using sudo?")?;
println!("Kubie has been updated successfully: {}", Path::display(&old_file));
}
}
Ok(())
}
pub fn replace_file(old_file: &Path, new_file: &Path) -> std::io::Result<()> {
fs::set_permissions(new_file, Permissions::from_mode(0o755))?;
fs::remove_file(old_file)?;
fs::copy(new_file, old_file)?;
Ok(())
}
#[test]
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
fn test_binary_name() {
assert_eq!(Release::get_binary_name(), Some("kubie-linux-amd64"))
}
#[test]
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
fn test_binary_name() {
assert_eq!(Release::get_binary_name(), Some("kubie-darwin-amd64"))
}
#[test]
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
fn test_binary_name() {
assert_eq!(Release::get_binary_name(), Some("kubie-darwin-arm64"))
}
0707010000001D000081A400000000000000000000000168642C2300000990000000000000000000000000000000000000001B00000000kubie-0.26.0/src/ioutil.rsuse std::io::{BufReader, BufWriter};
use std::path::Path;
use std::{
fs::{DirBuilder, File, OpenOptions},
panic::{self, UnwindSafe},
};
use anyhow::{Context, Result};
use fs2::FileExt;
use serde::{de::DeserializeOwned, Serialize};
pub fn read_json<P, T>(path: P) -> Result<T>
where
P: AsRef<Path>,
T: DeserializeOwned,
{
let file = File::open(path.as_ref())?;
let reader = BufReader::new(file);
let obj = serde_json::from_reader(reader)?;
Ok(obj)
}
pub fn write_json<P, T>(path: P, obj: &T) -> Result<()>
where
P: AsRef<Path>,
T: Serialize,
{
let path = path.as_ref();
DirBuilder::new()
.recursive(true)
.create(path.parent().expect("path has no parent"))?;
let file = File::create(path)?;
let writer = BufWriter::new(file);
serde_json::to_writer(writer, obj)?;
Ok(())
}
pub fn read_yaml<P, T>(path: P) -> Result<T>
where
P: AsRef<Path>,
T: DeserializeOwned,
{
let file = File::open(path.as_ref())?;
let reader = BufReader::new(file);
let obj = serde_yaml::from_reader(reader)?;
Ok(obj)
}
pub fn write_yaml<P, T>(path: P, obj: &T) -> Result<()>
where
P: AsRef<Path>,
T: Serialize,
{
let path = path.as_ref();
DirBuilder::new()
.recursive(true)
.create(path.parent().expect("path has no parent"))?;
let file = File::create(path)?;
let writer = BufWriter::new(file);
serde_yaml::to_writer(writer, obj)?;
Ok(())
}
pub fn file_lock<P, F, T>(path: P, scope: F) -> Result<T, anyhow::Error>
where
P: AsRef<Path>,
F: FnOnce() -> Result<T, anyhow::Error> + UnwindSafe,
{
let path = path.as_ref();
let file = OpenOptions::new()
.append(true)
.truncate(false)
.read(true)
.create(true)
.open(path)
.with_context(|| format!("Could not open lock file at {}", path.display()))?;
file.lock_exclusive()
.with_context(|| format!("Could not lock file at {}", path.display()))?;
// Run the given closure, but catch any panics so we can unlock before resuming the panic.
let exception = panic::catch_unwind(scope);
// Ignore errors during unlock. If we had a panic, we don't want to return the potential error.
// If we did not panic, we want to return the closure's result.
let _ = FileExt::unlock(&file);
match exception {
Ok(result) => result,
Err(x) => panic::resume_unwind(x),
}
}
0707010000001E000081A400000000000000000000000168642C23000026B1000000000000000000000000000000000000001F00000000kubie-0.26.0/src/kubeconfig.rsuse std::collections::HashMap;
use std::env;
use std::fs::{self, File, Permissions};
use std::io::BufWriter;
use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf};
use std::rc::Rc;
use anyhow::{anyhow, bail, Context as _, Result};
use serde::{Deserialize, Serialize};
use serde_yaml::{Mapping, Value};
use wildmatch::WildMatch;
use crate::ioutil;
use crate::settings::Settings;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct KubeConfig {
pub clusters: Vec<NamedCluster>,
pub users: Vec<NamedUser>,
pub contexts: Vec<NamedContext>,
#[serde(rename = "current-context")]
pub current_context: Option<String>,
#[serde(flatten)]
pub others: HashMap<String, Value>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct NamedCluster {
pub name: String,
pub cluster: Mapping,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct NamedUser {
pub name: String,
pub user: Mapping,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct NamedContext {
pub name: String,
pub context: Context,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Context {
pub cluster: String,
pub namespace: Option<String>,
pub user: String,
}
#[derive(Clone, Debug)]
pub struct Sourced<T> {
pub source: Rc<PathBuf>,
pub item: T,
}
impl<T> Sourced<T> {
pub fn new(source: &Rc<PathBuf>, item: T) -> Self {
Sourced {
source: source.clone(),
item,
}
}
}
#[derive(Debug)]
pub struct Installed {
pub clusters: Vec<Sourced<NamedCluster>>,
pub users: Vec<Sourced<NamedUser>>,
pub contexts: Vec<Sourced<NamedContext>>,
}
impl KubeConfig {
pub fn write_to_file(&self, path: &Path) -> anyhow::Result<()> {
let file = File::create(path).context("could not write file")?;
fs::set_permissions(path, Permissions::from_mode(0o600))?;
let buffer = BufWriter::new(file);
serde_yaml::to_writer(buffer, self)?;
Ok(())
}
}
impl Installed {
pub fn find_context_by_name(&self, name: &str) -> Option<&Sourced<NamedContext>> {
self.contexts.iter().find(|s| s.item.name == name)
}
pub fn find_cluster_by_name(&self, name: &str, source: &Path) -> Option<&Sourced<NamedCluster>> {
self.clusters
.iter()
.find(|s| s.item.name == name && *s.source == source)
.or_else(|| self.clusters.iter().find(|s| s.item.name == name))
}
pub fn find_user_by_name(&self, name: &str, source: &Path) -> Option<&Sourced<NamedUser>> {
self.users
.iter()
.find(|s| s.item.name == name && *s.source == source)
.or_else(|| self.users.iter().find(|s| s.item.name == name))
}
pub fn find_contexts_by_cluster(&self, name: &str, source: &Path) -> Vec<&Sourced<NamedContext>> {
self.contexts
.iter()
.filter(|s| s.item.context.cluster == name && *s.source == source)
.collect()
}
pub fn find_contexts_by_user(&self, name: &str, source: &Path) -> Vec<&Sourced<NamedContext>> {
self.contexts
.iter()
.filter(|s| s.item.context.user == name && *s.source == source)
.collect()
}
pub fn get_contexts_matching(&self, pattern: &str) -> Vec<&Sourced<NamedContext>> {
let matcher = WildMatch::new(pattern);
self.contexts.iter().filter(|s| matcher.matches(&s.item.name)).collect()
}
pub fn delete_context(&mut self, name: &str) -> Result<()> {
let context = self
.find_context_by_name(name)
.ok_or_else(|| anyhow!("Context not found"))?;
let mut kubeconfig: KubeConfig = ioutil::read_yaml(context.source.as_ref())?;
// Retain all contexts whose name is not our context.
kubeconfig.contexts.retain(|x| x.name != context.item.name);
// Retain all clusters whose name is not our context's cluster reference.
kubeconfig.clusters.retain(|x| x.name != context.item.context.cluster);
// Retain all users whose name is not our context's user reference.
kubeconfig.users.retain(|x| x.name != context.item.context.user);
if kubeconfig.contexts.is_empty() && kubeconfig.clusters.is_empty() && kubeconfig.users.is_empty() {
// If the kubeconfig is empty after removing the context and dangling references,
// we simply remove the file.
println!(
"Deleting kubeconfig {} because is it now empty.",
context.source.display()
);
fs::remove_file(context.source.as_ref()).context("Could not delete empty kubeconfig file")?;
} else {
// If the kubeconfig is not empty, we rewrite it with the context and dangling references removed.
println!("Updating kubeconfig {}.", context.source.display());
ioutil::write_yaml(context.source.as_ref(), &kubeconfig)
.context("Could not open kubeconfig file to rewrite it.")?;
}
Ok(())
}
fn make_path_absolute(mapping: &mut Mapping, key: &str, parent: &Path) {
if !mapping.contains_key(key) {
return;
}
let str = mapping.get(key).unwrap().as_str().expect("value should be a string");
let path = Path::new(str);
if !path.is_absolute() {
mapping.insert(key.into(), parent.join(path).to_str().expect("path should be a valid unicode string").into());
}
}
pub fn make_kubeconfig_for_context(
&self,
context_name: &str,
namespace_name: Option<impl Into<String>>,
) -> Result<KubeConfig> {
let mut context_src = self
.contexts
.iter()
.find(|c| c.item.name == context_name)
.cloned()
.ok_or_else(|| anyhow!("Could not find context {}", context_name))?;
context_src.item.context.namespace = namespace_name.map(Into::into);
let kubeconfig_dir = context_src.source.parent().expect("kubeconfig path should have a parent dir");
let cluster_src = self
.find_cluster_by_name(&context_src.item.context.cluster, &context_src.source)
.cloned()
.ok_or_else(|| {
anyhow!(
"Could not find cluster {} referenced by context {}",
context_src.item.context.cluster,
context_name,
)
})?;
let mut named_cluster = cluster_src.item;
let cluster = &mut named_cluster.cluster;
Self::make_path_absolute(cluster, "certificate-authority", kubeconfig_dir);
let user_src = self
.find_user_by_name(&context_src.item.context.user, &context_src.source)
.cloned()
.ok_or_else(|| {
anyhow!(
"Could not find user {} referenced by context {}",
context_src.item.context.user,
context_name,
)
})?;
let mut named_user = user_src.item;
let user = &mut named_user.user;
Self::make_path_absolute(user, "client-certificate", kubeconfig_dir);
Self::make_path_absolute(user, "client-key", kubeconfig_dir);
Ok(KubeConfig {
clusters: vec![named_cluster],
contexts: vec![context_src.item],
users: vec![named_user],
current_context: Some(context_name.into()),
others: {
let mut m: HashMap<String, Value> = HashMap::new();
m.insert("apiVersion".into(), Value::String("v1".into()));
m.insert("kind".into(), Value::String("Config".into()));
m
},
})
}
}
fn load_kubeconfigs<I, P>(kubeconfigs: I) -> Result<Installed>
where
I: IntoIterator<Item = P>,
P: AsRef<Path>,
{
let mut installed = Installed {
clusters: vec![],
contexts: vec![],
users: vec![],
};
for path in kubeconfigs.into_iter() {
let path = path.as_ref();
// Avoid parsing things that aren't files or don't link to a file.
if !path.is_file() {
continue;
}
let kubeconfig: Result<KubeConfig> = ioutil::read_yaml(path);
match kubeconfig {
Ok(mut kubeconfig) => {
let path = Rc::new(path.to_owned());
installed
.clusters
.extend(kubeconfig.clusters.drain(..).map(|x| Sourced::new(&path, x)));
installed
.contexts
.extend(kubeconfig.contexts.drain(..).map(|x| Sourced::new(&path, x)));
installed
.users
.extend(kubeconfig.users.drain(..).map(|x| Sourced::new(&path, x)));
}
Err(err) => {
eprintln!("Error loading kubeconfig {}: {}", path.display(), err);
}
}
}
Ok(installed)
}
pub fn get_installed_contexts(settings: &Settings) -> Result<Installed> {
let installed = load_kubeconfigs(settings.get_kube_configs_paths()?)?;
if installed.contexts.is_empty() {
bail!("Could not find any contexts in the Kubie kubeconfig directories!");
}
Ok(installed)
}
pub fn get_kubeconfigs_contexts(kubeconfigs: &Vec<String>) -> Result<Installed> {
let installed = load_kubeconfigs(kubeconfigs)?;
if installed.contexts.is_empty() {
bail!("Could not find any contexts in the given set of files!");
}
Ok(installed)
}
pub fn get_kubeconfig_path() -> Result<PathBuf> {
let path = env::var_os("KUBIE_KUBECONFIG").context("KUBIE_CONFIG not found")?;
Ok(PathBuf::from(path))
}
pub fn get_current_config() -> Result<KubeConfig> {
ioutil::read_yaml(get_kubeconfig_path()?)
}
0707010000001F000081A400000000000000000000000168642C230000052D000000000000000000000000000000000000001C00000000kubie-0.26.0/src/kubectl.rsuse std::env;
use std::process::Command;
use std::str;
use anyhow::{anyhow, Context};
use crate::kubeconfig::KubeConfig;
pub fn get_namespaces<'a>(kubeconfig: impl Into<Option<&'a KubeConfig>>) -> anyhow::Result<Vec<String>> {
let mut cmd = Command::new("kubectl");
cmd.arg("get");
cmd.arg("namespaces");
let temp_config_file;
if let Some(kubeconfig) = kubeconfig.into() {
temp_config_file = tempfile::Builder::new()
.prefix("kubie-config")
.suffix(".yaml")
.tempfile()?;
kubeconfig.write_to_file(temp_config_file.path())?;
cmd.env("KUBECONFIG", temp_config_file.path());
} else {
cmd.env(
"KUBECONFIG",
env::var("KUBIE_KUBECONFIG").context("KUBIE_KUBECONFIG variable is not set")?,
);
}
let result = cmd.output()?;
if !result.status.success() {
let stderr = str::from_utf8(&result.stderr).unwrap_or("could not decode stderr of kubectl as utf-8");
return Err(anyhow!("Error calling kubectl: {}", stderr));
}
let text = str::from_utf8(&result.stdout)?;
let mut namespaces = vec![];
for line in text.lines().skip(1) {
let idx = line.find(' ').unwrap_or(line.len());
namespaces.push(line[..idx].to_string());
}
Ok(namespaces)
}
07070100000020000081A400000000000000000000000168642C2300000B10000000000000000000000000000000000000001900000000kubie-0.26.0/src/main.rsuse anyhow::Result;
use clap::Parser;
use cmd::meta::Kubie;
use settings::Settings;
use skim::prelude::SkimOptionsBuilder;
mod cmd;
mod ioutil;
mod kubeconfig;
mod kubectl;
mod session;
mod settings;
mod shell;
mod state;
mod vars;
fn main() -> Result<()> {
let mut settings = Settings::load()?;
let skim_options = {
let mut options = SkimOptionsBuilder::default();
options.no_multi(true);
options.color(settings.fzf.color.take());
if settings.fzf.ignore_case {
options.case(skim::CaseMatching::Ignore);
};
if !settings.fzf.mouse {
options.no_mouse(true);
};
if settings.fzf.reverse {
options.reverse(true);
}
if settings.fzf.info_hidden {
options.no_info(true);
}
if let Some(prompt) = settings.fzf.prompt.take() {
options.prompt(prompt);
}
options.build().unwrap()
};
let kubie = Kubie::parse();
match kubie {
Kubie::Context {
namespace_name,
context_name,
kubeconfigs,
recursive,
} => {
cmd::context::context(
&settings,
&skim_options,
context_name,
namespace_name,
kubeconfigs,
recursive,
)?;
}
Kubie::Namespace {
namespace_name,
recursive,
unset,
} => {
cmd::namespace::namespace(&settings, &skim_options, namespace_name, recursive, unset)?;
}
Kubie::Info(info) => {
cmd::info::info(info)?;
}
Kubie::Exec {
context_name,
namespace_name,
exit_early,
context_headers_flag,
args,
} => {
cmd::exec::exec(
&settings,
context_name,
namespace_name,
exit_early,
context_headers_flag,
args,
)?;
}
Kubie::Lint => {
cmd::lint::lint(&settings)?;
}
Kubie::Edit { context_name } => {
cmd::edit::edit_context(&settings, &skim_options, context_name)?;
}
Kubie::EditConfig => {
cmd::edit::edit_config(&settings)?;
}
#[cfg(feature = "update")]
Kubie::Update => {
cmd::update::update()?;
}
Kubie::Delete { context_name } => {
cmd::delete::delete_context(&settings, &skim_options, context_name)?;
}
Kubie::Export {
context_name,
namespace_name,
} => {
cmd::export::export(&settings, context_name, namespace_name)?;
}
}
Ok(())
}
07070100000021000081A400000000000000000000000168642C2300000871000000000000000000000000000000000000001C00000000kubie-0.26.0/src/session.rsuse std::path::Path;
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use crate::ioutil;
use crate::vars;
/// Session contains information which is scoped to a kubie shell.
///
/// Currently it stores the history of contexts and namespaces entered to allow
/// users to switch back to the previous context with `-`.
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct Session {
history: Vec<HistoryEntry>,
}
impl Session {
pub fn load() -> Result<Session> {
let session_path = match vars::get_session_path() {
None => return Ok(Default::default()),
Some(x) => x,
};
if !session_path.exists() {
return Ok(Default::default());
}
ioutil::read_json(session_path)
}
pub fn save(&self, path: Option<&Path>) -> Result<()> {
let session_path = match path {
Some(p) => p.to_path_buf(),
None => vars::get_session_path().context("KUBIE_SESSION env variable missing")?,
};
ioutil::write_json(session_path, self)
}
pub fn add_history_entry(&mut self, context: impl Into<String>, namespace: Option<impl Into<String>>) {
self.history.push(HistoryEntry {
context: context.into(),
namespace: namespace.map(Into::into),
})
}
pub fn get_last_context(&self) -> Option<&HistoryEntry> {
let current_context = self.history.last()?;
self.history
.iter()
.rev()
.skip(1)
.find(|&entry| current_context.context != entry.context)
}
pub fn get_last_namespace(&self) -> Option<&str> {
let current_context = self.history.last()?;
for entry in self.history.iter().rev().skip(1) {
if current_context.context != entry.context {
return None;
}
if current_context.namespace != entry.namespace {
return entry.namespace.as_deref();
}
}
None
}
}
#[derive(Debug, Deserialize, Serialize)]
pub struct HistoryEntry {
pub context: String,
pub namespace: Option<String>,
}
07070100000022000081A400000000000000000000000168642C2300001638000000000000000000000000000000000000001D00000000kubie-0.26.0/src/settings.rsuse std::collections::HashSet;
use std::fs::File;
use std::io::{self, BufReader, IsTerminal};
use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
use glob::glob;
use lazy_static::lazy_static;
use serde::Deserialize;
lazy_static! {
static ref HOME_DIR: String = dirs::home_dir()
.expect("could not get home directory path")
.to_str()
.expect("home directory contains non unicode characters")
.to_string();
}
#[inline]
fn home_dir() -> &'static str {
&HOME_DIR
}
pub fn expanduser(path: &str) -> String {
if let Some(stripped) = path.strip_prefix("~/") {
format!("{}/{}", home_dir(), stripped)
} else {
path.to_string()
}
}
#[derive(Default, Debug, Deserialize)]
pub struct Fzf {
pub mouse: bool,
pub reverse: bool,
pub ignore_case: bool,
pub info_hidden: bool,
pub prompt: Option<String>,
pub color: Option<String>,
}
#[derive(Debug, Default, Deserialize)]
pub struct Settings {
#[serde(default)]
pub shell: Option<String>,
#[serde(default)]
pub default_editor: Option<String>,
#[serde(default)]
pub configs: Configs,
#[serde(default)]
pub prompt: Prompt,
#[serde(default)]
pub behavior: Behavior,
#[serde(default)]
pub hooks: Hooks,
#[serde(default)]
pub fzf: Fzf,
}
impl Settings {
pub fn path() -> String {
format!("{}/.kube/kubie.yaml", home_dir())
}
pub fn load() -> Result<Settings> {
let settings_path_str = Self::path();
let settings_path = Path::new(&settings_path_str);
let mut settings = if settings_path.exists() {
let file = File::open(settings_path)?;
let reader = BufReader::new(file);
serde_yaml::from_reader(reader).context("could not parse kubie config")?
} else {
Settings::default()
};
// Very important to exclude kubie's own config file ~/.kube/kubie.yaml from the results.
settings.configs.exclude.push(settings_path_str);
Ok(settings)
}
pub fn get_kube_configs_paths(&self) -> Result<HashSet<PathBuf>> {
let mut paths = HashSet::new();
for inc in &self.configs.include {
let expanded = expanduser(inc);
for entry in glob(&expanded)? {
paths.insert(entry?);
}
}
for exc in &self.configs.exclude {
let expanded = expanduser(exc);
for entry in glob(&expanded)? {
paths.remove(&entry?);
}
}
Ok(paths)
}
}
#[derive(Debug, Deserialize)]
pub struct Configs {
#[serde(default = "default_include_path")]
pub include: Vec<String>,
#[serde(default = "default_exclude_path")]
pub exclude: Vec<String>,
}
impl Default for Configs {
fn default() -> Self {
Configs {
include: default_include_path(),
exclude: default_exclude_path(),
}
}
}
fn default_include_path() -> Vec<String> {
let home_dir = home_dir();
vec![
format!("{home_dir}/.kube/config"),
format!("{home_dir}/.kube/*.yml"),
format!("{home_dir}/.kube/*.yaml"),
format!("{home_dir}/.kube/configs/*.yml"),
format!("{home_dir}/.kube/configs/*.yaml"),
format!("{home_dir}/.kube/kubie/*.yml"),
format!("{home_dir}/.kube/kubie/*.yaml"),
]
}
fn default_exclude_path() -> Vec<String> {
vec![]
}
#[derive(Debug, Deserialize)]
pub struct Prompt {
#[serde(default = "def_bool_false")]
pub disable: bool,
#[serde(default = "def_bool_true")]
pub show_depth: bool,
#[serde(default = "def_bool_false")]
pub zsh_use_rps1: bool,
#[serde(default = "def_bool_false")]
pub fish_use_rprompt: bool,
#[serde(default = "def_bool_false")]
pub xonsh_use_right_prompt: bool,
}
impl Default for Prompt {
fn default() -> Self {
Prompt {
disable: false,
show_depth: true,
zsh_use_rps1: false,
fish_use_rprompt: false,
xonsh_use_right_prompt: false,
}
}
}
#[derive(Debug, Clone, clap::ValueEnum, Deserialize)]
#[clap(rename_all = "lower")]
#[serde(rename_all = "lowercase")]
#[derive(Default)]
pub enum ContextHeaderBehavior {
#[default]
Auto,
Always,
Never,
}
impl ContextHeaderBehavior {
pub fn should_print_headers(&self) -> bool {
match self {
ContextHeaderBehavior::Auto => io::stdout().is_terminal(),
ContextHeaderBehavior::Always => true,
ContextHeaderBehavior::Never => false,
}
}
}
#[derive(Debug, Deserialize, Default)]
pub struct Behavior {
#[serde(default)]
pub validate_namespaces: ValidateNamespacesBehavior,
#[serde(default)]
pub print_context_in_exec: ContextHeaderBehavior,
}
#[derive(Debug, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum ValidateNamespacesBehavior {
#[default]
True,
False,
Partial,
}
impl ValidateNamespacesBehavior {
pub fn can_list_namespaces(&self) -> bool {
match self {
ValidateNamespacesBehavior::True | ValidateNamespacesBehavior::Partial => true,
ValidateNamespacesBehavior::False => false,
}
}
}
#[derive(Debug, Deserialize, Default)]
pub struct Hooks {
#[serde(default)]
pub start_ctx: String,
#[serde(default)]
pub stop_ctx: String,
}
fn def_bool_true() -> bool {
true
}
fn def_bool_false() -> bool {
false
}
#[test]
fn test_expanduser() {
assert_eq!(
expanduser("~/hello/world/*.foo"),
format!("{}/hello/world/*.foo", home_dir())
);
}
07070100000023000041ED00000000000000000000000268642C2300000000000000000000000000000000000000000000001700000000kubie-0.26.0/src/shell07070100000024000081A400000000000000000000000168642C23000009D3000000000000000000000000000000000000001F00000000kubie-0.26.0/src/shell/bash.rsuse std::io::{BufWriter, Write};
use std::process::Command;
use anyhow::Result;
use super::ShellSpawnInfo;
pub fn spawn_shell(info: &ShellSpawnInfo) -> Result<()> {
let temp_rc_file = tempfile::Builder::new()
.prefix("kubie-bashrc")
.suffix(".bash")
.tempfile()?;
let mut temp_rc_file_buf = BufWriter::new(temp_rc_file.as_file());
write!(
temp_rc_file_buf,
r#"
KUBIE_LOGIN_SHELL=0
if [[ "$OSTYPE" == "darwin"* ]] ; then
KUBIE_LOGIN_SHELL=1
fi
# Reference for loading behavior
# https://shreevatsa.wordpress.com/2008/03/30/zshbash-startup-files-loading-order-bashrc-zshrc-etc/
if [[ "$KUBIE_LOGIN_SHELL" == "1" ]] ; then
if [[ -f "/etc/profile" ]] ; then
source "/etc/profile"
fi
if [[ -f "$HOME/.bash_profile" ]] ; then
source "$HOME/.bash_profile"
elif [[ -f "$HOME/.bash_login" ]] ; then
source "$HOME/.bash_login"
elif [[ -f "$HOME/.profile" ]] ; then
source "$HOME/.profile"
fi
else
if [[ -f "/etc/bash.bashrc" ]] ; then
source "/etc/bash.bashrc"
fi
if [[ -f "$HOME/.bashrc" ]] ; then
source "$HOME/.bashrc"
fi
fi
function __kubie_cmd_pre_exec__() {{
export KUBECONFIG="$KUBIE_KUBECONFIG"
}}
trap '__kubie_cmd_pre_exec__' DEBUG
"#
)?;
if !info.settings.prompt.disable {
write!(
temp_rc_file_buf,
r#"
KUBIE_PROMPT='{}'
PS1="$KUBIE_PROMPT $PS1"
unset KUBIE_PROMPT
"#,
info.prompt,
)?;
}
if !info.settings.hooks.start_ctx.is_empty() {
write!(temp_rc_file_buf, "{}", info.settings.hooks.start_ctx)?;
}
temp_rc_file_buf.flush()?;
let mut cmd = Command::new("bash");
cmd.arg("--rcfile");
cmd.arg(temp_rc_file.path());
info.env_vars.apply(&mut cmd);
let mut child = cmd.spawn()?;
child.wait()?;
if !info.settings.hooks.start_ctx.is_empty() {
let temp_exit_hook_file = tempfile::Builder::new()
.prefix("kubie-bash-exit-hook")
.suffix(".bash")
.tempfile()?;
let mut temp_exit_hook_file_buf = BufWriter::new(temp_exit_hook_file.as_file());
write!(temp_exit_hook_file_buf, "{}", info.settings.hooks.stop_ctx)?;
temp_exit_hook_file_buf.flush()?;
let mut exit_cmd = Command::new("bash");
exit_cmd.arg(temp_exit_hook_file.path());
info.env_vars.apply(&mut exit_cmd);
let mut child = exit_cmd.spawn()?;
child.wait()?;
}
Ok(())
}
07070100000025000081A400000000000000000000000168642C2300000DE7000000000000000000000000000000000000002100000000kubie-0.26.0/src/shell/detect.rsuse std::process::Command;
use std::str;
use anyhow::{anyhow, Context, Result};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum ShellKind {
Bash,
Fish,
Xonsh,
Zsh,
Nu,
}
impl ShellKind {
pub fn from_str(name: &str) -> Option<ShellKind> {
Some(match name {
"bash" | "dash" => ShellKind::Bash,
"fish" => ShellKind::Fish,
"xonsh" | "python" => ShellKind::Xonsh,
"zsh" => ShellKind::Zsh,
"nu" => ShellKind::Nu,
_ => return None,
})
}
}
fn run_ps(args: &[&str]) -> Result<Vec<String>> {
let result = Command::new("ps").args(args).output().context("Could not spawn ps")?;
if !result.status.success() {
let stderr = str::from_utf8(&result.stderr).unwrap_or("Could not decode stderr of ps as utf-8");
return Err(anyhow!("Error calling ps: {}", stderr));
}
let text = str::from_utf8(&result.stdout)?;
Ok(text.split('\n').filter(|x| !x.is_empty()).map(String::from).collect())
}
fn parent_of(pid: &str) -> Result<String> {
let lines = run_ps(&["-o", "ppid=", pid])?;
lines
.into_iter()
.next()
.map(|x| x.trim().to_string())
.ok_or_else(|| anyhow!("Could not get parent pid of pid={}", pid))
}
fn command_of(pid: &str) -> Result<String> {
let lines = run_ps(&["-o", "args=", pid])?;
lines
.into_iter()
.next()
.ok_or_else(|| anyhow!("Could not get command of pid={}", pid))
}
fn parse_command(cmd: &str) -> &str {
let first_space = cmd.find(' ').unwrap_or(cmd.len());
let binary_path = &cmd[..first_space];
let last_path_sep = binary_path.rfind('/').map(|x| x + 1).unwrap_or(0);
let binary = &binary_path[last_path_sep..];
binary
.trim_start_matches('-')
.trim_end_matches(|c: char| c.is_ascii_digit() || c == '.')
}
/// Detect from which kind of shell kubie was spawned.
///
/// This function walks up the process tree and finds all the ancestors to kubie.
/// If any of kubie's ancestor is a known shell, we have found which shell is in
/// use.
///
/// This functions depends on the `ps` command being installed and available in
/// the PATH variable.
///
/// The SHELL environment variable corresponds to the user's configured SHELL, not
/// the shell currently in use.
pub fn detect() -> Result<ShellKind> {
let kubie_pid = format!("{}", std::process::id());
let mut parent_pid = parent_of(&kubie_pid)?;
loop {
if parent_pid == "1" {
return Err(anyhow!("Could not detect shell in use"));
}
let cmd = command_of(&parent_pid)?;
let name = parse_command(&cmd);
if let Some(kind) = ShellKind::from_str(name) {
return Ok(kind);
}
parent_pid = parent_of(&parent_pid)?;
}
}
#[test]
fn test_parse_command_simple() {
assert_eq!(parse_command("bash"), "bash");
}
#[test]
fn test_parse_command_with_args() {
assert_eq!(parse_command("bash --rcfile hello.sh"), "bash");
}
#[test]
fn test_parse_command_with_path() {
assert_eq!(parse_command("/bin/bash"), "bash");
}
#[test]
fn test_parse_command_with_path_and_args() {
assert_eq!(parse_command("/bin/bash --rcfile hello.sh"), "bash");
}
#[test]
fn test_parse_command_login_shell() {
assert_eq!(parse_command("-zsh"), "zsh");
}
#[test]
fn test_parse_command_versioned_intepreter() {
assert_eq!(parse_command("python3.8"), "python");
}
#[test]
fn test_parse_command_nu() {
assert_eq!(parse_command("/bin/nu"), "nu");
}
07070100000026000081A400000000000000000000000168642C23000007F4000000000000000000000000000000000000001F00000000kubie-0.26.0/src/shell/fish.rsuse std::process::Command;
use anyhow::Result;
use super::ShellSpawnInfo;
pub fn spawn_shell(info: &ShellSpawnInfo) -> Result<()> {
let mut cmd = Command::new("fish");
// run fish as an interactive login shell
cmd.arg("-ilC");
cmd.arg(format!(
r#"
# Set the proper KUBECONFIG variable before each command runs,
# to prevent the user from overwriting it.
function kubie_preexec --on-event fish_preexec
set -xg KUBECONFIG "$KUBIE_KUBECONFIG"
end
if test "$KUBIE_PROMPT_DISABLE" = "0"
# The general idea behind the prompt substitions is to save the existing
# prompt's output _before_ anything else is run. This is important since the
# existing prompt might be dependent on say the status of the executed command.
if test "$KUBIE_FISH_USE_RPROMPT" = "1"
functions -q fish_right_prompt
and functions --copy fish_right_prompt fish_right_prompt_original
or function fish_right_prompt_original; end
function fish_right_prompt
set -l original (fish_right_prompt_original)
# Fish's right prompt does not support newlines, so there's no point in
# iterating through the (potentially) existing prompt's lines.
printf '%s %s' (string unescape {prompt}) $original
end
else
functions --copy fish_prompt fish_prompt_original
function fish_prompt
set -l original (fish_prompt_original)
printf '%s ' (string unescape {prompt})
# Due to idiosyncrasies with the way fish is managing newlines in
# process substitions, each line needs to be printed separately
# to mirror the existing output. For more details,
# see https://github.com/fish-shell/fish-shell/issues/159.
for line in $original
echo -e $line
end
end
end
end
"#,
prompt = info.prompt,
));
info.env_vars.apply(&mut cmd);
let mut child = cmd.spawn()?;
child.wait()?;
Ok(())
}
07070100000027000081A400000000000000000000000168642C2300000E43000000000000000000000000000000000000001E00000000kubie-0.26.0/src/shell/mod.rsuse std::collections::HashMap;
use std::ffi::OsString;
use std::process::Command;
use anyhow::{anyhow, Result};
use self::detect::{detect, ShellKind};
use crate::kubeconfig::KubeConfig;
use crate::session::Session;
use crate::settings::Settings;
use crate::state;
use crate::vars;
mod bash;
mod detect;
mod fish;
mod nu;
mod prompt;
mod xonsh;
mod zsh;
pub struct EnvVars<'n> {
vars: HashMap<&'n str, OsString>,
}
impl<'n> EnvVars<'n> {
pub fn new() -> EnvVars<'n> {
EnvVars { vars: HashMap::new() }
}
pub fn insert(&mut self, name: &'n str, value: impl Into<OsString>) {
self.vars.insert(name, value.into());
}
pub fn apply(&self, cmd: &mut Command) {
for (name, value) in &self.vars {
cmd.env(name, value);
}
}
}
pub struct ShellSpawnInfo<'s, 'n> {
settings: &'s Settings,
env_vars: EnvVars<'n>,
prompt: String,
}
pub fn spawn_shell(settings: &Settings, config: KubeConfig, session: &Session) -> Result<()> {
let kind = match &settings.shell {
Some(shell) => ShellKind::from_str(shell).ok_or_else(|| anyhow!("Invalid shell setting: {}", shell))?,
None => detect()?,
};
let temp_config_file = tempfile::Builder::new()
.prefix("kubie-config")
.suffix(".yaml")
.tempfile()?;
config.write_to_file(temp_config_file.path())?;
let temp_session_file = tempfile::Builder::new()
.prefix("kubie-session")
.suffix(".json")
.tempfile()?;
session.save(Some(temp_session_file.path()))?;
let depth = vars::get_depth();
let next_depth = depth + 1;
let mut env_vars = EnvVars::new();
// Pre-insert the KUBECONFIG variable into the shell.
// This will make sure any shell plugins/add-ons which require this env variable
// will have it available at the beginninng of the .rc file
env_vars.insert("KUBECONFIG", temp_config_file.path());
env_vars.insert("KUBIE_ACTIVE", "1");
env_vars.insert("KUBIE_DEPTH", next_depth.to_string());
env_vars.insert("KUBIE_KUBECONFIG", temp_config_file.path());
env_vars.insert("KUBIE_SESSION", temp_session_file.path());
env_vars.insert("KUBIE_STATE", state::paths::state());
env_vars.insert("KUBIE_PROMPT_DISABLE", if settings.prompt.disable { "1" } else { "0" });
env_vars.insert(
"KUBIE_ZSH_USE_RPS1",
if settings.prompt.zsh_use_rps1 { "1" } else { "0" },
);
env_vars.insert(
"KUBIE_FISH_USE_RPROMPT",
if settings.prompt.fish_use_rprompt { "1" } else { "0" },
);
env_vars.insert(
"KUBIE_XONSH_USE_RIGHT_PROMPT",
if settings.prompt.xonsh_use_right_prompt {
"1"
} else {
"0"
},
);
match kind {
ShellKind::Bash => {
env_vars.insert("KUBIE_SHELL", "bash");
}
ShellKind::Fish => {
env_vars.insert("KUBIE_SHELL", "fish");
}
ShellKind::Xonsh => {
env_vars.insert("KUBIE_SHELL", "xonsh");
}
ShellKind::Zsh => {
env_vars.insert("KUBIE_SHELL", "zsh");
}
ShellKind::Nu => {
env_vars.insert("KUBIE_SHELL", "nu");
}
}
let info = ShellSpawnInfo {
settings,
env_vars,
prompt: prompt::generate_ps1(settings, next_depth, kind),
};
match kind {
ShellKind::Bash => bash::spawn_shell(&info),
ShellKind::Fish => fish::spawn_shell(&info),
ShellKind::Xonsh => xonsh::spawn_shell(&info),
ShellKind::Zsh => zsh::spawn_shell(&info),
ShellKind::Nu => nu::spawn_shell(&info),
}
}
07070100000028000081A400000000000000000000000168642C230000048A000000000000000000000000000000000000001D00000000kubie-0.26.0/src/shell/nu.rsuse anyhow::Result;
use std::process::Command;
use crate::shell::ShellSpawnInfo;
pub fn spawn_shell(info: &ShellSpawnInfo) -> Result<()> {
// let dir = tempdir()?;
let mut cmd = Command::new("nu");
let mut args = "".to_string();
for (name, value) in &info.env_vars.vars {
args.push_str(&format!(
r#"$env.{} = '{}';"#,
name,
value.as_os_str().to_str().unwrap()
));
if String::from("KUBIE_PROMPT_DISABLE").eq(name) && value == "0" {
let mut _prompt = info.prompt.clone();
// TODO: This is improvable, but it works for now
_prompt = _prompt
.replace("\\[\\e[31m\\]", "")
.replace("\\[\\e[32m\\]", "")
.replace("\\[\\e[0m\\]", "")
.replace('$', "");
let prompt = format!(
r#"$env.PROMPT_COMMAND = {{ || $"{prompt}\n(create_left_prompt)" }};"#,
prompt = _prompt
);
args.push_str(prompt.as_str());
}
}
cmd.arg("-e");
cmd.arg(args);
let mut child = cmd.spawn()?;
child.wait()?;
Ok(())
}
07070100000029000081A400000000000000000000000168642C2300000CD0000000000000000000000000000000000000002100000000kubie-0.26.0/src/shell/prompt.rsuse std::env;
use std::fmt::{self, Display};
use crate::settings::Settings;
use crate::shell::ShellKind;
struct Command {
content: String,
shell_kind: ShellKind,
}
impl Command {
fn new(content: impl Into<String>, shell_kind: ShellKind) -> Command {
Command {
content: content.into(),
shell_kind,
}
}
}
impl fmt::Display for Command {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.shell_kind {
ShellKind::Fish => write!(f, "({})", self.content),
_ => write!(f, "$({})", self.content),
}
}
}
struct Color<D> {
color: u32,
content: D,
shell_kind: ShellKind,
}
impl<D> Color<D> {
fn new(color: u32, content: D, shell_kind: ShellKind) -> Color<D> {
Color {
color,
content,
shell_kind,
}
}
}
// FIXME: @Miuler Validate this implementation for nu shell
impl<D> Color<D>
where
D: Display,
{
fn isolate<E>(&self, f: &mut fmt::Formatter, content: E) -> fmt::Result
where
E: Display,
{
match self.shell_kind {
ShellKind::Fish | ShellKind::Xonsh => write!(f, "{content}"),
ShellKind::Zsh => write!(f, "%{{{content}%}}"),
ShellKind::Bash => write!(f, "\\[{content}\\]"),
_ => write!(f, "{content}"),
}
}
fn start_color(&self, f: &mut fmt::Formatter, color: u32) -> fmt::Result {
match self.shell_kind {
ShellKind::Xonsh => self.isolate(f, format!("\\033[{color}m")),
_ => self.isolate(f, format!("\\e[{color}m")),
}
}
fn end_color(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.shell_kind {
ShellKind::Xonsh => self.isolate(f, "\\033[0m"),
_ => self.isolate(f, "\\e[0m"),
}
}
}
impl<D> fmt::Display for Color<D>
where
D: Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.start_color(f, self.color)?;
write!(f, "{}", self.content)?;
self.end_color(f)?;
Ok(())
}
}
const RED: u32 = 31;
const GREEN: u32 = 32;
const BLUE: u32 = 34;
/// Generates a PS1 string that shows the current context, namespace and depth.
///
/// Makes sure to protect the escape sequences so that the shell will not count the escape
/// sequences in the length calculation of the prompt.
pub fn generate_ps1(settings: &Settings, depth: u32, shell_kind: ShellKind) -> String {
let current_exe_path = env::current_exe().expect("Could not get own binary path");
let current_exe_path_str = current_exe_path.to_str().expect("Binary path is not unicode");
let mut parts = vec![];
parts.push(
Color::new(
RED,
Command::new(format!("{current_exe_path_str} info ctx"), shell_kind),
shell_kind,
)
.to_string(),
);
parts.push(
Color::new(
GREEN,
Command::new(format!("{current_exe_path_str} info ns"), shell_kind),
shell_kind,
)
.to_string(),
);
if settings.prompt.show_depth && depth > 1 {
parts.push(Color::new(BLUE, depth, shell_kind).to_string());
}
format!("[{}]", parts.join("|"))
}
0707010000002A000081A400000000000000000000000168642C23000006CF000000000000000000000000000000000000002000000000kubie-0.26.0/src/shell/xonsh.rsuse std::io::{BufWriter, Write};
use std::process::Command;
use anyhow::Result;
use super::ShellSpawnInfo;
pub fn spawn_shell(info: &ShellSpawnInfo) -> Result<()> {
let temp_rc_file = tempfile::Builder::new()
.prefix("kubie-xonshrc")
.suffix(".xsh")
.tempfile()?;
let mut temp_rc_file_buf = BufWriter::new(temp_rc_file.as_file());
write!(
temp_rc_file_buf,
r#"
# https://xon.sh/xonshrc.html
from pathlib import Path
files = [
"/etc/xonshrc",
"~/.xonshrc",
"~/.config/xonsh/rc.xsh",
]
for file in files:
if Path(file).is_file():
source @(file)
if Path("~/.config/xonsh/rc.d").is_dir():
for file in path.glob('*.xsh'):
source @(file)
@events.on_precommand
def __kubie_cmd_pre_exec__(cmd):
$KUBECONFIG = $KUBIE_KUBECONFIG
"#
)?;
if !info.settings.prompt.disable {
write!(
temp_rc_file_buf,
r#"
$KUBIE_PROMPT='{}'
import re
# Fanciful prompt-command replacement as xonsh forces the use of PROMPT_FIELDS
for match in re.finditer(r'\$\(([^)]*)\)', $KUBIE_PROMPT):
command = match.group(1)
name = command.split().pop()
$PROMPT_FIELDS[name] = evalx(f'lambda: $({{command}}).strip()')
$KUBIE_PROMPT = $KUBIE_PROMPT.replace(f'$({{command}})', '{{' + name + '}}')
if $KUBIE_XONSH_USE_RIGHT_PROMPT == "1":
$RIGHT_PROMPT = $KUBIE_PROMPT + $RIGHT_PROMPT
else:
$PROMPT = $KUBIE_PROMPT + $PROMPT
del $KUBIE_PROMPT
"#,
info.prompt,
)?;
}
temp_rc_file_buf.flush()?;
let mut cmd = Command::new("xonsh");
cmd.arg("--rc");
cmd.arg(temp_rc_file.path());
info.env_vars.apply(&mut cmd);
let mut child = cmd.spawn()?;
child.wait()?;
Ok(())
}
0707010000002B000081A400000000000000000000000168642C230000130D000000000000000000000000000000000000001E00000000kubie-0.26.0/src/shell/zsh.rsuse std::fs::File;
use std::io::{BufWriter, Write};
use std::process::Command;
use anyhow::{Context, Result};
use tempfile::tempdir;
use super::ShellSpawnInfo;
pub fn spawn_shell(info: &ShellSpawnInfo) -> Result<()> {
let dir = tempdir()?;
{
let zshrc_path = dir.path().join(".zshrc");
let zshrc = File::create(zshrc_path).context("Could not open zshrc file")?;
let mut zshrc_buf = BufWriter::new(zshrc);
write!(
zshrc_buf,
r#"
# Reference for loading behavior
# https://shreevatsa.wordpress.com/2008/03/30/zshbash-startup-files-loading-order-bashrc-zshrc-etc/
if [[ -f "/etc/zshenv" ]] ; then
source "/etc/zshenv"
elif [[ -f "/etc/zsh/zshenv" ]] ; then
source "/etc/zsh/zshenv"
fi
if [[ -f "$HOME/.zshenv" ]] ; then
tmp_ZDOTDIR=$ZDOTDIR
source "$HOME/.zshenv"
# If the user has overridden $ZDOTDIR, we save that in $_KUBIE_USER_ZDOTDIR for later reference
# and reset $ZDOTDIR
if [[ "$tmp_ZDOTDIR" != "$ZDOTDIR" ]]; then
_KUBIE_USER_ZDOTDIR=$ZDOTDIR
ZDOTDIR=$tmp_ZDOTDIR
unset tmp_ZDOTDIR
fi
fi
# If a zsh_history file exists, copy it over before zsh initialization so history is maintained
if [[ -f "$HOME/.zsh_history" ]] ; then
cp $HOME/.zsh_history $ZDOTDIR
fi
KUBIE_LOGIN_SHELL=0
if [[ "$OSTYPE" == "darwin"* ]] ; then
KUBIE_LOGIN_SHELL=1
fi
if [[ -f "/etc/zprofile" && "$KUBIE_LOGIN_SHELL" == "1" ]] ; then
source "/etc/zprofile"
elif [[ -f "/etc/zsh/zprofile" && "$KUBIE_LOGIN_SHELL" == "1" ]] ; then
source "/etc/zsh/zprofile"
fi
if [[ -f "${{_KUBIE_USER_ZDOTDIR:-$HOME}}/.zprofile" && "$KUBIE_LOGIN_SHELL" == "1" ]] ; then
source "${{_KUBIE_USER_ZDOTDIR:-$HOME}}/.zprofile"
fi
if [[ -f "/etc/zshrc" ]] ; then
source "/etc/zshrc"
elif [[ -f "/etc/zsh/zshrc" ]] ; then
source "/etc/zsh/zshrc"
fi
if [[ -f "${{_KUBIE_USER_ZDOTDIR:-$HOME}}/.zshrc" ]] ; then
ZDOTDIR=$_KUBIE_USER_ZDOTDIR \
source "${{_KUBIE_USER_ZDOTDIR:-$HOME}}/.zshrc"
fi
if [[ -f "/etc/zlogin" && "$KUBIE_LOGIN_SHELL" == "1" ]] ; then
source "/etc/zlogin"
elif [[ -f "/etc/zsh/zlogin" && "$KUBIE_LOGIN_SHELL" == "1" ]] ; then
source "/etc/zsh/zlogin"
fi
if [[ -f "${{_KUBIE_USER_ZDOTDIR:-$HOME}}/.zlogin" && "$KUBIE_LOGIN_SHELL" == "1" ]] ; then
source "${{_KUBIE_USER_ZDOTDIR:-$HOME}}/.zlogin"
fi
unset _KUBIE_USER_ZDOTDIR
autoload -Uz add-zsh-hook
# This function sets the proper KUBECONFIG variable before a command runs,
# in case something overwrote it.
function __kubie_cmd_pre_exec__() {{
export KUBECONFIG="$KUBIE_KUBECONFIG"
}}
add-zsh-hook preexec __kubie_cmd_pre_exec__
"#,
)?;
if !info.settings.prompt.disable {
write!(
zshrc_buf,
r#"
# Activate prompt substitution.
setopt PROMPT_SUBST
# This function fixes the prompt via a precmd hook.
function __kubie_cmd_pre_cmd__() {{
local KUBIE_PROMPT=$'{}'
# If KUBIE_ZSH_USE_RPS1 is set, we use RPS1 instead of PS1.
if [[ "$KUBIE_ZSH_USE_RPS1" == "1" ]] ; then
# Avoid modifying RPS1 again if the RPS1 has not been reset.
if [[ "$RPS1" != *"$KUBIE_PROMPT"* ]] ; then
# If RPS1 is empty, we do not seperate with a space.
if [[ -z "$RPS1" ]] ; then
RPS1="$KUBIE_PROMPT"
else
RPS1="$KUBIE_PROMPT $RPS1"
fi
fi
else
# Avoid modifying PS1 again if the PS1 has not been reset.
if [[ "$PS1" != *"$KUBIE_PROMPT"* ]] ; then
PS1="$KUBIE_PROMPT $PS1"
fi
fi
}}
# When promptinit is activated, a precmd hook which updates PS1 is installed.
# In order to inject the kubie PS1 when promptinit is activated, we must
# also add our own precmd hook which modifies PS1 after promptinit themes.
add-zsh-hook precmd __kubie_cmd_pre_cmd__
"#,
info.prompt
)?;
}
if !info.settings.hooks.start_ctx.is_empty() {
write!(zshrc_buf, "{}", info.settings.hooks.start_ctx)?;
}
}
let mut cmd = Command::new("zsh");
cmd.env("ZDOTDIR", dir.path());
info.env_vars.apply(&mut cmd);
let mut child = cmd.spawn()?;
child.wait()?;
if !info.settings.hooks.stop_ctx.is_empty() {
let temp_exit_hook_file = tempfile::Builder::new()
.prefix("kubie-zsh-exit-hook")
.suffix(".zsh")
.tempfile()?;
let mut temp_exit_hook_file_buf = BufWriter::new(temp_exit_hook_file.as_file());
write!(temp_exit_hook_file_buf, "{}", info.settings.hooks.stop_ctx)?;
temp_exit_hook_file_buf.flush()?;
let mut exit_cmd = Command::new("zsh");
exit_cmd.arg(temp_exit_hook_file.path());
info.env_vars.apply(&mut exit_cmd);
let mut child = exit_cmd.spawn()?;
child.wait()?;
}
Ok(())
}
0707010000002C000081A400000000000000000000000168642C2300000BAA000000000000000000000000000000000000001A00000000kubie-0.26.0/src/state.rsuse std::fs::DirBuilder;
use std::{collections::HashMap, panic::UnwindSafe};
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use crate::ioutil;
pub mod paths {
use std::path::{Path, PathBuf};
use lazy_static::lazy_static;
lazy_static! {
static ref KUBIE_DATA_DIR: PathBuf = {
let base_data_dir = dirs::data_local_dir().expect("Could not get local data dir");
base_data_dir.join("kubie")
};
static ref KUBIE_STATE_PATH: PathBuf = KUBIE_DATA_DIR.join("state.json");
static ref KUBIE_STATE_LOCK_PATH: PathBuf = KUBIE_DATA_DIR.join(".state.json.lock");
}
#[inline]
pub fn data_dir() -> &'static Path {
&KUBIE_DATA_DIR
}
#[inline]
pub fn state() -> &'static Path {
&KUBIE_STATE_PATH
}
#[inline]
pub fn state_lock() -> &'static Path {
&KUBIE_STATE_LOCK_PATH
}
}
#[derive(Debug, Default, Deserialize, Serialize)]
pub struct State {
/// This map stores the last namespace in which a context was used, in order to restore the namespace
/// when the context is entered again.
///
/// The key represents the name of the context and the value is the namespace's name.
pub namespace_history: HashMap<String, Option<String>>,
}
impl State {
/// Loads the state.json from the filesystem, waiting for a file lock to ensure no other
/// concurrent Kubie processes are accessing/writing the file at the same time.
pub fn load() -> Result<State> {
Self::access(Ok)
}
/// Takes a closure that allows for modifications of the state. Automatically handles
/// locking/unlocking and saving after execution of the closure.
pub fn modify<F: FnOnce(&mut State) -> Result<()> + UnwindSafe>(func: F) -> Result<()> {
Self::access(|mut state| {
func(&mut state)?;
state.save()?;
Ok(())
})
}
fn access<R, F: FnOnce(State) -> Result<R> + UnwindSafe>(func: F) -> Result<R> {
// Create directory where state and lock will live.
DirBuilder::new()
.recursive(true)
.create(paths::data_dir())
.with_context(|| format!("Could not create data dir: {}", paths::data_dir().display()))?;
ioutil::file_lock(paths::state_lock(), || {
State::read_and_parse()
.with_context(|| format!("Could not load state file: {}", paths::state().display()))
.and_then(func)
})
}
fn read_and_parse() -> Result<State> {
if !paths::state().exists() {
return Ok(State::default());
}
ioutil::read_json(paths::state())
.with_context(|| format!("Failed to read state from '{}'", paths::state().display()))
}
fn save(&self) -> Result<()> {
ioutil::write_json(paths::state(), self)
.with_context(|| format!("Failed to write state to '{}'", paths::state().display()))
}
}
0707010000002D000081A400000000000000000000000168642C23000002E3000000000000000000000000000000000000001900000000kubie-0.26.0/src/vars.rsuse std::env;
use std::path::PathBuf;
use anyhow::{anyhow, Result};
/// Get the current depth of shells.
pub fn get_depth() -> u32 {
env::var("KUBIE_DEPTH")
.ok()
.and_then(|s| s.parse::<u32>().ok())
.unwrap_or(0)
}
/// Check if we're in a kubie shell.
pub fn is_kubie_active() -> bool {
let active = env::var("KUBIE_ACTIVE").unwrap_or_else(|_| "0".into());
active == "1"
}
/// Ensure that we're inside a kubie shell, returning an error if we aren't.
pub fn ensure_kubie_active() -> Result<()> {
if !is_kubie_active() {
return Err(anyhow!("Not in a kubie shell!"));
}
Ok(())
}
pub fn get_session_path() -> Option<PathBuf> {
env::var_os("KUBIE_SESSION").map(PathBuf::from)
}
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!324 blocks