diff --git a/.github/fetch_version/.releaserc.json b/.github/fetch_version/.releaserc.json new file mode 100644 index 0000000..0450a98 --- /dev/null +++ b/.github/fetch_version/.releaserc.json @@ -0,0 +1,4 @@ +{ + "branches": ["master"], + "plugins": ["@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator"] +} diff --git a/.github/workflows/dotnet-release.yml b/.github/workflows/dotnet-release.yml deleted file mode 100644 index c2f9ced..0000000 --- a/.github/workflows/dotnet-release.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: .Net Release - -on: [workflow_dispatch] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Setup .Net - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 5.0.100 - - name: Create Executables - run: ./build.sh --target Publish --no-logo - - name: Semantic Release - uses: cycjimmy/semantic-release-action@v2 - with: - extra_plugins: | - @semantic-release/exec - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/dotnet-test.yml b/.github/workflows/dotnet-test.yml deleted file mode 100644 index f4e0b5e..0000000 --- a/.github/workflows/dotnet-test.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: .Net Testing - -on: - push: - branches: - - '**' - - '!master' - - pull_request: - branches: - - '**' - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Setup .Net - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 5.0.100 - - name: Test - run: ./build.sh --target Compile --no-logo diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..cc8355d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,182 @@ +name: Release Binary + +on: + push: + branches: + - master + +jobs: + get_next_version: + runs-on: ubuntu-latest + name: Fetch next version number + steps: + - uses: actions/checkout@v2 + - name: semantic release + id: semantic + uses: cycjimmy/semantic-release-action@v2 + with: + dry_run: true + working_directory: .github/fetch_version + - run: echo ${{ steps.semantic.outputs.new_release_version }} + - run: echo ${{ steps.semantic.outputs.new_release_published }} + outputs: + create_release: ${{ steps.semantic.outputs.new_release_published }} + new_version: ${{ steps.semantic.outputs.new_release_version }} + + build_windows: + needs: get_next_version + if: needs.get_next_version.outputs.create_release == 'true' + strategy: + fail-fast: true + matrix: + include: + - target: x86_64-pc-windows-msvc + openssl_target: openssl:x64-windows-static-md + name: Build ${{ matrix.target }} on windows + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + + - name: set new version number (${{ needs.get_next_version.outputs.new_version }}) + run: (get-content -Path .\Cargo.toml) | %{$_ -replace "version = \`"0.0.0-development\`"","version = `"${{ needs.get_next_version.outputs.new_version }}`""} | set-content -Path .\Cargo.toml + + - name: install and setup vcpkg + uses: lukka/run-vcpkg@v10.1 + with: + vcpkgGitCommitId: b196dacc2f63f37bb75504c36c349042336749cb + + - name: setup openssl + run: vcpkg install ${{ matrix.openssl_target }} + + - name: setup rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: ${{ matrix.target }} + override: true + + - name: Build + uses: actions-rs/cargo@v1 + with: + command: build + args: --release --target ${{ matrix.target }} + + - name: upload artifacts + uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.target }} + path: | + target/${{ matrix.target }}/release/kuby.exe + + build_unix: + needs: get_next_version + if: needs.get_next_version.outputs.create_release == 'true' + strategy: + fail-fast: true + matrix: + include: + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + name: Build ${{ matrix.target }} on ubuntu + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: set new version number (${{ needs.get_next_version.outputs.new_version }}) + run: sed -i -e 's/^version = .*/version = "${{ needs.get_next_version.outputs.new_version }}"/' Cargo.toml + + - name: setup rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: ${{ matrix.target }} + override: true + + - name: Build + uses: actions-rs/cargo@v1 + with: + command: build + args: --release --target ${{ matrix.target }} + + - name: upload artifacts + uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.target }} + path: | + target/${{ matrix.target }}/release/kuby + + build_macos: + needs: get_next_version + if: needs.get_next_version.outputs.create_release == 'true' + strategy: + fail-fast: false + matrix: + include: + - target: aarch64-apple-darwin + - target: x86_64-apple-darwin + name: Build ${{ matrix.target }} on macos + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + + - name: set new version number (${{ needs.get_next_version.outputs.new_version }}) + run: sed -i -e 's/^version = .*/version = "${{ needs.get_next_version.outputs.new_version }}"/' Cargo.toml + + - name: setup rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + target: ${{ matrix.target }} + override: true + + - name: Build + uses: actions-rs/cargo@v1 + with: + command: build + use-cross: true + args: --release --target ${{ matrix.target }} + + - name: upload artifacts + uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.target }} + path: | + target/${{ matrix.target }}/release/kuby + + create_release: + needs: + - build_windows + - build_unix + - build_macos + if: needs.get_next_version.outputs.create_release == 'true' + name: Create release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/download-artifact@v3 + + - name: package m1 apple + uses: papeloto/action-zip@v1 + with: + files: aarch64-apple-darwin/ + dest: aarch64-apple-darwin.zip + - name: package intel apple + uses: papeloto/action-zip@v1 + with: + files: x86_64-apple-darwin/ + dest: x86_64-apple-darwin.zip + - name: package windows x64 + uses: papeloto/action-zip@v1 + with: + files: x86_64-pc-windows-msvc/ + dest: x86_64-pc-windows-msvc.zip + - name: package unix + uses: papeloto/action-zip@v1 + with: + files: x86_64-unknown-linux-gnu/ + dest: x86_64-unknown-linux-gnu.zip + + - name: create release + uses: cycjimmy/semantic-release-action@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 7afb26c..ea8c4bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,29 +1 @@ -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# Ci things -node_modules/ -tools/ -nuget/ -artifacts/ -coverage/ -.tmp/ - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Oo]ut/ - -# Testing results -coverage.json -coverage.info +/target diff --git a/.nuke b/.nuke deleted file mode 100755 index b2f1080..0000000 --- a/.nuke +++ /dev/null @@ -1 +0,0 @@ -Kuby.sln \ No newline at end of file diff --git a/.releaserc.json b/.releaserc.json index 8a806fa..b9eeb65 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -1,36 +1,17 @@ -{ - "verifyConditions": ["@semantic-release/github"], - "addChannel": ["@semantic-release/github"], - "prepare": [ - [ - "@semantic-release/exec", - { - "prepareCmd": "./build.sh --no-logo --version ${nextRelease.version} --target Publish" - } - ] - ], - "publish": [ - [ - "@semantic-release/github", - { - "assets": [ - { - "path": "artifacts/linux-x64/kuby", - "name": "kuby-linux-x64", - "label": "Kuby for linux x64 (${nextRelease.gitTag})" - }, - { - "path": "artifacts/osx-x64/kuby", - "name": "kuby-osx-x64", - "label": "Kuby for macOS / OSX x64 (${nextRelease.gitTag})" - }, - { - "path": "artifacts/win-x64/kuby.exe", - "name": "kuby-win-x64.exe", - "label": "Kuby for windows x64 (${nextRelease.gitTag})" - } - ] - } - ] - ] -} +{ + "branches": ["master"], + "plugins": [ + "@semantic-release/commit-analyzer", + "@semantic-release/release-notes-generator", + [ + "@semantic-release/github", + { + "assets": [ + { + "path": "./*.zip" + } + ] + } + ] + ] +} diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6d7aea2 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1385 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cc" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "serde", + "winapi", +] + +[[package]] +name = "clap" +version = "3.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63edc3f163b3c71ec8aa23f9bd6070f77edbf3d1d198b164afa90ff00e4ec62" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1132dc3944b31c20dd8b906b3a9f0a5d0243e092d59171414969657ac6aa85" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "console" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "regex", + "terminal_size", + "unicode-width", + "winapi", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + +[[package]] +name = "dialoguer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61579ada4ec0c6031cfac3f86fdba0d195a7ebeb5e36693bd53cb5999a25beeb" +dependencies = [ + "console", + "lazy_static", + "tempfile", + "zeroize", +] + +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +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.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[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", + "winapi", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-executor" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + +[[package]] +name = "httparse" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043f0e083e9901b6cc658a77d1eb86f4fc650bbb977a4337dd63192826aa85dd" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "jsonpath_lib" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaa63191d68230cccb81c5aa23abd53ed64d83337cacbb25a7b8c7979523774f" +dependencies = [ + "log", + "serde", + "serde_json", +] + +[[package]] +name = "k8s-openapi" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0489fc937cc7616a9abfa61bf39c250d7e32e1325ef028c8d9278dd24ea395b3" +dependencies = [ + "base64", + "bytes", + "chrono", + "http", + "percent-encoding", + "serde", + "serde-value", + "serde_json", + "url", +] + +[[package]] +name = "kube" +version = "0.69.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f06ab5c1d0d0bffbc96240728792fbe0f50139cf1320c285c8dc8eb0b4a09da" +dependencies = [ + "k8s-openapi", + "kube-client", + "kube-core", +] + +[[package]] +name = "kube-client" +version = "0.69.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "600ef6c2724d235b5fc725254e08d7bd1fd8de95976ca9c99d060b1cb7ce91e9" +dependencies = [ + "base64", + "bytes", + "chrono", + "dirs-next", + "either", + "futures", + "http", + "http-body", + "hyper", + "hyper-timeout", + "hyper-tls", + "jsonpath_lib", + "k8s-openapi", + "kube-core", + "openssl", + "pem", + "pin-project", + "secrecy", + "serde", + "serde_json", + "serde_yaml", + "thiserror", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower", + "tower-http", + "tracing", +] + +[[package]] +name = "kube-core" +version = "0.69.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a87945c0eccb682d387c3400c50c3bd8750d80127919a0a25119d68e7bd5d0a" +dependencies = [ + "chrono", + "form_urlencoded", + "http", + "k8s-openapi", + "once_cell", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "kuby" +version = "0.0.0-development" +dependencies = [ + "clap", + "colored", + "dialoguer", + "dirs", + "k8s-openapi", + "kube", + "openssl-sys", + "serde", + "serde_yaml", + "tokio", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" + +[[package]] +name = "linked-hash-map" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "mio" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +dependencies = [ + "winapi", +] + +[[package]] +name = "native-tls" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ntapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" +dependencies = [ + "winapi", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" + +[[package]] +name = "openssl" +version = "0.10.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ordered-float" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +dependencies = [ + "num-traits", +] + +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr", +] + +[[package]] +name = "pem" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9a3b09a20e374558580a4914d3b7d89bd61b954a5a5e1dcbea98753addb1947" +dependencies = [ + "base64", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + +[[package]] +name = "schannel" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" +dependencies = [ + "lazy_static", + "winapi", +] + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "serde", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "serde" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a521f2940385c165a24ee286aa8599633d162077a54bdcae2a6fd5a7bfa7a0" +dependencies = [ + "indexmap", + "ryu", + "serde", + "yaml-rust", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c27a64b625de6d309e8c57716ba93021dccf1b3b5c97edd6d3dd2d2135afc0a" +dependencies = [ + "libc", + "mio", + "num_cpus", + "once_cell", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tower" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5651b5f6860a99bd1adb59dbfe1db8beb433e73709d9032b413a77e2fb7c066a" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ed53e1fd082268841975cb39587fa9fca9a7a30da84f97818ef667c97f2872" +dependencies = [ + "base64", + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" + +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + +[[package]] +name = "tracing" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "zeroize" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c88870063c39ee00ec285a2f8d6a966e5b6fb2becc4e8dac77ed0d370ed6006" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8584394 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "kuby" +version = "0.0.0-development" +description = "Kubernetes config helpers and utilities." +edition = "2021" + +[dependencies] +clap = { version = "3.0.14", features = ["derive"] } +colored = "2.0.0" +dialoguer = "0.9.0" +dirs = "4.0.0" +k8s-openapi = { version = "0.14.0", features = ["v1_22"] } +kube = { version = "0.69.0" } +openssl-sys = "0.9.72" +serde = "1.0" +serde_yaml = "0.8" +tokio = { version = "1.16.1", features = ["rt-multi-thread", "macros"] } + +[target.'cfg(all(target_arch = "aarch64", target_os = "macos"))'.dependencies] +openssl-sys = { version = "0.9.72", features = ["vendored"] } diff --git a/Kuby.sln b/Kuby.sln deleted file mode 100755 index de8fed8..0000000 --- a/Kuby.sln +++ /dev/null @@ -1,28 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5F749BCF-7099-4989-8C5D-B42A288A9401}" -EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Kuby", "src\Kuby\Kuby.fsproj", "{7D166352-7A64-4F57-8FF0-1010443F3A90}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\_build.csproj", "{6096BE1B-F368-4338-AD7D-1C6098BF41AF}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{F4315FC3-2F26-41B4-92A6-DFECBB23C345}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6096BE1B-F368-4338-AD7D-1C6098BF41AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6096BE1B-F368-4338-AD7D-1C6098BF41AF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7D166352-7A64-4F57-8FF0-1010443F3A90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7D166352-7A64-4F57-8FF0-1010443F3A90}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7D166352-7A64-4F57-8FF0-1010443F3A90}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7D166352-7A64-4F57-8FF0-1010443F3A90}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {7D166352-7A64-4F57-8FF0-1010443F3A90} = {5F749BCF-7099-4989-8C5D-B42A288A9401} - {6096BE1B-F368-4338-AD7D-1C6098BF41AF} = {F4315FC3-2F26-41B4-92A6-DFECBB23C345} - EndGlobalSection -EndGlobal diff --git a/build.cmd b/build.cmd deleted file mode 100755 index 4a72f9b..0000000 --- a/build.cmd +++ /dev/null @@ -1,7 +0,0 @@ -:; set -eo pipefail -:; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) -:; ${SCRIPT_DIR}/build.sh "$@" -:; exit $? - -@ECHO OFF -powershell -ExecutionPolicy ByPass -NoProfile %0\..\build.ps1 %* diff --git a/build.ps1 b/build.ps1 deleted file mode 100755 index e5c8a44..0000000 --- a/build.ps1 +++ /dev/null @@ -1,69 +0,0 @@ -[CmdletBinding()] -Param( - [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)] - [string[]]$BuildArguments -) - -Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)" - -Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 } -$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent - -########################################################################### -# CONFIGURATION -########################################################################### - -$BuildProjectFile = "$PSScriptRoot\build\_build.csproj" -$TempDirectory = "$PSScriptRoot\\.tmp" - -$DotNetGlobalFile = "$PSScriptRoot\\global.json" -$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1" -$DotNetChannel = "Current" - -$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1 -$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1 -$env:DOTNET_MULTILEVEL_LOOKUP = 0 - -########################################################################### -# EXECUTION -########################################################################### - -function ExecSafe([scriptblock] $cmd) { - & $cmd - if ($LASTEXITCODE) { exit $LASTEXITCODE } -} - -# If dotnet CLI is installed globally and it matches requested version, use for execution -if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and ` - $(dotnet --version) -and $LASTEXITCODE -eq 0) { - $env:DOTNET_EXE = (Get-Command "dotnet").Path -} -else { - # Download install script - $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1" - New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null - [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile) - - # If global.json exists, load expected version - if (Test-Path $DotNetGlobalFile) { - $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json) - if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) { - $DotNetVersion = $DotNetGlobal.sdk.version - } - } - - # Install by channel or version - $DotNetDirectory = "$TempDirectory\dotnet-win" - if (!(Test-Path variable:DotNetVersion)) { - ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath } - } else { - ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } - } - $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe" -} - -Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)" - -ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet } -ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments } diff --git a/build.sh b/build.sh deleted file mode 100755 index 3d52643..0000000 --- a/build.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env bash - -bash --version 2>&1 | head -n 1 - -set -eo pipefail -SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) - -########################################################################### -# CONFIGURATION -########################################################################### - -BUILD_PROJECT_FILE="$SCRIPT_DIR/build/_build.csproj" -TEMP_DIRECTORY="$SCRIPT_DIR//.tmp" - -DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json" -DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh" -DOTNET_CHANNEL="Current" - -export DOTNET_CLI_TELEMETRY_OPTOUT=1 -export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1 -export DOTNET_MULTILEVEL_LOOKUP=0 - -########################################################################### -# EXECUTION -########################################################################### - -function FirstJsonValue { - perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}" -} - -# If dotnet CLI is installed globally and it matches requested version, use for execution -if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then - export DOTNET_EXE="$(command -v dotnet)" -else - # Download install script - DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh" - mkdir -p "$TEMP_DIRECTORY" - curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL" - chmod +x "$DOTNET_INSTALL_FILE" - - # If global.json exists, load expected version - if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then - DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")") - if [[ "$DOTNET_VERSION" == "" ]]; then - unset DOTNET_VERSION - fi - fi - - # Install by channel or version - DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix" - if [[ -z ${DOTNET_VERSION+x} ]]; then - "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path - else - "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path - fi - export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet" -fi - -echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)" - -"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet -"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@" diff --git a/build/.editorconfig b/build/.editorconfig deleted file mode 100755 index 31e43dc..0000000 --- a/build/.editorconfig +++ /dev/null @@ -1,11 +0,0 @@ -[*.cs] -dotnet_style_qualification_for_field = false:warning -dotnet_style_qualification_for_property = false:warning -dotnet_style_qualification_for_method = false:warning -dotnet_style_qualification_for_event = false:warning -dotnet_style_require_accessibility_modifiers = never:warning - -csharp_style_expression_bodied_methods = true:silent -csharp_style_expression_bodied_properties = true:warning -csharp_style_expression_bodied_indexers = true:warning -csharp_style_expression_bodied_accessors = true:warning diff --git a/build/Build.cs b/build/Build.cs deleted file mode 100755 index dfa674d..0000000 --- a/build/Build.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System.Collections.Generic; -using JetBrains.Annotations; -using Nuke.Common; -using Nuke.Common.CI; -using Nuke.Common.Execution; -using Nuke.Common.IO; -using Nuke.Common.ProjectModel; -using Nuke.Common.Tooling; -using Nuke.Common.Tools.DotNet; -using Nuke.Common.Utilities.Collections; -using static Nuke.Common.IO.FileSystemTasks; -using static Nuke.Common.Tools.DotNet.DotNetTasks; - -[CheckBuildProjectConfigurations] -[ShutdownDotNetAfterServerBuild] -class Build : NukeBuild -{ - public static int Main() => Execute(x => x.Compile); - - [Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")] - readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release; - - [Parameter("Version number that is built.")] readonly string Version = "0.0.0"; - - [Parameter("Single Runtime that should be built.")] [CanBeNull] readonly string Runtime; - - [Solution] readonly Solution Solution; - - AbsolutePath SourceDirectory => RootDirectory / "src"; - AbsolutePath TestsDirectory => RootDirectory / "tests"; - AbsolutePath ArtifactsDirectory => RootDirectory / "artifacts"; - - IEnumerable Runtimes = new[] {"linux-x64", "osx-x64", "win-x64"}; - - Target Clean => _ => _ - .Before(Restore) - .Executes(() => - { - SourceDirectory.GlobDirectories("**/bin", "**/obj").ForEach(DeleteDirectory); - TestsDirectory.GlobDirectories("**/bin", "**/obj").ForEach(DeleteDirectory); - EnsureCleanDirectory(ArtifactsDirectory); - }); - - Target Restore => _ => _ - .Executes(() => DotNetRestore(s => s.SetProjectFile(Solution))); - - Target Compile => _ => _ - .DependsOn(Restore) - .Executes(() => DotNetBuild(s => s - .SetProjectFile(Solution) - .SetConfiguration(Configuration) - .EnableNoRestore())); - - Target Publish => _ => _ - .DependsOn(Clean) - .Executes(() => DotNetPublish(s => s - .SetProject(Solution) - .SetConfiguration(Configuration) - .SetVersion(Version) - .SetAssemblyVersion(Version) - .SetFileVersion(Version) - .SetInformationalVersion(Version) - .AddProperty("SelfContained", true) - .AddProperty("PublishSingleFile", true) - .AddProperty("IncludeNativeLibrariesForSelfExtract", true) - .AddProperty("PublishTrimmed", Equals(Configuration, Configuration.Release)) - .CombineWith( - Runtimes, - (settings, runtime) => settings - .SetRuntime(runtime) - .SetOutput(ArtifactsDirectory / runtime)))); - - Target PublishSingle => _ => _ - .DependsOn(Clean) - .Requires(() => !string.IsNullOrWhiteSpace(Runtime)) - .Executes(() => DotNetPublish(s => s - .SetProject(Solution) - .SetConfiguration(Configuration) - .SetVersion(Version) - .SetAssemblyVersion(Version) - .SetFileVersion(Version) - .SetInformationalVersion(Version) - .AddProperty("SelfContained", true) - .AddProperty("IncludeNativeLibrariesForSelfExtract", true) - .AddProperty("PublishSingleFile", true) - .AddProperty("PublishTrimmed", Equals(Configuration, Configuration.Release)) - .SetRuntime(Runtime) - .SetOutput(ArtifactsDirectory / Runtime) - )); -} diff --git a/build/Configuration.cs b/build/Configuration.cs deleted file mode 100755 index 9c08b1a..0000000 --- a/build/Configuration.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.ComponentModel; -using System.Linq; -using Nuke.Common.Tooling; - -[TypeConverter(typeof(TypeConverter))] -public class Configuration : Enumeration -{ - public static Configuration Debug = new Configuration { Value = nameof(Debug) }; - public static Configuration Release = new Configuration { Value = nameof(Release) }; - - public static implicit operator string(Configuration configuration) - { - return configuration.Value; - } -} diff --git a/build/_build.csproj b/build/_build.csproj deleted file mode 100644 index 9b0243e..0000000 --- a/build/_build.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - Exe - net5.0 - - CS0649;CS0169 - .. - .. - - - - - - - - - ci\dotnet-release.yml - - - - - - config\.releaserc.json - - - - diff --git a/build/_build.csproj.DotSettings b/build/_build.csproj.DotSettings deleted file mode 100755 index 7bc2848..0000000 --- a/build/_build.csproj.DotSettings +++ /dev/null @@ -1,27 +0,0 @@ - - DO_NOT_SHOW - DO_NOT_SHOW - DO_NOT_SHOW - DO_NOT_SHOW - Implicit - Implicit - ExpressionBody - 0 - NEXT_LINE - True - False - 120 - IF_OWNER_IS_SINGLE_LINE - WRAP_IF_LONG - False - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> - True - True - True - True - True - True - True - True - True diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..6d4c8af --- /dev/null +++ b/renovate.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["github>buehler/renovate-config"] +} diff --git a/src/Kuby/.gitignore b/src/Kuby/.gitignore deleted file mode 100644 index 2ee5026..0000000 --- a/src/Kuby/.gitignore +++ /dev/null @@ -1 +0,0 @@ -[Kk]ubectl/ diff --git a/src/Kuby/Clipboard.fs b/src/Kuby/Clipboard.fs deleted file mode 100755 index 89091ae..0000000 --- a/src/Kuby/Clipboard.fs +++ /dev/null @@ -1,105 +0,0 @@ -module Kuby.Clipboard - -open System -open System.Diagnostics -open System.IO -open System.Reflection -open System.Runtime.InteropServices -open Kuby.ConsoleWriter -open McMaster.Extensions.CommandLineUtils - -let private basePath = - Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "kuby", "clipboard") - -let private isWsl = - if not (RuntimeInformation.IsOSPlatform OSPlatform.Linux) then - false - else - use proc = new Process() - - try - proc.StartInfo.FileName <- "which" - proc.StartInfo.Arguments <- ArgumentEscaper.EscapeAndConcatenate [ "explorer.exe" ] - proc.StartInfo.RedirectStandardOutput <- true - proc.StartInfo.RedirectStandardError <- true - proc.StartInfo.CreateNoWindow <- true - proc.Start() |> ignore - proc.WaitForExit() - - proc.ExitCode = 0 - with _ -> false - -let private targetExecutable = - if RuntimeInformation.IsOSPlatform OSPlatform.Windows - || isWsl then - Path.Join(basePath, "clipboard.exe") - else if RuntimeInformation.IsOSPlatform OSPlatform.Linux then - Path.Join(basePath, "xsel") - else - "pbcopy" - -let private executable = - let assembly = Assembly.GetExecutingAssembly() - - if RuntimeInformation.IsOSPlatform OSPlatform.Windows - || isWsl then - assembly.GetManifestResourceStream("Kuby.Clipboard.Windows.clipboard.exe") - else - assembly.GetManifestResourceStream("Kuby.Clipboard.Linux.xsel") - -let private prepare () = - async { - if RuntimeInformation.IsOSPlatform OSPlatform.OSX - then return () - - if not (File.Exists targetExecutable) then - use memStream = new MemoryStream() - executable.CopyTo memStream - Directory.CreateDirectory(basePath) |> ignore - - do! File.WriteAllBytesAsync(targetExecutable, memStream.ToArray()) - |> Async.AwaitTask - - if RuntimeInformation.IsOSPlatform OSPlatform.Linux then - use chmod = new Process() - chmod.StartInfo.FileName <- "chmod" - chmod.StartInfo.Arguments <- ArgumentEscaper.EscapeAndConcatenate([ "+x"; targetExecutable ]) - chmod.StartInfo.CreateNoWindow <- true - chmod.Start() |> ignore - do! chmod.WaitForExitAsync() |> Async.AwaitTask - - writeLine [ Color($@"Installed clipboard helper at ""{targetExecutable}""", Color.Cyan) ] - } - -let copy (content: string) = - async { - do! prepare () - - use proc = new Process() - - proc.StartInfo.FileName <- targetExecutable - proc.StartInfo.RedirectStandardOutput <- true - proc.StartInfo.RedirectStandardError <- true - - proc.StartInfo.Arguments <- - ArgumentEscaper.EscapeAndConcatenate - (seq { - if RuntimeInformation.IsOSPlatform OSPlatform.Windows - || isWsl then - "--copy" - - if RuntimeInformation.IsOSPlatform OSPlatform.Linux - && not isWsl then - "--clipboard" - "--input" - }) - - proc.StartInfo.RedirectStandardInput <- true - proc.StartInfo.CreateNoWindow <- true - proc.Start() |> ignore - proc.StandardInput.Write content - proc.StandardInput.Flush() - proc.StandardInput.Close() - - do! proc.WaitForExitAsync() |> Async.AwaitTask - } diff --git a/src/Kuby/Clipboard/Linux/xsel b/src/Kuby/Clipboard/Linux/xsel deleted file mode 100755 index a6b2fd3..0000000 Binary files a/src/Kuby/Clipboard/Linux/xsel and /dev/null differ diff --git a/src/Kuby/Clipboard/Windows/clipboard.exe b/src/Kuby/Clipboard/Windows/clipboard.exe deleted file mode 100644 index e69bcc2..0000000 Binary files a/src/Kuby/Clipboard/Windows/clipboard.exe and /dev/null differ diff --git a/src/Kuby/Commands/Base64.fs b/src/Kuby/Commands/Base64.fs deleted file mode 100755 index e5e56f2..0000000 --- a/src/Kuby/Commands/Base64.fs +++ /dev/null @@ -1,72 +0,0 @@ -namespace Kuby.Commands - -open System -open System.ComponentModel.DataAnnotations -open System.Text -open McMaster.Extensions.CommandLineUtils -open Kuby.Clipboard - -[] -type Encode() = - inherit BaseCommand() - - [] - [] - member val Content = "" with get, set - - [] - member val NoCopy = false with get, set - - override this.Execute _ = - async { - let result = - this.Content - |> Encoding.UTF8.GetBytes - |> Convert.ToBase64String - - printfn "Encoded content:" - printfn "%s" result - - if not this.NoCopy - then do! copy result - - return ReturnValues.success - } - -[] -type Decode() = - inherit BaseCommand() - - [] - [] - member val Content = "" with get, set - - [] - member val NoCopy = false with get, set - - override this.Execute _ = - async { - let result = - this.Content - |> Convert.FromBase64String - |> Encoding.UTF8.GetString - - printfn "Decoded content:" - printfn "%s" result - - if not this.NoCopy - then do! copy result - - return ReturnValues.success - } - -[] -[, typeof)>] -type Base64() = - inherit BaseCommand() - - override this.Execute app = - async { - if not app.IsShowingInformation then app.ShowHelp() else () - return ReturnValues.success - } diff --git a/src/Kuby/Commands/BaseCommand.fs b/src/Kuby/Commands/BaseCommand.fs deleted file mode 100755 index 2819eab..0000000 --- a/src/Kuby/Commands/BaseCommand.fs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Kuby.Commands - -open System.Threading.Tasks -open McMaster.Extensions.CommandLineUtils - -[] -type BaseCommand() = - member this.OnExecuteAsync app: Task = this.Execute app |> Async.StartAsTask - - abstract Execute: CommandLineApplication -> Async - abstract GetCodeCompletions: unit -> Async - default this.GetCodeCompletions() = async { return Seq.empty } diff --git a/src/Kuby/Commands/CompletionTemplate.fs b/src/Kuby/Commands/CompletionTemplate.fs deleted file mode 100755 index e2e1ac7..0000000 --- a/src/Kuby/Commands/CompletionTemplate.fs +++ /dev/null @@ -1,83 +0,0 @@ -namespace Kuby.Commands - -open System -open McMaster.Extensions.CommandLineUtils - -module private Templates = - // https://iridakos.com/programming/2018/03/01/bash-programmable-completion-tutorial -// let bash = -// String.Format -// (@" -//###-begin-{0}-completions-### -//# -//# {0} command completion script -//# -//# Installation: {0} completion --shell bash >> ~/.bashrc -//# or {0} completion --shell bash >> ~/.bash_profile on OSX. -//# -//_{0}_completions() -//{{ -// local cur_word args type_list -// cur_word=""${{COMP_WORDS[COMP_CWORD]}}"" -// args=(""${{COMP_WORDS[@]}}"") -// -// type_list=$({0} get-completions ""${{args[@]}}"") -// COMPREPLY=( $(compgen -W ""${{type_list}}"" -- ${{cur_word}}) ) -// -// # if no match was found, fall back to filename completion -// if [ ${{#COMPREPLY[@]}} -eq 0 ]; then -// COMPREPLY=() -// fi -// return 0 -//}} -//complete -o default -F _{0}_completions {0} -//###-end-{0}-completions-### -//", "kuby") - - let zsh = - String.Format - (@" -###-begin-{0}-completions-### -# -# {0} command completion script -# -# Installation: {0} completion --shell zsh >> ~/.zshrc -# or {0} completion --shell zsh >> ~/.zsh_profile on OSX. -# -_{0}_completions() -{{ - local reply - local si=$IFS - IFS=$'\n' reply=($({0} get-completions ""$BUFFER"")) - IFS=$si - _describe 'values' reply -}} -compdef _{0}_completions {0} -###-end-{0}-completions-### -", - "kuby") - -type ShellType = - //| Bash = 0 - | Zsh = 1 - -[> ~/.zshrc).")>] -type CompletionTemplate() = - inherit BaseCommand() - -// [] -// member val Shell = ShellType.Zsh with get, set - - override this.Execute _ = - async { -// match this.Shell with -//// | ShellType.Bash -> printf "%s" Templates.bash -// | ShellType.Zsh -> printf "%s" Templates.zsh -// | _ -> failwith "The provided shell value is not valid." - - printf "%s" Templates.zsh - return ReturnValues.success - } diff --git a/src/Kuby/Commands/Context.fs b/src/Kuby/Commands/Context.fs deleted file mode 100755 index 7e8ce2e..0000000 --- a/src/Kuby/Commands/Context.fs +++ /dev/null @@ -1,35 +0,0 @@ -namespace Kuby.Commands - -open Kuby.ConsoleWriter -open Kuby.Kubernetes -open McMaster.Extensions.CommandLineUtils -open Sharprompt - -[] -type Context() = - inherit BaseCommand() - - [] - member val NewContext = "" with get, set - - override this.Execute _ = - async { - if this.NewContext <> "" - && Context.printableCurrentContextName = this.NewContext then - return ReturnValues.success - else - if this.NewContext = "" then - writeLine [ Plain("The current context is: ") - Color(Context.printableCurrentContextName, Color.Yellow) ] - this.NewContext <- - Prompt.Select($"Select new context (arrows for nav, type for search)", Context.contextNames, 5) - - writeLine [ Plain("Switch current context to: ") - Color(this.NewContext, Color.Cyan) ] - - KubeConfig.update (fun c -> c.CurrentContext <- this.NewContext) - - return ReturnValues.success - } - - override this.GetCodeCompletions() = async { return Context.contextNames } diff --git a/src/Kuby/Commands/Deployment.fs b/src/Kuby/Commands/Deployment.fs deleted file mode 100755 index ea31003..0000000 --- a/src/Kuby/Commands/Deployment.fs +++ /dev/null @@ -1,162 +0,0 @@ -namespace Kuby.Commands.Deployment - -open System -open System.Collections -open System.IO -open System.Text -open System.Text.RegularExpressions -open Kuby -open Kuby.ConsoleWriter -open Kuby.Commands -open McMaster.Extensions.CommandLineUtils - -[] -type Deployment() = - inherit BaseCommand() - - [] - member val SourceFolder = "./k8s/" with get, set - - [] - member val DryRun = false with get, set - - [.")>] - member val Login: struct (bool * string) = (false, null) with get, set - - [] - member val Output = "" with get, set - - [] - member val Remove = false with get, set - - [] - member val Namespace = "" with get, set - - [] - member val Context = "" with get, set - - [] - member val EnvTrimPrefix = "" with get, set - - override this.Execute app = - async { - let sourcePath = - Path.GetFullPath - (if Path.IsPathRooted this.SourceFolder - then this.SourceFolder - else Path.Join(Directory.GetCurrentDirectory(), this.SourceFolder)) - - let rec getAllFiles dir = - seq { - yield! - Directory.EnumerateFiles(dir, "*.*") - |> Seq.filter (fun f -> f.EndsWith(".yaml") || f.EndsWith(".yml")) - - for d in Directory.EnumerateDirectories(dir) do - yield! getAllFiles d - } - - let targetDirectory = - if String.IsNullOrWhiteSpace this.Output then - Path.GetFullPath(Path.Join(Path.GetTempPath(), Path.GetRandomFileName())) - else - Path.GetFullPath - (if Path.IsPathRooted this.Output - then this.Output - else Path.Join(Directory.GetCurrentDirectory(), this.Output)) - - if not (Directory.Exists targetDirectory) then - Directory.CreateDirectory targetDirectory - |> ignore - - let envsubst (source: string) = - Environment.GetEnvironmentVariables() - |> Seq.cast - |> Seq.map (fun d -> d.Key :?> string, d.Value :?> string) - |> Map.ofSeq - |> Map.fold (fun source key value -> - let envkey = Strings.trimStart this.EnvTrimPrefix key - Regex.Replace(source, $@"\$({envkey}|{{{envkey}}})", value)) source - - do! getAllFiles sourcePath - |> Seq.map (fun file -> - async { - use sourceFile = File.OpenText file - let! source = sourceFile.ReadToEndAsync() |> Async.AwaitTask - - use destinationFile = - new StreamWriter(Path.Join(targetDirectory, Path.GetFileName file), false, Encoding.UTF8) - - do! destinationFile.WriteLineAsync(envsubst source) - |> Async.AwaitTask - }) - |> Async.Parallel - |> Async.Ignore - - if this.DryRun then - getAllFiles targetDirectory - |> Seq.iter (fun f -> - use source = File.OpenText f - - writeLines [ Color($@"Prepared file ""{Path.GetFileName f}"":", Color.Green) - Plain(source.ReadToEnd()) ]) - else - let kubeConfigPath = - Path.GetFullPath(Path.Join(Path.GetTempPath(), Path.GetRandomFileName())) - - let struct (login, loginContent) = this.Login - - if login then - let kc = KubeConfig() - kc.Path <- kubeConfigPath - - if not (String.IsNullOrWhiteSpace loginContent) - then kc.Content <- loginContent - - do! kc.Execute app |> Async.Ignore - - let! log, err = - Kubectl.execute - (seq { - if login then - "--kubeconfig" - kubeConfigPath - - if not (String.IsNullOrWhiteSpace this.Context) then - "--context" - this.Context - - if not (String.IsNullOrWhiteSpace this.Namespace) then - "--namespace" - this.Namespace - - if this.Remove then "delete" else "apply" - "-f" - targetDirectory - }) - - if not (String.IsNullOrWhiteSpace log) then writeLine [ Color(log, Color.Green) ] - - if not (String.IsNullOrWhiteSpace err) then writeLine [ Color(err, Color.Red) ] - - return ReturnValues.success - } diff --git a/src/Kuby/Commands/KubeConfig.fs b/src/Kuby/Commands/KubeConfig.fs deleted file mode 100755 index 98f7e01..0000000 --- a/src/Kuby/Commands/KubeConfig.fs +++ /dev/null @@ -1,160 +0,0 @@ -namespace Kuby.Commands.Deployment - -open System -open System.IO -open System.Text -open DotnetKubernetesClient -open Kuby.ConsoleWriter -open Kuby.Commands -open Kuby.Kubernetes -open Kuby.Strings -open McMaster.Extensions.CommandLineUtils -open Sharprompt -open k8s.KubeConfigModels -open k8s.Models - -[] -type Generate() = - inherit BaseCommand() - - let client = KubernetesClient() - - let getServiceAccounts (namespaceName: string) = - async { - let! serviceAccounts = - client.List(namespaceName) - |> Async.AwaitTask - - return - serviceAccounts - |> Seq.map (fun sa -> sa.Name()) - |> Seq.sort - } - - [] - member val Namespace = "" with get, set - - [] - member val ServiceAccount = "" with get, set - - override this.Execute _ = - async { - if String.IsNullOrWhiteSpace(this.Namespace) then - let! namespaces = Namespace.namespaceNames - - this.Namespace <- Prompt.Select($"Select namespace (arrows for nav, type for search)", namespaces, 5) - - if String.IsNullOrWhiteSpace(this.ServiceAccount) then - let! serviceAccounts = getServiceAccounts this.Namespace - - this.ServiceAccount <- - Prompt.Select($"Select service account (arrows for nav, type for search)", serviceAccounts, 5) - - let! secrets = - client.List(this.Namespace) - |> Async.AwaitTask - - match secrets - |> Seq.filter (fun s -> s.Type.Contains "service-account-token") - |> Seq.tryFind (fun s -> s.Name().StartsWith this.ServiceAccount) with - | Some (secret) -> - let resultConfig = K8SConfiguration() - - let token = - secret.Data.["token"] |> Encoding.UTF8.GetString - - let cluster = - match Cluster.currentCluster with - | Some (cluster) -> cluster - | _ -> Cluster() - - cluster.Name <- "cluster" - - resultConfig.ApiVersion <- "v1" - resultConfig.Kind <- "Config" - - resultConfig.Users <- - [ User(Name = this.ServiceAccount, UserCredentials = UserCredentials(Token = token)) ] - - resultConfig.Contexts <- - [ Context - (Name = "cluster-context", - ContextDetails = - ContextDetails(Cluster = "cluster", User = this.ServiceAccount, Namespace = this.Namespace)) ] - - resultConfig.Clusters <- [ cluster ] - resultConfig.CurrentContext <- "cluster-context" - - writeLines [ Plain - ($@"KubeConfig for service account ""{this.ServiceAccount}"" in namespace ""{ - this.Namespace - }"":") - Plain(KubeConfig.toString resultConfig) ] - - return ReturnValues.success - | None -> - writeLine [ Color("No secret deploy token was found for this account.", Color.Red) ] - return ReturnValues.failure - } - - override this.GetCodeCompletions() = - async { - if String.IsNullOrWhiteSpace(this.Namespace) - then return! Namespace.namespaceNames - else if String.IsNullOrWhiteSpace(this.ServiceAccount) - then return! getServiceAccounts this.Namespace - else return Seq.empty - } - -[] -[)>] -type KubeConfig() = - inherit BaseCommand() - - [] - member val Content = "" with get, set - - [] - member val Force = false with get, set - - [] - member val Path = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".kube", "config") with get, set - - override this.Execute _ = - async { - let path = - Path.GetFullPath - (if Path.IsPathRooted this.Path - then this.Path - else Path.Join(Directory.GetCurrentDirectory(), this.Path)) - - if Directory.Exists path then - writeLine [ Color("The given path is a directory.", Color.Red) ] - return ReturnValues.failure - else if String.IsNullOrWhiteSpace(this.Content) - && String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("KUBE_CONFIG")) then - writeLine [ Color("Neither content nor environment variable is set.", Color.Red) ] - return ReturnValues.failure - else if File.Exists(path) - && not this.Force - && not - (Prompt.GetYesNo($"Do you want to overwrite the config at {path}?", false, ConsoleColor.Yellow)) then - return ReturnValues.success - else - let content = - if String.IsNullOrWhiteSpace this.Content - then Environment.GetEnvironmentVariable("KUBE_CONFIG") - else this.Content - - let valid, text = isValidBase64 content - if valid then this.Content <- text - - File.WriteAllText(path, this.Content) - - return ReturnValues.success - } diff --git a/src/Kuby/Commands/Kuby.fs b/src/Kuby/Commands/Kuby.fs deleted file mode 100755 index 5660811..0000000 --- a/src/Kuby/Commands/Kuby.fs +++ /dev/null @@ -1,96 +0,0 @@ -namespace Kuby.Commands - -open System -open Kuby.Commands.Deployment -open McMaster.Extensions.CommandLineUtils - -[] -[, - typeof, - typeof, - typeof, - typeof, - typeof, - typeof, - typeof, - typeof)>] -type Kuby() = - inherit BaseCommand() - - override this.Execute app = - async { - if not app.IsShowingInformation then app.ShowHelp() else () - return ReturnValues.success - } - -and [] GetCompletions() = - inherit BaseCommand() - - let completionApp = new CommandLineApplication() - - do - completionApp.Conventions.UseDefaultConventions() - |> ignore - - completionApp.UnrecognizedArgumentHandling <- UnrecognizedArgumentHandling.CollectAndContinue - - [] - member val Arguments = "" with get, set - - override this.Execute _ = - async { - let args = this.Arguments.Split ' ' - let parsed = completionApp.Parse args - - let rec isAssignable (givenType: Type) (genericType: Type) = - if (givenType.IsGenericType - && givenType.GetGenericTypeDefinition() = genericType) - || Array.exists (fun (t: Type) -> - t.IsGenericType - && t.GetGenericTypeDefinition() = genericType) (givenType.GetInterfaces()) then - true - else if givenType.BaseType = null then - false - else - isAssignable givenType.BaseType genericType - - seq { - let description (description: string) = - if description = null then "" else $":{description}" - - yield! - parsed.SelectedCommand.Options - |> Seq.filter (fun o -> - not (Array.contains $"--{o.LongName}" args) - && not (Array.contains $"--{o.ShortName}" args) - && not (Array.contains $"--{o.SymbolName}" args)) - |> Seq.collect (fun o -> - seq { - yield $"--{o.LongName}{description o.Description}" - yield $"--{o.ShortName}{description o.Description}" - yield $"--{o.SymbolName}{description o.Description}" - }) - - yield! - parsed.SelectedCommand.Commands - |> Seq.filter (fun o -> o.ShowInHelpText) - |> Seq.collect (fun o -> o.Names |> Seq.map (fun n -> (n, o.Description))) - |> Seq.filter (fun (name, _) -> not <| Array.contains name args) - |> Seq.map (fun (name, desc) -> $"{name}{description desc}") - - if isAssignable (parsed.SelectedCommand.GetType()) typedefof> then - let baseCommand = - parsed - .SelectedCommand - .GetType() - .GetProperty("Model") - .GetValue(parsed.SelectedCommand) :?> BaseCommand - - yield! - baseCommand.GetCodeCompletions() - |> Async.RunSynchronously - } - |> Seq.iter (printfn "%s") - - return ReturnValues.success - } diff --git a/src/Kuby/Commands/Namespace.fs b/src/Kuby/Commands/Namespace.fs deleted file mode 100755 index ec856d3..0000000 --- a/src/Kuby/Commands/Namespace.fs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Kuby.Commands - -open Kuby.ConsoleWriter -open Kuby.Kubernetes -open McMaster.Extensions.CommandLineUtils -open Sharprompt - -[] -type Namespace() = - inherit BaseCommand() - - [] - member val NewNamespace = "" with get, set - - override this.Execute _ = - async { - writeLine [ Plain("The current namespace is: ") - Color(Namespace.printableCurrentNamespace, Color.Yellow) ] - - if this.NewNamespace = "" then - let! namespaces = Namespace.namespaceNames - - this.NewNamespace <- - Prompt.Select($"Select new namespace (arrows for nav, type for search)", namespaces, 5) - - writeLine [ Plain("Switch current namespace to: ") - Color(this.NewNamespace, Color.Cyan) ] - - KubeConfig.update (fun c -> - match c.Contexts - |> Seq.tryFind (fun ctx -> ctx.Name = c.CurrentContext) with - | Some (ctx) -> ctx.ContextDetails.Namespace <- this.NewNamespace - | _ -> ()) - - return ReturnValues.success - } - - override this.GetCodeCompletions() = Namespace.namespaceNames diff --git a/src/Kuby/Commands/ReturnValues.fs b/src/Kuby/Commands/ReturnValues.fs deleted file mode 100755 index 86f7444..0000000 --- a/src/Kuby/Commands/ReturnValues.fs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Kuby.Commands - -module ReturnValues = - let success = 0 - let failure = 1 diff --git a/src/Kuby/Commands/Secret.fs b/src/Kuby/Commands/Secret.fs deleted file mode 100755 index 94f4724..0000000 --- a/src/Kuby/Commands/Secret.fs +++ /dev/null @@ -1,140 +0,0 @@ -namespace Kuby.Commands.Deployment - -open System -open System.ComponentModel.DataAnnotations -open System.Text -open Kuby.ConsoleWriter -open Kuby.Commands -open McMaster.Extensions.CommandLineUtils -open YamlDotNet.Core -open YamlDotNet.Serialization -open YamlDotNet.Serialization.NamingConventions -open k8s.Models - -type private Base64Converter() = - interface IYamlTypeConverter with - member this.Accepts t = t = typeof - - member this.ReadYaml(parser, t) = - let scalar = - parser.Current :?> YamlDotNet.Core.Events.Scalar - - let bytes = Convert.FromBase64String scalar.Value - parser.MoveNext() |> ignore - bytes :> obj - - member this.WriteYaml(emitter, value, _) = - let bytes = value :?> byte [] - - emitter.Emit - (YamlDotNet.Core.Events.Scalar(null, null, Convert.ToBase64String bytes, ScalarStyle.Plain, true, false)) - - -[] -type Create() = - inherit BaseCommand() - - let serializer = - SerializerBuilder() - .ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitDefaults) - .WithNamingConvention(CamelCaseNamingConvention.Instance) - .WithTypeConverter(Base64Converter()) - .Build() - - [] - [] - member val Name = "" with get, set - - [] - member val Data = [| "" |] with get, set - - override this.Execute _ = - async { - let data = - this.Data - |> Array.map (fun d -> d.Split '=' |> List.ofArray) - |> Array.map (fun d -> - match d with - | name :: values -> Some(name, String.Join('=', values) |> Encoding.UTF8.GetBytes) - | _ -> None) - |> Array.choose id - |> dict - - let secret = - V1Secret - (ApiVersion = V1Secret.KubeApiVersion, - Kind = V1Secret.KubeKind, - Type = "opaque", - Metadata = V1ObjectMeta(Name = this.Name), - Data = data) - - writeLines [ Plain("Resulting secret:") - Plain(serializer.Serialize secret) ] - - return ReturnValues.success - } - -[] -type DockerSecret() = - inherit BaseCommand() - - [] - [] - member val Name = "" with get, set - - [] - member val Username = "" with get, set - - [] - member val Password = "" with get, set - - [] - member val Server = "https://index.docker.io/v1/" with get, set - - [] - member val Email = "" with get, set - - override this.Execute app = - async { - while String.IsNullOrWhiteSpace this.Username do - this.Username <- Prompt.GetString "Enter the username for the registry:" - - while String.IsNullOrWhiteSpace this.Password do - this.Password <- Prompt.GetPassword "Enter the password for the registry:" - - while String.IsNullOrWhiteSpace this.Email do - this.Email <- Prompt.GetString "Enter the email for the registry:" - - while String.IsNullOrWhiteSpace this.Server do - this.Server <- Prompt.GetString "Enter the server for the registry:" - - let auth = - $"{this.Username}:{this.Password}" - |> Encoding.UTF8.GetBytes - |> Convert.ToBase64String - - let cfg = - $@"{{""auths"":{{""{this.Server}"":{{""username"":""{this.Username}"",""password"":""{this.Password}"",""email"":""{ - this.Email - }"",""auth"":""{auth}""}}}}}}" - - let creator = Create() - creator.Name <- this.Name - creator.Data <- [|$".dockerconfigjson={cfg}"|] - - do! creator.Execute(app) |> Async.Ignore - - return ReturnValues.success - } - -[] -[, typeof)>] -type Secret() = - inherit BaseCommand() - - override this.Execute app = - async { - if not app.IsShowingInformation then app.ShowHelp() else () - return ReturnValues.success - } diff --git a/src/Kuby/Commands/Version.fs b/src/Kuby/Commands/Version.fs deleted file mode 100644 index 5955ff8..0000000 --- a/src/Kuby/Commands/Version.fs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Kuby.Commands - -open System.Reflection -open DotnetKubernetesClient -open Kuby -open Kuby.ConsoleWriter -open Kuby.Kubernetes -open McMaster.Extensions.CommandLineUtils - -[] -type Version() = - inherit BaseCommand() - - override this.Execute _ = - async { - let client = KubernetesClient() - - let server = - client.GetServerVersion() - |> Async.AwaitTask - |> Async.RunSynchronously - - let assemblyAttribute = - Assembly - .GetExecutingAssembly() - .GetCustomAttribute() - - let assembly = - if assemblyAttribute = null then "No explicit version." else assemblyAttribute.InformationalVersion - - writeLines [ Plain($"Kuby: v{assembly}") - Plain($"Kubectl: {Kubectl.version}") - Plain($"Current Server ({Cluster.currentClusterName}): v{server.Major}.{server.Minor}") - Plain($"Current Namespace: {Namespace.printableCurrentNamespace}") ] - - return ReturnValues.success - } diff --git a/src/Kuby/ConsoleWriter.fs b/src/Kuby/ConsoleWriter.fs deleted file mode 100755 index bce73fd..0000000 --- a/src/Kuby/ConsoleWriter.fs +++ /dev/null @@ -1,26 +0,0 @@ -module Kuby.ConsoleWriter - -open System - -type Color = ConsoleColor - -type Output = - | Plain of string - | Color of string * Color - -let private write (output: Output seq) (writer: string -> unit) = - output - |> Seq.iter (fun o -> - match o with - | Plain (s) -> writer s - | Color (s, c) -> - Console.ForegroundColor <- c - writer s - Console.ResetColor()) - -let writeLine (output: Output seq) = - write output Console.Write - Console.Write Environment.NewLine - -let writeLines (output: Output seq) = - write output Console.WriteLine diff --git a/src/Kuby/Kubectl.fs b/src/Kuby/Kubectl.fs deleted file mode 100755 index 10096c3..0000000 --- a/src/Kuby/Kubectl.fs +++ /dev/null @@ -1,69 +0,0 @@ -module Kuby.Kubectl - -open System -open System.Diagnostics -open System.IO -open System.Reflection -open System.Runtime.InteropServices -open McMaster.Extensions.CommandLineUtils -open Kuby.ConsoleWriter - -let version = "v1.19.4" - -let private basePath = - Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "kuby", "kubectl", version) - -let private targetExecutable = - if RuntimeInformation.IsOSPlatform OSPlatform.Windows - then Path.Join(basePath, "kubectl.exe") - else Path.Join(basePath, "kubectl") - -let private executable = - let assembly = Assembly.GetExecutingAssembly() - - if RuntimeInformation.IsOSPlatform OSPlatform.Windows then - assembly.GetManifestResourceStream("Kuby.Kubectl.windows.kubectl.exe") - else if RuntimeInformation.IsOSPlatform OSPlatform.Linux then - assembly.GetManifestResourceStream("Kuby.Kubectl.linux.kubectl") - else - assembly.GetManifestResourceStream("Kuby.Kubectl.darwin.kubectl") - -let private prepare () = - async { - if not (File.Exists targetExecutable) then - use memStream = new MemoryStream() - executable.CopyTo memStream - Directory.CreateDirectory(basePath) |> ignore - - do! File.WriteAllBytesAsync(targetExecutable, memStream.ToArray()) - |> Async.AwaitTask - - if RuntimeInformation.IsOSPlatform OSPlatform.Linux - || RuntimeInformation.IsOSPlatform OSPlatform.OSX then - use chmod = new Process() - chmod.StartInfo.FileName <- "chmod" - chmod.StartInfo.Arguments <- ArgumentEscaper.EscapeAndConcatenate([ "+x"; targetExecutable ]) - chmod.StartInfo.CreateNoWindow <- true - chmod.Start() |> ignore - do! chmod.WaitForExitAsync() |> Async.AwaitTask - - writeLine [ Color($@"Installed kubectl at ""{targetExecutable}""", Color.Cyan) ] - } - -let execute args = async { - do! prepare() - - use proc = new Process() - - proc.StartInfo.FileName <- targetExecutable - proc.StartInfo.RedirectStandardOutput <- true - proc.StartInfo.RedirectStandardError <- true - proc.StartInfo.Arguments <- ArgumentEscaper.EscapeAndConcatenate args - proc.StartInfo.CreateNoWindow <- true - proc.Start() |> ignore - do! proc.WaitForExitAsync() |> Async.AwaitTask - let! output = proc.StandardOutput.ReadToEndAsync() |> Async.AwaitTask - let! error = proc.StandardError.ReadToEndAsync() |> Async.AwaitTask - - return output, error -} diff --git a/src/Kuby/Kubernetes/Cluster.fs b/src/Kuby/Kubernetes/Cluster.fs deleted file mode 100755 index b81e729..0000000 --- a/src/Kuby/Kubernetes/Cluster.fs +++ /dev/null @@ -1,15 +0,0 @@ -module Kuby.Kubernetes.Cluster - -let currentCluster = - let config = KubeConfig.load() - let currentClusterName = match Context.currentContext with - | Some(ctx) -> ctx.ContextDetails.Cluster - | None -> "" - - config.Clusters - |> Seq.tryFind (fun c -> c.Name = currentClusterName) - -let currentClusterName = - match currentCluster with - | Some(cluster) -> cluster.Name - | None -> "" diff --git a/src/Kuby/Kubernetes/Context.fs b/src/Kuby/Kubernetes/Context.fs deleted file mode 100755 index fd444ae..0000000 --- a/src/Kuby/Kubernetes/Context.fs +++ /dev/null @@ -1,22 +0,0 @@ -module Kuby.Kubernetes.Context - -let currentContext = - let config = KubeConfig.load() - - config.Contexts - |> Seq.tryFind (fun c -> c.Name = config.CurrentContext) - -let currentContextName = - match currentContext with - | Some (ctx) -> Some ctx.Name - | None -> None - -let printableCurrentContextName = - match currentContextName with - | Some (ctx) -> ctx - | None -> "" - -let contexts = KubeConfig.load().Contexts - -let contextNames = - contexts |> Seq.map (fun c -> c.Name) |> Seq.sort diff --git a/src/Kuby/Kubernetes/KubeConfig.fs b/src/Kuby/Kubernetes/KubeConfig.fs deleted file mode 100755 index 5239bd8..0000000 --- a/src/Kuby/Kubernetes/KubeConfig.fs +++ /dev/null @@ -1,70 +0,0 @@ -module Kuby.Kubernetes.KubeConfig - -open System.Collections.Generic -open System.IO -open YamlDotNet.Core -open YamlDotNet.Serialization -open YamlDotNet.Serialization.EventEmitters -open YamlDotNet.Serialization.NamingConventions -open k8s -open k8s.KubeConfigModels - -type private EmitterState(valuePeriod: int) = - let mutable period = valuePeriod - let mutable currentIndex = 0 - - member this.VisitNext() = - currentIndex <- currentIndex + 1 - currentIndex % period = 0 - -type private StringEmitter(next: IEventEmitter) = - inherit ChainedEventEmitter(next) - - let state = Stack() - - do state.Push <| EmitterState(1) - - override this.Emit(eventInfo: ScalarEventInfo, emitter: IEmitter): unit = - if state.Peek().VisitNext() - && eventInfo.Source.Type = typeof then - eventInfo.Style <- ScalarStyle.DoubleQuoted - - base.Emit(eventInfo, emitter) - - override this.Emit(eventInfo: MappingStartEventInfo, emitter: IEmitter): unit = - state.Peek().VisitNext() |> ignore - state.Push <| EmitterState(2) - base.Emit(eventInfo, emitter) - - override this.Emit(eventInfo: MappingEndEventInfo, emitter: IEmitter): unit = - state.Pop() |> ignore - base.Emit(eventInfo, emitter) - - override this.Emit(eventInfo: SequenceStartEventInfo, emitter: IEmitter): unit = - state.Peek().VisitNext() |> ignore - state.Push <| EmitterState(1) - base.Emit(eventInfo, emitter) - - override this.Emit(eventInfo: SequenceEndEventInfo, emitter: IEmitter): unit = - state.Pop() |> ignore - base.Emit(eventInfo, emitter) - -let private serializer = - SerializerBuilder() - .ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitDefaults) - .WithNamingConvention(CamelCaseNamingConvention.Instance) - .WithEventEmitter(fun n -> StringEmitter(n)) - .Build() - -let load () = - KubernetesClientConfiguration.LoadKubeConfig() - -let save (config: K8SConfiguration) = - File.WriteAllText(config.FileName, (serializer.Serialize config)) - -let toString (config: K8SConfiguration) = serializer.Serialize config - -let update (updater: K8SConfiguration -> unit) = - let config = load () - updater config - save config diff --git a/src/Kuby/Kubernetes/Namespace.fs b/src/Kuby/Kubernetes/Namespace.fs deleted file mode 100755 index 9bf48c8..0000000 --- a/src/Kuby/Kubernetes/Namespace.fs +++ /dev/null @@ -1,25 +0,0 @@ -module Kuby.Kubernetes.Namespace - -open DotnetKubernetesClient -open k8s.Models - -let private client = KubernetesClient() - -let currentNamespace = - match Context.currentContext with - | None -> None - | Some (ctx) -> - match ctx.ContextDetails.Namespace with - | null -> None - | value -> Some value - -let printableCurrentNamespace = - match currentNamespace with - | Some (ns) -> ns - | None -> "default" - -let namespaceNames = - async { - let! ns = client.List() |> Async.AwaitTask - return ns |> Seq.map (fun a -> a.Name()) |> Seq.sort - } diff --git a/src/Kuby/Kuby.fsproj b/src/Kuby/Kuby.fsproj deleted file mode 100644 index b687ae0..0000000 --- a/src/Kuby/Kuby.fsproj +++ /dev/null @@ -1,61 +0,0 @@ - - - - Exe - net5.0 - preview - kuby - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - v1.19.4 - - - - - - - - - - - - - - - - - - - - diff --git a/src/Kuby/Program.fs b/src/Kuby/Program.fs deleted file mode 100755 index 6b09f51..0000000 --- a/src/Kuby/Program.fs +++ /dev/null @@ -1,8 +0,0 @@ -open Kuby.Commands -open McMaster.Extensions.CommandLineUtils - -[] -let main argv = - CommandLineApplication.ExecuteAsync argv - |> Async.AwaitTask - |> Async.RunSynchronously diff --git a/src/Kuby/Strings.fs b/src/Kuby/Strings.fs deleted file mode 100755 index 042c4b1..0000000 --- a/src/Kuby/Strings.fs +++ /dev/null @@ -1,24 +0,0 @@ -module Kuby.Strings - -open System -open System.Text - -let isValidBase64 (string: string) = - let buffer = - Span(Array.create string.Length 0uy) - - let isBase64, converted = - Convert.TryFromBase64String(string, buffer) - - let result = - Encoding.UTF8.GetString(buffer.ToArray(), 0, converted) - - let test = - Convert.ToBase64String(Encoding.UTF8.GetBytes(result)) - - isBase64 && string = test, result - -let rec trimStart (pattern: string) (string: string) = - if String.IsNullOrWhiteSpace pattern then string - else if string.StartsWith pattern then trimStart pattern (string.Substring pattern.Length) - else string diff --git a/src/commands/context.rs b/src/commands/context.rs new file mode 100644 index 0000000..7fea5db --- /dev/null +++ b/src/commands/context.rs @@ -0,0 +1,40 @@ +use colored::Colorize; +use dialoguer::theme::ColorfulTheme; +use dialoguer::Select; + +use crate::kubeconfig::{load, save}; + +pub async fn context(name: &Option) -> Result<(), Box> { + let mut config = load()?; + let contexts: Vec = config.contexts.iter().map(|c| c.name.to_string()).collect(); + let current_context = config.current_context.unwrap_or_else(|| "".to_string()); + + let new_context = match name { + Some(name) => name.to_string(), + None => { + let selected = Select::with_theme(&ColorfulTheme::default()) + .with_prompt(format!( + "Select new context (current: {})", + current_context.green() + )) + .default(0) + .items(&contexts) + .interact()?; + contexts + .get(selected) + .unwrap_or(&"".to_string()) + .to_string() + } + }; + + if current_context == new_context { + println!("{} is already set as context.", current_context.green()); + return Ok(()); + } + + println!("Set {} as active context.", new_context.green()); + config.current_context = Some(new_context); + save(&config)?; + + Ok(()) +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs new file mode 100644 index 0000000..ff0171d --- /dev/null +++ b/src/commands/mod.rs @@ -0,0 +1,29 @@ +use clap::Subcommand; + +pub mod context; +pub mod namespace; + +const CONTEXT_LONG_ABOUT: &str = r#"This command lets you switch your current Kubernetes context. +When you provide a new context (via the name attribute) the new context +is directly selected if possible. If you omit the name, +a list of avilabile contexts is shown and you can select one."#; +const NAMESPACE_LONG_ABOUT: &str = r#"This command lets you switch your current Kubernetes namespace. +When you provide a new namespace (via the name attribute) the new namespace +is directly selected if possible. If you omit the name, +a list of avilabile namespaces is shown and you can select one."#; + +#[derive(Subcommand)] +pub enum Commands { + #[clap(about = "Directly switch a context or show a list of available context", long_about = CONTEXT_LONG_ABOUT)] + #[clap(visible_alias = "ctx", visible_alias = "c")] + Context { + /// The new context to switch to. + name: Option, + }, + #[clap(about = "Directly switch a namespace or show a list of available namespaces", long_about = NAMESPACE_LONG_ABOUT)] + #[clap(visible_alias = "ns", visible_alias = "n")] + Namespace { + /// The new namespace to switch to. + name: Option, + }, +} diff --git a/src/commands/namespace.rs b/src/commands/namespace.rs new file mode 100644 index 0000000..9db5fbe --- /dev/null +++ b/src/commands/namespace.rs @@ -0,0 +1,75 @@ +use colored::Colorize; +use dialoguer::theme::ColorfulTheme; +use dialoguer::Select; +use k8s_openapi::api::core::v1::Namespace; +use kube::api::ListParams; +use kube::{Api, Client}; + +use crate::kubeconfig::{load, save}; + +pub async fn namespace(name: &Option) -> Result<(), Box> { + let mut config = load()?; + let default_context = "".to_string(); + let current_context_name = config.current_context.as_ref().unwrap_or(&default_context); + let current_namespace = config + .contexts + .iter() + .find(|&ctx| ctx.name == *current_context_name) + .expect("No context with name found.") + .clone() + .context + .namespace + .unwrap_or_else(|| "default".to_string()); + + let new_namespace = match name { + Some(name) => name.to_string(), + None => { + let client = Client::try_default().await?; + let namespaces: Api = Api::all(client); + let mut namespace_names = Vec::new(); + + for ns in namespaces.list(&ListParams::default()).await? { + match ns.metadata.name { + None => continue, + Some(name) => namespace_names.push(name), + } + } + + let selected = Select::with_theme(&ColorfulTheme::default()) + .with_prompt(format!( + "Select new namespace (current: {})", + current_namespace.green() + )) + .default(0) + .items(&namespace_names) + .interact()?; + namespace_names + .get(selected) + .unwrap_or(&"".to_string()) + .to_string() + } + }; + + if current_namespace == new_namespace { + println!("{} is already set as namespace.", current_namespace.green()); + return Ok(()); + } + + println!("Set {} as active namespace.", new_namespace.green()); + + let mut new_contexts = Vec::new(); + for mut ctx in config.contexts { + if ctx.name != *current_context_name { + new_contexts.push(ctx); + continue; + } + + ctx.context.namespace = Some(new_namespace.to_string()); + new_contexts.push(ctx); + } + + config.contexts = new_contexts; + save(&config)?; + + Ok(()) +} diff --git a/src/kubeconfig.rs b/src/kubeconfig.rs new file mode 100644 index 0000000..1f11fd5 --- /dev/null +++ b/src/kubeconfig.rs @@ -0,0 +1,22 @@ +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +use kube::config::{Kubeconfig, KubeconfigError}; + +pub fn load() -> Result { + Kubeconfig::read() +} + +pub fn save(config: &Kubeconfig) -> Result<(), Box> { + let yaml = serde_yaml::to_string(&config)?; + let mut file = File::create(default_kube_path().expect("No default config path available."))?; + file.write_all(yaml.as_bytes())?; + + Ok(()) +} + +fn default_kube_path() -> Option { + use dirs::home_dir; + home_dir().map(|h| h.join(".kube").join("config")) +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..3ab56b8 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,29 @@ +use clap::{AppSettings, Parser}; + +use crate::commands::context::context; +use crate::commands::namespace::namespace; +use crate::commands::Commands; + +mod commands; +mod kubeconfig; + +#[derive(Parser)] +#[clap(version, about, long_about = None)] +#[clap(global_setting(AppSettings::PropagateVersion))] +#[clap(global_setting(AppSettings::UseLongFormatForHelpSubcommand))] +struct Cli { + #[clap(subcommand)] + command: Commands, +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let cli = Cli::parse(); + + match &cli.command { + Commands::Context { name } => context(name).await?, + Commands::Namespace { name } => namespace(name).await?, + } + + Ok(()) +}