diff --git a/.gitignore b/.gitignore index 699bf92..ea8c4bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,120 +1 @@ -# Created by https://www.toptal.com/developers/gitignore/api/jetbrains+all,go -# Edit at https://www.toptal.com/developers/gitignore?templates=jetbrains+all,go - -### Go ### -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - -### Go Patch ### -/vendor/ -/Godeps/ - -### JetBrains+all ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml -# .idea/modules.xml -# .idea/*.iml -# .idea/modules -# *.iml -# *.ipr - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### JetBrains+all Patch ### -# Ignores the whole .idea folder and all .iml files -# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 - -.idea/ - -# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 - -*.iml -modules.xml -.idea/misc.xml -*.ipr - -# Sonarlint plugin -.idea/sonarlint - -# Builds -dist/ - -# Wixtoolset output -*.wixobj - -# End of https://www.toptal.com/developers/gitignore/api/jetbrains+all,godist/ +/target diff --git a/.goreleaser.yml b/.goreleaser.yml deleted file mode 100644 index 14100be..0000000 --- a/.goreleaser.yml +++ /dev/null @@ -1,38 +0,0 @@ -project_name: vumm -before: - hooks: - - go mod tidy -builds: - - env: - - CGO_ENABLED=0 - goos: - - linux - - windows - - darwin - goarch: - - 386 - - amd64 - ldflags: - - -s -w -X github.com/vumm/cli/internal/common.version={{.Version}} -X github.com/vumm/cli/internal/common.commit={{.ShortCommit}} -X github.com/vumm/cli/internal/common.date={{ .CommitDate }} -archives: - - name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}' - format_overrides: - - goos: windows - format: zip - files: - - README.md - - LICENSE -checksum: - name_template: 'checksums.txt' -snapshot: - name_template: "{{ .Tag }}-next" -changelog: - sort: asc - filters: - exclude: - - '^docs:' - - '^test:' - - '^cicd:' - - '^refactor' - - Merge pull request - - Merge branch diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..d946d68 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,45 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug 'vumm'", + "cargo": { + "args": [ + "build", + "--bin=vumm_cli", + "--package=vumm_cli" + ], + "filter": { + "name": "vumm_cli", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}/vumm_cli" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'rusty-vumm'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=rusty-vumm", + "--package=rusty-vumm" + ], + "filter": { + "name": "rusty-vumm", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0665f62 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "rust-analyzer.linkedProjects": ["./Cargo.toml"], + "workbench.colorCustomizations": { + "minimap.background": "#00000000", + "scrollbar.shadow": "#00000000" + } +} diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..48c3daa --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1664 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "filetime" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "windows-sys 0.48.0", +] + +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "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.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "h2" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[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.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.9", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[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.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +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 = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "ipnet" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" + +[[package]] +name = "linux-raw-sys" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b64f40e5e03e0d54f03845c8197d0291253cdbedfb1cb46b13c2c117554a9f4c" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "openssl" +version = "0.10.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[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.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "windows-sys 0.45.0", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[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.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "reqwest" +version = "0.11.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "winreg", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustix" +version = "0.37.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bbfc1d1c7c40c01715f47d71444744a81669ca84e8b63e25a55e169b1f86433" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "security-framework" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.162" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.162" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[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.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tar" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys 0.45.0", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.5", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vumm" +version = "0.1.0" +dependencies = [ + "tokio", + "vumm_api", + "vumm_cli", +] + +[[package]] +name = "vumm_api" +version = "0.1.0" +dependencies = [ + "flate2", + "futures", + "reqwest", + "semver", + "serde", + "serde_json", + "tar", + "thiserror", + "tokio", +] + +[[package]] +name = "vumm_cli" +version = "0.1.0" +dependencies = [ + "clap", + "regex", + "semver", + "tokio", + "vumm_api", + "vumm_installer", +] + +[[package]] +name = "vumm_installer" +version = "0.1.0" +dependencies = [ + "anyhow", + "semver", + "serde", + "serde_json", + "thiserror", + "tokio", + "vumm_api", +] + +[[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.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "wasm-streams" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +dependencies = [ + "libc", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..0459fce --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,38 @@ +[package] +authors = ["IllustrisJack", "paulhobbel"] +name = "vumm" +version = "0.1.0" +readme = "README.md" +description = "Venice Unleashed Mod Manager is a simple, fast and easy to use mod manager for Venice Unleashed" +homepage = "https://github.com/BF3RM/vumm" +repository = "https://github.com/BF3RM/vumm" +keywords = [ + "venice-unleashed", + "mod-manager", + "mod", + "venice", + "unleashed", + "bf3", + "battlefield", + "battlefield-3", +] +edition = "2021" +rust-version = "1.74.0" + +[workspace] +members = ["vumm_api", "vumm_cli", "vumm_installer"] + +[dependencies] +vumm_api = { path = "vumm_api" } +vumm_cli = { path = "vumm_cli" } + +tokio = { version = "1.35", features = ["full"] } + +[[example]] +name = "client_get_mod" +path = "examples/client_get_mod.rs" + +[profile.release] +strip = true +opt-level = "z" +lto = true diff --git a/cli.go b/cli.go deleted file mode 100644 index bfac743..0000000 --- a/cli.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "github.com/vumm/cli/cmd" -) - -func main() { - cmd.Execute() -} diff --git a/cmd/install.go b/cmd/install.go deleted file mode 100644 index c6717a4..0000000 --- a/cmd/install.go +++ /dev/null @@ -1,59 +0,0 @@ -package cmd - -import ( - "fmt" - "github.com/apex/log" - "github.com/caarlos0/ctrlc" - "github.com/spf13/cobra" - "github.com/vumm/cli/internal/context" - "github.com/vumm/cli/internal/pipe/fetcher" - "github.com/vumm/cli/internal/pipe/installer" - "github.com/vumm/cli/internal/pipeline" - "time" -) - -type installCmd struct { - cmd *cobra.Command - timeout time.Duration -} - -func newInstallCmd() *installCmd { - root := &installCmd{} - root.cmd = &cobra.Command{ - Use: "install [@]", - Aliases: []string{"add", "i"}, - Short: "Install a mod", - Long: "This command installs a mod and any mods that it depends on.", - Args: func(cmd *cobra.Command, args []string) error { - if len(args) < 1 { - return fmt.Errorf("install requires at least a name of the mod") - } - return nil - }, - - RunE: func(cmd *cobra.Command, args []string) error { - name := args[0] - - ctx, cancel := context.NewWithTimeout(client, root.timeout) - defer cancel() - - start := time.Now() - log.Info("installing...") - - err := ctrlc.Default.Run(ctx, func() error { - return pipeline.Run(ctx, fetcher.New(name), installer.Pipe{}) - }) - - if err != nil { - return fmt.Errorf("failed installing after %0.2fs: %w", time.Since(start).Seconds(), err) - } - - log.Infof("successfully installed after %0.2fs", time.Since(start).Seconds()) - return nil - }, - } - - root.cmd.Flags().DurationVar(&root.timeout, "timeout", 30*time.Minute, "Timeout for the install process") - - return root -} diff --git a/cmd/login.go b/cmd/login.go deleted file mode 100644 index ada76dc..0000000 --- a/cmd/login.go +++ /dev/null @@ -1,71 +0,0 @@ -package cmd - -import ( - "bufio" - "fmt" - "github.com/apex/log" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/vumm/cli/pkg/api" - "golang.org/x/crypto/ssh/terminal" - "os" - "strings" -) - -type loginCmd struct { - tokenType string - cmd *cobra.Command -} - -func newLoginCmd() *loginCmd { - root := &loginCmd{} - root.cmd = &cobra.Command{ - Use: "login", - Short: "Login with username and password", - Long: "Login with a username and password so you can publish your mod", - RunE: func(cmd *cobra.Command, args []string) error { - tokenType, err := api.PermissionTypeFromString(root.tokenType) - if err != nil { - return err - } - - reader := bufio.NewReader(os.Stdin) - - fmt.Print("Username: ") - username, err := reader.ReadString('\n') - if err != nil { - return err - } - - fmt.Print("Password: ") - bytePassword, err := terminal.ReadPassword(int(os.Stdin.Fd())) - if err != nil { - return err - } - fmt.Println() - - log.Info("logging in...") - token, _, err := client.Auth.Login(cmd.Context(), strings.TrimSpace(username), strings.TrimSpace(string(bytePassword)), tokenType) - if err != nil { - return err - } - - viper.Set("token", token.Token) - if err = viper.WriteConfig(); err != nil { - if _, ok := err.(viper.ConfigFileNotFoundError); ok { - return viper.SafeWriteConfig() - } else { - return err - } - } - - log.Info("logged in successfully") - - return nil - }, - } - - root.cmd.Flags().StringVar(&root.tokenType, "type", "publish", "Type of token to be generated (publish, readonly)") - - return root -} diff --git a/cmd/pack.go b/cmd/pack.go deleted file mode 100644 index efae4c9..0000000 --- a/cmd/pack.go +++ /dev/null @@ -1,50 +0,0 @@ -package cmd - -import ( - "fmt" - "github.com/apex/log" - "github.com/caarlos0/ctrlc" - "github.com/spf13/cobra" - "github.com/vumm/cli/internal/context" - "github.com/vumm/cli/internal/pipe/archiver" - "github.com/vumm/cli/internal/pipe/project" - "github.com/vumm/cli/internal/pipeline" - "time" -) - -type packCmd struct { - cmd *cobra.Command - timeout time.Duration -} - -func newPackCmd() *packCmd { - root := &packCmd{} - root.cmd = &cobra.Command{ - Use: "pack", - Short: "Create a tarball for a mod", - Long: "Packs the current mod into a tarball like the publish command would do", - - RunE: func(cmd *cobra.Command, args []string) error { - log.Info("packing...") - start := time.Now() - - ctx, cancel := context.NewWithTimeout(client, root.timeout) - defer cancel() - - err := ctrlc.Default.Run(ctx, func() error { - return pipeline.Run(ctx, project.Pipe{}, archiver.Pipe{Store: true}) - }) - if err != nil { - return fmt.Errorf("failed packing after %0.2fs: %w", time.Since(start).Seconds(), err) - } - - log.Infof("pack success after %0.2fs", time.Since(start).Seconds()) - - return nil - }, - } - - root.cmd.Flags().DurationVar(&root.timeout, "timeout", 30*time.Minute, "Timeout for the pack process") - - return root -} diff --git a/cmd/permissions.go b/cmd/permissions.go deleted file mode 100644 index 03e93b0..0000000 --- a/cmd/permissions.go +++ /dev/null @@ -1,89 +0,0 @@ -package cmd - -import ( - "fmt" - "github.com/apex/log" - "github.com/spf13/cobra" - "github.com/vumm/cli/pkg/api" - "strings" -) - -type grantCmd struct { - cmd *cobra.Command -} - -func newGrantCmd() *grantCmd { - root := &grantCmd{} - root.cmd = &cobra.Command{ - Use: "grant ", - Short: "Grant mod permissions to a user", - Long: `Give people mod permissions. Either grant someone with publish permissions -or give someone access to a private mod by granting them the readonly permission`, - Args: func(cmd *cobra.Command, args []string) error { - if len(args) != 3 { - return fmt.Errorf("accepts 3 arg(s), received %d", len(args)) - } - - if args[2] != "readonly" && args[2] != "publish" { - return fmt.Errorf("invalid permission type specified, only readonly and publish are supported") - } - - return nil - }, - RunE: func(cmd *cobra.Command, args []string) error { - mod, tag := extractModNameAndTag(args[0]) - permission, err := api.PermissionTypeFromString(args[2]) - if err != nil { - return err - } - _, err = client.Mods.GrantModPermissions(cmd.Context(), mod, tag, args[1], permission) - - if err != nil { - return err - } - - log.Infof("successfully granted user %s %s permissions on mod %s", args[1], args[2], args[0]) - - return nil - }, - } - - return root -} - -type revokeCmd struct { - cmd *cobra.Command -} - -func newRevokeCmd() *revokeCmd { - root := &revokeCmd{} - root.cmd = &cobra.Command{ - Use: "revoke ", - Short: "Revoke mod permissions of a user", - Long: `Revoke all mod permissions of a user`, - Args: cobra.ExactArgs(2), - RunE: func(cmd *cobra.Command, args []string) error { - mod, tag := extractModNameAndTag(args[0]) - - _, err := client.Mods.RevokeModPermissions(cmd.Context(), mod, tag, args[1]) - if err != nil { - return err - } - - log.Infof("successfully revoked user %s permissions on mod %s", args[1], args[0]) - - return nil - }, - } - - return root -} - -func extractModNameAndTag(mod string) (string, string) { - parts := strings.SplitN(mod, "@", 2) - if len(parts) > 1 { - return parts[0], parts[1] - } - - return parts[0], "" -} diff --git a/cmd/publish.go b/cmd/publish.go deleted file mode 100644 index 268614d..0000000 --- a/cmd/publish.go +++ /dev/null @@ -1,53 +0,0 @@ -package cmd - -import ( - "fmt" - "github.com/apex/log" - "github.com/caarlos0/ctrlc" - "github.com/spf13/cobra" - "github.com/vumm/cli/internal/context" - "github.com/vumm/cli/internal/pipe/archiver" - "github.com/vumm/cli/internal/pipe/project" - "github.com/vumm/cli/internal/pipe/publish" - "github.com/vumm/cli/internal/pipeline" - "time" -) - -type publishCmd struct { - cmd *cobra.Command - tag string - timeout time.Duration -} - -func newPublishCmd() *publishCmd { - root := &publishCmd{} - root.cmd = &cobra.Command{ - Use: "publish", - Short: "Publish a mod", - Long: "Publishes a mod to the registry so that it can by installed by others.", - - RunE: func(cmd *cobra.Command, args []string) error { - log.Info("publishing...") - start := time.Now() - - ctx, cancel := context.NewWithTimeout(client, root.timeout) - defer cancel() - - err := ctrlc.Default.Run(ctx, func() error { - return pipeline.Run(ctx, project.Pipe{}, archiver.Pipe{}, publish.Pipe{Tag: root.tag}) - }) - if err != nil { - return fmt.Errorf("failed publishing after %0.2fs: %w", time.Since(start).Seconds(), err) - } - - log.Infof("publish success after %0.2fs", time.Since(start).Seconds()) - - return nil - }, - } - - root.cmd.Flags().StringVarP(&root.tag, "tag", "t", "latest", "The version tag") - root.cmd.Flags().DurationVar(&root.timeout, "timeout", 30*time.Minute, "Timeout for the publish process") - - return root -} diff --git a/cmd/register.go b/cmd/register.go deleted file mode 100644 index 289017e..0000000 --- a/cmd/register.go +++ /dev/null @@ -1,70 +0,0 @@ -package cmd - -import ( - "bufio" - "fmt" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/vumm/cli/pkg/api" - "golang.org/x/crypto/ssh/terminal" - "os" - "strings" -) - -type registerCmd struct { - tokenType string - cmd *cobra.Command -} - -func newRegisterCmd() *registerCmd { - root := ®isterCmd{} - root.cmd = &cobra.Command{ - Use: "register", - Short: "Register with username and password", - Long: "Register with a username and password so you can publish your mod or access private mods", - RunE: func(cmd *cobra.Command, args []string) error { - tokenType, err := api.PermissionTypeFromString(root.tokenType) - if err != nil { - return err - } - - reader := bufio.NewReader(os.Stdin) - - fmt.Print("Username: ") - username, err := reader.ReadString('\n') - if err != nil { - return err - } - - fmt.Print("Password: ") - bytePassword, err := terminal.ReadPassword(int(os.Stdin.Fd())) - if err != nil { - return err - } - fmt.Println() - - fmt.Println("registering...") - token, _, err := client.Auth.Register(cmd.Context(), strings.TrimSpace(username), strings.TrimSpace(string(bytePassword)), tokenType) - if err != nil { - return err - } - - viper.Set("token", token.Token) - if err = viper.WriteConfig(); err != nil { - if _, ok := err.(viper.ConfigFileNotFoundError); ok { - return viper.SafeWriteConfig() - } else { - return err - } - } - - fmt.Println("registered successfully, you are automatically logged in") - - return nil - }, - } - - root.cmd.Flags().StringVar(&root.tokenType, "type", "publish", "Type of token to be generated (publish, readonly)") - - return root -} diff --git a/cmd/root.go b/cmd/root.go deleted file mode 100644 index 091c18c..0000000 --- a/cmd/root.go +++ /dev/null @@ -1,114 +0,0 @@ -package cmd - -import ( - "github.com/apex/log" - "github.com/apex/log/handlers/cli" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/vumm/cli/internal/common" - "github.com/vumm/cli/internal/updater" - "github.com/vumm/cli/pkg/api" - "os" -) - -func Execute() { - log.SetHandler(cli.Default) - newRootCmd().Execute() -} - -var client *api.Client - -type rootCmd struct { - cmd *cobra.Command - verbose bool -} - -func (cmd *rootCmd) Execute() { - if err := cmd.cmd.Execute(); err != nil { - log.WithError(err).Error("command failed") - os.Exit(1) - } -} - -func newRootCmd() *rootCmd { - cobra.OnInitialize(initConfig) - - root := &rootCmd{} - - root.cmd = &cobra.Command{ - Use: "vumm", - Short: "A mod workspace for Venice Unleashed", - Long: "Install and manage your favourite Venice Unleashed mods.", - SilenceErrors: true, - SilenceUsage: true, - Version: common.GetFullVersion(), - PersistentPreRun: func(cmd *cobra.Command, args []string) { - var options []api.Option - registryUrl := viper.GetString("registry") - if registryUrl != "" { - options = append(options, api.BaseURL(registryUrl)) - } - - token := viper.GetString("token") - if token != "" { - options = append(options, api.RoundTrip(&api.TokenAuthTransport{Token: token})) - } - - if root.verbose { - log.SetLevel(log.DebugLevel) - } - - var err error - client, err = api.New(options...) - if err != nil { - log.WithError(err).Fatal("Failed to initialise api client") - } - }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - release, available, _ := updater.PeriodicCheckForUpdates() - if available { - log.WithField("version", release.Version()).Info("update available, run vumm update to install") - } - }, - } - - root.cmd.PersistentFlags().String("registry", "", "Custom registry url") - root.cmd.PersistentFlags().String("token", "", "A access token to access the registry") - root.cmd.PersistentFlags().BoolVarP(&root.verbose, "verbose", "v", false, "Enable verbose output") - - cobra.CheckErr(viper.BindPFlag("registry", root.cmd.PersistentFlags().Lookup("registry"))) - cobra.CheckErr(viper.BindPFlag("token", root.cmd.PersistentFlags().Lookup("token"))) - - root.cmd.AddCommand(newInstallCmd().cmd) - //root.cmd.AddCommand(uninstallCmd) - - root.cmd.AddCommand(newPublishCmd().cmd) - root.cmd.AddCommand(newUnpublishCmd().cmd) - root.cmd.AddCommand(newPackCmd().cmd) - - root.cmd.AddCommand(newLoginCmd().cmd) - root.cmd.AddCommand(newRegisterCmd().cmd) - root.cmd.AddCommand(newGrantCmd().cmd) - root.cmd.AddCommand(newRevokeCmd().cmd) - - root.cmd.AddCommand(newUpdateCmd().cmd) - - return root -} - -func initConfig() { - home, err := os.UserHomeDir() - cobra.CheckErr(err) - - viper.AddConfigPath(home) - viper.SetConfigType("json") - viper.SetConfigName(".vumm") - viper.SetEnvPrefix("vumm") - viper.AutomaticEnv() - - if err := viper.ReadInConfig(); err != nil { - if _, ok := err.(viper.ConfigFileNotFoundError); !ok { - cobra.CheckErr(err) - } - } -} diff --git a/cmd/uninstall.go b/cmd/uninstall.go deleted file mode 100644 index c18a5b1..0000000 --- a/cmd/uninstall.go +++ /dev/null @@ -1,23 +0,0 @@ -package cmd - -import ( - "fmt" - "github.com/spf13/cobra" -) - -var uninstallCmd = &cobra.Command{ - Use: "uninstall ", - Aliases: []string{"remove", "u"}, - Short: "Remove a installed mod", - Long: "This command uninstalls a mods and any leftover dependencies", - Args: func(cmd *cobra.Command, args []string) error { - if len(args) < 1 { - return fmt.Errorf("install requires at least a name of the mod") - } - return nil - }, - - Run: func(cmd *cobra.Command, args []string) { - - }, -} diff --git a/cmd/unpublish.go b/cmd/unpublish.go deleted file mode 100644 index b3ddcef..0000000 --- a/cmd/unpublish.go +++ /dev/null @@ -1,48 +0,0 @@ -package cmd - -import ( - "fmt" - "github.com/Masterminds/semver" - "github.com/apex/log" - "github.com/spf13/cobra" - "strings" - "time" -) - -type unpublishCmd struct { - cmd *cobra.Command -} - -func newUnpublishCmd() *unpublishCmd { - root := &unpublishCmd{} - root.cmd = &cobra.Command{ - Use: "unpublish @", - Short: "Remove a mod from the registry", - Long: "Removes a mod version from the registry.", - Args: cobra.ExactArgs(1), - - RunE: func(cmd *cobra.Command, args []string) error { - parts := strings.Split(args[0], "@") - if len(parts) != 2 { - return fmt.Errorf("invalid mod version specified") - } - mod := parts[0] - version, err := semver.NewVersion(parts[1]) - if err != nil { - return fmt.Errorf("invalid mod version specified") - } - - start := time.Now() - log.Info("unpublishing...") - - if _, err = client.Mods.UnpublishModVersion(cmd.Context(), mod, version); err != nil { - return fmt.Errorf("unpublish unsuccessful after %0.2fs: %v", time.Since(start).Seconds(), err) - } - - log.Infof("unpublish successful after %0.2fs", time.Since(start).Seconds()) - return nil - }, - } - - return root -} diff --git a/cmd/update.go b/cmd/update.go deleted file mode 100644 index 201c35f..0000000 --- a/cmd/update.go +++ /dev/null @@ -1,41 +0,0 @@ -package cmd - -import ( - "github.com/apex/log" - "github.com/spf13/cobra" - "github.com/vumm/cli/internal/updater" -) - -type updateCmd struct { - cmd *cobra.Command -} - -func newUpdateCmd() *updateCmd { - root := &updateCmd{} - root.cmd = &cobra.Command{ - Use: "update", - Short: "Check for updates", - Long: "Check for updates and try to self update if a newer version is available", - RunE: func(cmd *cobra.Command, args []string) error { - log.Infof("checking for updates") - release, updateAvailable, err := updater.CheckForUpdates() - if err != nil { - return err - } - - if !updateAvailable { - log.Info("already up to date") - return nil - } - - log.Infof("new version available, installing version %s", release.Version()) - if _, err := updater.SelfUpdate(); err != nil { - return err - } - - return nil - }, - } - - return root -} diff --git a/examples/client_get_mod.rs b/examples/client_get_mod.rs new file mode 100644 index 0000000..f837aab --- /dev/null +++ b/examples/client_get_mod.rs @@ -0,0 +1,25 @@ +use vumm_api::Error; + +#[tokio::main] +async fn main() { + let client = vumm_api::Client::new(); + + let mod_name = String::from("mapeditor"); + let mod_version = String::from("0.2.0"); + + let mod_response = client.mods().get_version(mod_name, mod_version).await; + + match mod_response { + Ok(mod_) => { + println!("Mod: {:?}", mod_); + } + Err(e) => match e { + Error::NotFound(response) => { + println!("Mod not found: {}", response.status()); + } + _ => { + println!("Error: {}", e); + } + }, + } +} diff --git a/go.mod b/go.mod deleted file mode 100644 index 0248441..0000000 --- a/go.mod +++ /dev/null @@ -1,15 +0,0 @@ -module github.com/vumm/cli - -go 1.15 - -require ( - github.com/Masterminds/semver v1.5.0 - github.com/Masterminds/semver/v3 v3.1.0 - github.com/apex/log v1.9.0 - github.com/caarlos0/ctrlc v1.0.0 - github.com/creativeprojects/go-selfupdate v0.6.1 - github.com/google/go-cmp v0.5.6 - github.com/spf13/cobra v1.3.0 - github.com/spf13/viper v1.10.1 - golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 -) diff --git a/go.sum b/go.sum deleted file mode 100644 index 9ce8441..0000000 --- a/go.sum +++ /dev/null @@ -1,853 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -code.gitea.io/sdk/gitea v0.13.2 h1:wAnT/J7Z62q3fJXbgnecoaOBh8CM1Qq0/DakWxiv4yA= -code.gitea.io/sdk/gitea v0.13.2/go.mod h1:lee2y8LeV3kQb2iK+hHlMqoadL4bp27QOkOV/hawLKg= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= -github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver/v3 v3.1.0 h1:Y2lUDsFKVRSYGojLJ1yLxSXdMmMYTYls0rCvoqmMUQk= -github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0= -github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA= -github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= -github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= -github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/caarlos0/ctrlc v1.0.0 h1:2DtF8GSIcajgffDFJzyG15vO+1PuBWOMUdFut7NnXhw= -github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= -github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creativeprojects/go-selfupdate v0.6.1 h1:H+wSRrXJ8FbXRcIuN3u1fy7rO2Q03XURhEEcrSXRnxU= -github.com/creativeprojects/go-selfupdate v0.6.1/go.mod h1:Zr5CB9GEee179eQpho5k6eNAVv1NJoz3DcbkAz/bpVE= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= -github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo= -github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= -github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= -github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI= -github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= -github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= -github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= -github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= -github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= -github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= -github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= -github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= -github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0= -github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= -github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk= -github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= -github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= -github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= -github.com/tj/go-buffer v1.1.0/go.mod h1:iyiJpfFcR2B9sXu7KvjbT9fpM4mOelRSDTbntVj52Uc= -github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= -github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= -github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= -github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ulikunitz/xz v0.5.8 h1:ERv8V6GKqVi23rgu5cj9pVfVzJbOqAY2Ntl88O6c2nQ= -github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= -golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486 h1:5hpz5aRr+W1erYCL5JRhSUBJRph7l9XkNveoExlrKYk= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= -gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/internal/common/semver.go b/internal/common/semver.go deleted file mode 100644 index 778b384..0000000 --- a/internal/common/semver.go +++ /dev/null @@ -1,47 +0,0 @@ -package common - -import ( - "encoding/json" - "github.com/Masterminds/semver/v3" -) - -type SemverConstraints struct { - original string - *semver.Constraints -} - -func NewSemverConstraints(c string) (*SemverConstraints, error) { - constraints, err := semver.NewConstraint(c) - if err != nil { - return nil, err - } - - return &SemverConstraints{ - original: c, - Constraints: constraints, - }, nil -} - -func (c *SemverConstraints) String() string { - return c.original -} - -// UnmarshalJSON implements JSON.Unmarshaler interface. -func (c *SemverConstraints) UnmarshalJSON(b []byte) error { - var s string - if err := json.Unmarshal(b, &s); err != nil { - return err - } - temp, err := semver.NewConstraint(s) - if err != nil { - return err - } - c.original = s - c.Constraints = temp - return nil -} - -// MarshalJSON implements JSON.Marshaler interface. -func (c *SemverConstraints) MarshalJSON() ([]byte, error) { - return json.Marshal(c.String()) -} diff --git a/internal/common/strings.go b/internal/common/strings.go deleted file mode 100644 index b658e67..0000000 --- a/internal/common/strings.go +++ /dev/null @@ -1,16 +0,0 @@ -package common - -import "fmt" - -func ByteCountToHuman(b int) string { - const unit = 1000 - if b < unit { - return fmt.Sprintf("%d B", b) - } - div, exp := int64(unit), 0 - for n := b / unit; n >= unit; n /= unit { - div *= unit - exp++ - } - return fmt.Sprintf("%.1f %cB", float64(b)/float64(div), "kMGTPE"[exp]) -} diff --git a/internal/common/version.go b/internal/common/version.go deleted file mode 100644 index a536d8e..0000000 --- a/internal/common/version.go +++ /dev/null @@ -1,25 +0,0 @@ -package common - -import "fmt" - -var ( - version = "dev" - commit = "local" - date = "unknown" -) - -func GetVersion() string { - return version -} - -func GetFullVersion() string { - return fmt.Sprintf("%s-%s", version, commit) -} - -func GetBuildDate() string { - return date -} - -func IsRelease() bool { - return version != "dev" -} diff --git a/internal/common/vu.go b/internal/common/vu.go deleted file mode 100644 index 11cc89f..0000000 --- a/internal/common/vu.go +++ /dev/null @@ -1,62 +0,0 @@ -package common - -import ( - "encoding/json" - "fmt" - "github.com/Masterminds/semver" - "os" - "strings" -) - -var InternalMods = []string{"veniceext"} - -func IsInternalMod(mod string) bool { - for _, internalMod := range InternalMods { - if strings.ToLower(mod) == internalMod { - return true - } - } - - return false -} - -// ModMetadata holds info of the mod.json -type ModMetadata struct { - Name string `json:"Name"` - Version *semver.Version `json:"Version"` - Dependencies map[string]*SemverConstraints `json:"Dependencies"` -} - -func (m ModMetadata) String() string { - return fmt.Sprintf("%s@%s", m.Name, m.Version) -} - -func LoadModMetadata(metadataFile string) (ModMetadata, error) { - file, err := os.Open(metadataFile) - if err != nil { - return ModMetadata{}, err - } - defer file.Close() - - var metadata ModMetadata - err = json.NewDecoder(file).Decode(&metadata) - if err != nil { - return ModMetadata{}, err - } - - // Normalize names (to lowercase) - metadata.Name = strings.ToLower(metadata.Name) - - for dep, constraints := range metadata.Dependencies { - normalizedDep := strings.ToLower(dep) - - if normalizedDep == dep { - continue - } - delete(metadata.Dependencies, dep) - - metadata.Dependencies[normalizedDep] = constraints - } - - return metadata, nil -} diff --git a/internal/config/config.go b/internal/config/config.go deleted file mode 100644 index 063048e..0000000 --- a/internal/config/config.go +++ /dev/null @@ -1,32 +0,0 @@ -package config - -import ( - "fmt" - "os" - "path/filepath" -) - -var cachedPath string - -func init() { - path := GetPath() - if _, err := os.Stat(path); os.IsNotExist(err) { - err := os.MkdirAll(path, 0755) - if err != nil { - panic(fmt.Errorf("failed creating config path: %v", err)) - } - } -} - -func GetPath() string { - if cachedPath != "" { - return cachedPath - } - - homedir, err := os.UserHomeDir() - if err != nil { - panic(fmt.Errorf("failed resolving config path: %v", err)) - } - - return filepath.Join(homedir, ".vumm") -} diff --git a/internal/context/context.go b/internal/context/context.go deleted file mode 100644 index 8229ef9..0000000 --- a/internal/context/context.go +++ /dev/null @@ -1,66 +0,0 @@ -package context - -import ( - "context" - "github.com/vumm/cli/internal/project" - "github.com/vumm/cli/internal/workspace" - "github.com/vumm/cli/pkg/api" - "reflect" - "time" -) - -type Context struct { - context.Context - - Project *project.Project - WorkingDirectory string - ModList *workspace.ModList - Dependencies map[string]api.ModVersion - Client *api.Client - - values map[interface{}]interface{} -} - -func NewWithTimeout(client *api.Client, duration time.Duration) (*Context, context.CancelFunc) { - ctx, cancel := context.WithTimeout(context.Background(), duration) - - return &Context{ - Context: ctx, - Client: client, - values: map[interface{}]interface{}{}, - }, cancel -} - -// SetValue adds a value to the context for later usage -func (ctx *Context) SetValue(key, val interface{}) { - ctx.values[key] = val -} - -// Value tries to lookup a value within the context -func (ctx *Context) Value(key interface{}) interface{} { - return ctx.values[key] -} - -// ValueAs tries to lookup a value within the context and assign it to target -func (ctx *Context) ValueAs(key, target interface{}) bool { - val, ok := ctx.values[key] - if !ok { - return false - } - - if target == nil { - panic("errors: target cannot be nil") - } - targetVal := reflect.ValueOf(target) - targetTyp := targetVal.Type() - if targetTyp.Kind() != reflect.Ptr || targetVal.IsNil() { - panic("errors: target must be a non-nil pointer") - } - - if reflect.TypeOf(val).AssignableTo(targetTyp) { - targetVal.Elem().Set(reflect.ValueOf(val).Elem()) - return true - } - - return false -} diff --git a/internal/middleware/logger.go b/internal/middleware/logger.go deleted file mode 100644 index ce6ff66..0000000 --- a/internal/middleware/logger.go +++ /dev/null @@ -1,25 +0,0 @@ -package middleware - -import ( - "github.com/apex/log" - "github.com/apex/log/handlers/cli" - "github.com/vumm/cli/internal/context" -) - -const DefaultPadding = 3 - -// Logging is a middleware that automatically increases padding on the logger -func Logging(title string, next Next) Next { - return func(ctx *context.Context) error { - defer func() { - if cli.Default.Padding >= DefaultPadding*2 { - cli.Default.Padding /= 2 - } - }() - - log.Infof(title) - cli.Default.Padding *= 2 - - return next(ctx) - } -} diff --git a/internal/middleware/next.go b/internal/middleware/next.go deleted file mode 100644 index 76fc4a9..0000000 --- a/internal/middleware/next.go +++ /dev/null @@ -1,5 +0,0 @@ -package middleware - -import "github.com/vumm/cli/internal/context" - -type Next func(ctx *context.Context) error diff --git a/internal/pipe/archiver/archiver.go b/internal/pipe/archiver/archiver.go deleted file mode 100644 index 66f218f..0000000 --- a/internal/pipe/archiver/archiver.go +++ /dev/null @@ -1,53 +0,0 @@ -package archiver - -import ( - "bytes" - "fmt" - "github.com/apex/log" - "github.com/vumm/cli/internal/common" - "github.com/vumm/cli/internal/context" - "github.com/vumm/cli/pkg/tar" - "os" - "path/filepath" -) - -type Pipe struct { - Store bool -} - -func (Pipe) String() string { - return "archiver" -} - -func (p Pipe) Run(ctx *context.Context) error { - log.Info("compressing files") - - packager := tar.NewPackager() - packager.SetFileFilter(func(filePath string) bool { - return !ctx.Project.Ignorer.Matches(filePath) - }) - - var buf bytes.Buffer - if err := packager.Compress(ctx.Project.Directory, &buf); err != nil { - return err - } - log.Infof("compressed files to archive of %s", common.ByteCountToHuman(buf.Len())) - - if p.Store { - fileName := fmt.Sprintf("%s-%s.tgz", ctx.Project.Metadata.Name, ctx.Project.Metadata.Version) - log.WithField("file", fileName).Infof("saving archive") - file, err := os.Create(filepath.Join(ctx.WorkingDirectory, fileName)) - if err != nil { - return err - } - defer file.Close() - n, err := file.Write(buf.Bytes()) - if err != nil { - return err - } - log.Debugf("wrote %s to %s", common.ByteCountToHuman(n), file.Name()) - } - - ctx.SetValue("archive", &buf) - return nil -} diff --git a/internal/pipe/fetcher/dependency.go b/internal/pipe/fetcher/dependency.go deleted file mode 100644 index 6e199a2..0000000 --- a/internal/pipe/fetcher/dependency.go +++ /dev/null @@ -1,43 +0,0 @@ -package fetcher - -import ( - "github.com/vumm/cli/internal/common" - "strings" -) - -type modDependency struct { - Name string - Tag string - VersionConstraints *common.SemverConstraints -} - -func resolveModDependency(name string, version string) modDependency { - var err error - var tag string - var constraints *common.SemverConstraints - - // First try to parse constraint - constraints, err = common.NewSemverConstraints(version) - - // Else set it as tag - if err != nil { - tag = version - } - - return modDependency{ - Name: name, - Tag: tag, - VersionConstraints: constraints, - } -} - -func resolveModDependencyFromString(mod string) modDependency { - parts := strings.SplitN(mod, "@", 2) - - version := "latest" - if len(parts) > 1 { - version = parts[1] - } - - return resolveModDependency(parts[0], version) -} diff --git a/internal/pipe/fetcher/dependency_test.go b/internal/pipe/fetcher/dependency_test.go deleted file mode 100644 index a68a054..0000000 --- a/internal/pipe/fetcher/dependency_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package fetcher - -import ( - "testing" -) - -type modDependencyTest struct { - name, version string - expectedTag string - hasConstraints bool -} - -type modDependencyStringTest struct { - nameAndVersion string - expectedTag string - hasConstraints bool -} - -func TestResolveModDependency(t *testing.T) { - tests := []modDependencyTest{ - {"realitymod", "latest", "latest", false}, - {"realitymod", "0.1.0", "", true}, - {"realitymod", ">=0.1.0", "", true}, - } - - for _, test := range tests { - dep := resolveModDependency(test.name, test.version) - if dep.Tag != test.expectedTag { - t.Errorf("Tag %s not equal to expected %s", dep.Tag, test.expectedTag) - } - hasConstraints := dep.VersionConstraints != nil - if hasConstraints != test.hasConstraints { - t.Errorf("VersionConstraints %v not equal to expected %v", hasConstraints, test.hasConstraints) - } - } -} - -func TestResolveModDependencyFromString(t *testing.T) { - tests := []modDependencyStringTest{ - {"realitymod@latest", "latest", false}, - {"realitymod@0.1.0", "", true}, - {"realitymod@>=0.1.0", "", true}, - } - - for _, test := range tests { - dep := resolveModDependencyFromString(test.nameAndVersion) - if dep.Tag != test.expectedTag { - t.Errorf("Tag %s not equal to expected %s", dep.Tag, test.expectedTag) - } - hasConstraints := dep.VersionConstraints != nil - if hasConstraints != test.hasConstraints { - t.Errorf("VersionConstraints %v not equal to expected %v", hasConstraints, test.hasConstraints) - } - } -} diff --git a/internal/pipe/fetcher/fetcher.go b/internal/pipe/fetcher/fetcher.go deleted file mode 100644 index 71061fd..0000000 --- a/internal/pipe/fetcher/fetcher.go +++ /dev/null @@ -1,99 +0,0 @@ -package fetcher - -import ( - "fmt" - "github.com/apex/log" - "github.com/vumm/cli/internal/common" - "github.com/vumm/cli/internal/context" - "github.com/vumm/cli/pkg/api" -) - -// Pipe is a pipe that tries resolving the given mod and its dependencies -type Pipe struct { - mod string -} - -func New(mod string) Pipe { - return Pipe{mod: mod} -} - -func (Pipe) String() string { - return "gathering dependencies" -} - -func (p Pipe) Run(ctx *context.Context) error { - if ctx.Dependencies != nil { - return fmt.Errorf("dependencies where already resolved") - } - ctx.Dependencies = map[string]api.ModVersion{} - - // List with unresolved mod dependencies - unresolved := []modDependency{resolveModDependencyFromString(p.mod)} - - // TODO: Handle ctx.Done() - for len(unresolved) > 0 { - // Pop first unresolved - dep := unresolved[0] - unresolved = unresolved[1:] - - log.WithField("mod", dep.Name).Info("fetching metadata") - version, err := p.resolveModVersion(ctx, dep) - if err != nil { - return err - } - log.WithFields(log.Fields{ - "mod": version.Name, - "version": version.Version, - }).Debug("fetched metadata") - - if len(version.Dependencies) > 0 { - for name, version := range version.Dependencies { - if common.IsInternalMod(name) { - log.Debugf("skipped %s, is internal mod", name) - continue - } - - dep := resolveModDependency(name, version) - shouldAdd, err := p.checkCanAddDependency(ctx, dep) - if err != nil { - return err - } - - if shouldAdd { - unresolved = append(unresolved, dep) - } - } - } - - ctx.Dependencies[version.Name] = version - } - - return nil -} - -func (p Pipe) resolveModVersion(ctx *context.Context, dep modDependency) (api.ModVersion, error) { - mod, _, err := ctx.Client.Mods.GetMod(ctx, dep.Name) - if err != nil { - return api.ModVersion{}, err - } - if dep.Tag != "" { - return mod.GetVersionByTag(dep.Tag) - } - - return mod.GetLatestVersionByConstraints(dep.VersionConstraints) -} - -func (p Pipe) checkCanAddDependency(ctx *context.Context, dep modDependency) (bool, error) { - if version, ok := ctx.Dependencies[dep.Name]; ok { - // TODO: Handle edge case not compatible... - // Uhm what do we do if the dependency was found but not compatible??? - ok, errors := dep.VersionConstraints.Validate(version.Version) - if !ok { - return false, errors[0] - } - - return false, nil - } - - return true, nil -} diff --git a/internal/pipe/installer/installer.go b/internal/pipe/installer/installer.go deleted file mode 100644 index b666975..0000000 --- a/internal/pipe/installer/installer.go +++ /dev/null @@ -1,98 +0,0 @@ -package installer - -import ( - "fmt" - "github.com/apex/log" - "github.com/vumm/cli/internal/common" - "github.com/vumm/cli/internal/context" - "github.com/vumm/cli/internal/middleware" - "github.com/vumm/cli/internal/workspace" - "github.com/vumm/cli/pkg/api" - "github.com/vumm/cli/pkg/tar" - "os" - "path/filepath" - "time" -) - -type Pipe struct { -} - -func (p Pipe) String() string { - return "installing dependencies" -} - -func (p Pipe) Run(ctx *context.Context) error { - if len(ctx.Dependencies) == 0 { - log.Warn("nothing to install") - return nil - } - - packager := tar.NewPackager() - - if err := p.loadModList(ctx); err != nil { - return err - } - - for _, version := range ctx.Dependencies { - if err := p.installModVersion(ctx, packager, version); err != nil { - return err - } - } - - return p.updateModList(ctx) -} - -func (p Pipe) installModVersion(ctx *context.Context, packager tar.Packager, version api.ModVersion) error { - return middleware.Logging(fmt.Sprintf("installing %s@%s", version.Name, version.Version), func(ctx *context.Context) error { - log.Info("fetching archive") - - archiveBuf, _, err := ctx.Client.Mods.DownloadModArchive(ctx, version.Name, version.Version) - - if err != nil { - return err - } - log.WithField("size", common.ByteCountToHuman(archiveBuf.Len())).Debugf("downloaded archive file") - - modFolder := filepath.Join(ctx.WorkingDirectory, "Mods", version.Name) - - // 1. Make sure the mods folder exists - if err := os.MkdirAll(modFolder, os.ModePerm); err != nil { - return err - } - - // 2. Make sure the ext folder is removed - if err := os.RemoveAll(filepath.Join(modFolder, "ext")); err != nil { - return err - } - - start := time.Now() - log.Infof("extracting archive") - err = packager.Decompress(archiveBuf, modFolder) - if err != nil { - return err - } - log.WithField("time", time.Since(start).Truncate(time.Millisecond)).Debugf("extracted archive") - - ctx.ModList.EnableMod(version.Name) - - return nil - })(ctx) -} - -func (p Pipe) loadModList(ctx *context.Context) error { - log.WithField("file", "ModList.txt").Infof("loading") - - modList, err := workspace.TryLoadModList(ctx.WorkingDirectory) - if err != nil { - return err - } - ctx.ModList = modList - - return nil -} - -func (p Pipe) updateModList(ctx *context.Context) error { - log.WithField("file", "ModList.txt").Infof("updating") - - return ctx.ModList.Save() -} diff --git a/internal/pipe/project/project.go b/internal/pipe/project/project.go deleted file mode 100644 index 5cf9691..0000000 --- a/internal/pipe/project/project.go +++ /dev/null @@ -1,28 +0,0 @@ -package project - -import ( - "fmt" - "github.com/vumm/cli/internal/context" - "github.com/vumm/cli/internal/project" - "os" -) - -type Pipe struct { -} - -func (Pipe) String() string { - return "loading project" -} - -func (Pipe) Run(ctx *context.Context) error { - cwd, err := os.Getwd() - if err != nil { - return fmt.Errorf("failed receiving working directory: %v", err) - } - ctx.Project, err = project.Load(cwd) - if err != nil { - return fmt.Errorf("failed loading project: %v", err) - } - - return nil -} diff --git a/internal/pipe/publish/publisher.go b/internal/pipe/publish/publisher.go deleted file mode 100644 index df4b82a..0000000 --- a/internal/pipe/publish/publisher.go +++ /dev/null @@ -1,32 +0,0 @@ -package publish - -import ( - "bytes" - "fmt" - "github.com/apex/log" - "github.com/vumm/cli/internal/context" -) - -type Pipe struct { - Tag string -} - -func (Pipe) String() string { - return "publisher" -} - -func (p Pipe) Run(ctx *context.Context) error { - var archiveBuf bytes.Buffer - if !ctx.ValueAs("archive", &archiveBuf) { - return fmt.Errorf("missing archive buffer") - } - - log.Info("publishing to registry") - _, err := ctx.Client.Mods.PublishMod(ctx, ctx.Project.Metadata, p.Tag, &archiveBuf) - if err != nil { - return err - } - log.Infof("published %s successfully", ctx.Project.Metadata) - - return nil -} diff --git a/internal/pipeline/pipeline.go b/internal/pipeline/pipeline.go deleted file mode 100644 index 380625e..0000000 --- a/internal/pipeline/pipeline.go +++ /dev/null @@ -1,22 +0,0 @@ -package pipeline - -import ( - "fmt" - "github.com/vumm/cli/internal/context" - "github.com/vumm/cli/internal/middleware" -) - -type Pipe interface { - fmt.Stringer - Run(ctx *context.Context) error -} - -func Run(ctx *context.Context, pipeline ...Pipe) error { - for _, pipe := range pipeline { - if err := middleware.Logging(pipe.String(), pipe.Run)(ctx); err != nil { - return err - } - } - - return nil -} diff --git a/internal/project/project.go b/internal/project/project.go deleted file mode 100644 index c48d485..0000000 --- a/internal/project/project.go +++ /dev/null @@ -1,68 +0,0 @@ -package project - -import ( - "github.com/apex/log" - "github.com/vumm/cli/internal/common" - "github.com/vumm/cli/pkg/ignorer" - "os" - "path/filepath" -) - -var defaultIgnoresLines = []string{ - // Git - ".git", - ".gitmodules", - ".gitignore", - ".github/", - - // Node - "node_modules/", - "package.json", - "package-lock.json", - "yarn.lock", - - // Editors - ".vscode/", - ".idea/", - ".editorconfig", - "*.iml", - - // VU (ui folders, these should be compiled to a ui.vuic anyways) - "^[Uu][Ii]/", - "^[Ww]eb[Uu][Ii]/", - ".vummignore", // yea lets also remove ourselves -} - -type Project struct { - Metadata common.ModMetadata - Directory string - Ignorer ignorer.Ignorer -} - -func Load(projectPath string) (*Project, error) { - log.WithField("file", "mod.json").Info("loading metadata") - metadata, err := common.LoadModMetadata(filepath.Join(projectPath, "mod.json")) - if err != nil { - return nil, err - } - log.WithField("file", "mod.json").Debug("loaded metadata") - - log.WithField("file", ".vummignore").Info("loading ignore file") - fileIgnorer, err := ignorer.CompileIgnorerFromFile(filepath.Join(projectPath, ".vummignore"), defaultIgnoresLines...) - if err != nil { - if !os.IsNotExist(err) { - return nil, err - } - - fileIgnorer = ignorer.CompileIgnorerFromLines(defaultIgnoresLines...) - log.Debug("no .vummignore found, using default") - } else { - log.WithField("file", ".vummignore").Debug("loaded ignore file") - } - - return &Project{ - Metadata: metadata, - Directory: projectPath, - Ignorer: fileIgnorer, - }, nil -} diff --git a/internal/updater/periodic.go b/internal/updater/periodic.go deleted file mode 100644 index 722655b..0000000 --- a/internal/updater/periodic.go +++ /dev/null @@ -1,47 +0,0 @@ -package updater - -import ( - "github.com/creativeprojects/go-selfupdate" - "github.com/vumm/cli/internal/common" - "github.com/vumm/cli/internal/config" - "os" - "path/filepath" - "time" -) - -const updateInterval = time.Hour * 24 * 7 // 1 week - -func PeriodicCheckForUpdates() (*selfupdate.Release, bool, error) { - if !shouldCheck() { - return nil, false, nil - } - - return CheckForUpdates() -} - -func shouldCheck() bool { - // Don't check for updates on development versions - if !common.IsRelease() { - return false - } - - checkFile := filepath.Join(config.GetPath(), "last-update-check") - - nextCheck := time.Now().Add(-updateInterval) - var lastChecked time.Time - - stat, err := os.Stat(checkFile) - if err != nil { - lastChecked = nextCheck.Add(-time.Millisecond) - } else { - lastChecked = stat.ModTime() - } - - if nextCheck.After(lastChecked) { - f, _ := os.Create(checkFile) - f.Close() - return true - } - - return false -} diff --git a/internal/updater/updater.go b/internal/updater/updater.go deleted file mode 100644 index fe9dab9..0000000 --- a/internal/updater/updater.go +++ /dev/null @@ -1,67 +0,0 @@ -package updater - -import ( - "errors" - "fmt" - "github.com/creativeprojects/go-selfupdate" - "github.com/vumm/cli/internal/common" - "log" - "os" - "runtime" -) - -var latestVersion *selfupdate.Release -var updater *selfupdate.Updater - -func init() { - var err error - updater, err = selfupdate.NewUpdater(selfupdate.Config{Validator: &selfupdate.ChecksumValidator{UniqueFilename: "checksums.txt"}}) - if err != nil { - panic(err) - } -} - -func CheckForUpdates() (*selfupdate.Release, bool, error) { - latest, found, err := updater.DetectLatest("BF3RM/vumm-cli") - if err != nil { - return nil, false, fmt.Errorf("failed to fetch latest version: %v", err) - } - - if !found { - return nil, false, fmt.Errorf("failed to find latest version for %s", runtime.GOOS) - } - - latestVersion = latest - return latest, IsUpdateAvailable(), nil -} - -func IsUpdateAvailable() bool { - if latestVersion == nil || !common.IsRelease() { - return false - } - - return latestVersion.GreaterThan(common.GetVersion()) -} - -func SelfUpdate() (bool, error) { - if latestVersion == nil { - _, _, err := CheckForUpdates() - if err != nil { - return false, err - } - } - - if !IsUpdateAvailable() { - return false, nil - } - - exe, err := os.Executable() - if err != nil { - return false, errors.New("could not locate executable path") - } - if err := updater.UpdateTo(latestVersion, exe); err != nil { - return false, fmt.Errorf("error occurred while updating binary: %v", err) - } - log.Printf("Successfully updated to version %s", latestVersion.Version()) - return false, nil -} diff --git a/internal/workspace/modlist.go b/internal/workspace/modlist.go deleted file mode 100644 index edc7c3a..0000000 --- a/internal/workspace/modlist.go +++ /dev/null @@ -1,123 +0,0 @@ -package workspace - -import ( - "bufio" - "fmt" - "github.com/apex/log" - "os" - "path/filepath" - "strings" -) - -type ModList struct { - dir string - lines []string -} - -func TryLoadModList(dir string) (*ModList, error) { - modList := &ModList{ - dir: dir, - lines: []string{}, - } - - filePath := filepath.Join(dir, "ModList.txt") - log.WithField("file", filePath).Debugf("loading mod list") - file, err := os.Open(filePath) - if err != nil { - if os.IsNotExist(err) { - log.Warn("mod list not found, creating") - return modList, nil - } - - return nil, err - } - defer file.Close() - - scanner := bufio.NewScanner(file) - for scanner.Scan() { - modList.lines = append(modList.lines, scanner.Text()) - } - if err = scanner.Err(); err != nil { - return nil, err - } - - return modList, nil -} - -func (m *ModList) EnableMod(mod string) bool { - mod = strings.ToLower(mod) - - enabled, idx := m.isModEnabled(mod) - - // not found, add new line - if idx == -1 { - m.lines = append(m.lines, mod) - return true - } - - m.lines[idx] = mod - - // disabled - return !enabled -} - -func (m *ModList) DisableMod(mod string) bool { - mod = strings.ToLower(mod) - - enabled, idx := m.isModEnabled(mod) - - // not found, nothing to do - if idx == -1 { - return false - } - - // enabled, lets disable - if enabled { - m.lines[idx] = "#" + mod - return true - } - - // Replace anyway to remove leftover spaces - m.lines[idx] = mod - return false -} - -func (m ModList) isModEnabled(mod string) (bool, int) { - for idx, line := range m.lines { - parsedLine := strings.TrimLeft(strings.ToLower(line), " ") - // already enabled - if parsedLine == mod { - return true, idx - } - - // disabled, lets enable - if strings.HasPrefix(parsedLine, "#") && strings.TrimLeft(parsedLine, "# ") == mod { - return false, idx - } - } - - return false, -1 -} - -func (m *ModList) Save() error { - log.WithField("file", "ModList.txt").Debugf("saving ModList.txt") - - file, err := os.OpenFile(filepath.Join(m.dir, "ModList.txt"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) - if err != nil { - return err - } - defer file.Close() - - writer := bufio.NewWriter(file) - - for _, line := range m.lines { - if _, err = writer.WriteString(fmt.Sprintf("%s\n", line)); err != nil { - return err - } - } - if err = writer.Flush(); err != nil { - return err - } - - return nil -} diff --git a/pkg/api/auth.go b/pkg/api/auth.go deleted file mode 100644 index 75751d2..0000000 --- a/pkg/api/auth.go +++ /dev/null @@ -1,49 +0,0 @@ -package api - -import ( - "context" - "fmt" - "net/http" - "time" -) - -type AuthResult struct { - Token string `json:"token"` - Type PermissionType `json:"type"` - CreatedAt time.Time `json:"createdAt"` -} - -type credentialsDto struct { - Username string `json:"username"` - Password string `json:"password"` - Type PermissionType `json:"type"` -} - -type AuthService commonService - -func (s AuthService) Login(ctx context.Context, username string, password string, permission PermissionType) (*AuthResult, *http.Response, error) { - return s.authRequest(ctx, "login", username, password, permission) -} - -func (s AuthService) Register(ctx context.Context, username string, password string, permission PermissionType) (*AuthResult, *http.Response, error) { - return s.authRequest(ctx, "register", username, password, permission) -} - -func (s AuthService) authRequest(ctx context.Context, endpoint, username, password string, permission PermissionType) (*AuthResult, *http.Response, error) { - req, err := s.client.NewRequest(http.MethodPost, fmt.Sprintf("auth/%s", endpoint), &credentialsDto{ - Username: username, - Password: password, - Type: permission, - }) - if err != nil { - return nil, nil, err - } - - result := new(AuthResult) - res, err := s.client.Do(ctx, req, result) - if err != nil { - return nil, res, err - } - - return result, res, nil -} diff --git a/pkg/api/auth_test.go b/pkg/api/auth_test.go deleted file mode 100644 index 6c02d7d..0000000 --- a/pkg/api/auth_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package api - -import ( - "context" - "fmt" - "github.com/google/go-cmp/cmp" - "net/http" - "testing" - "time" -) - -func TestAuthService_Login(t *testing.T) { - client, mux, teardown := setup() - defer teardown() - - input := &credentialsDto{ - Username: "test", - Password: "test", - Type: PermissionTypePublish, - } - - mux.HandleFunc("/auth/login", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "POST") - testBodyJSON(t, r, input) - - fmt.Fprint(w, `{"token": "1234", "type": "Publish", "createdAt": "2022-05-03T12:00:00.000Z"}`) - }) - - ctx := context.Background() - result, _, err := client.Auth.Login(ctx, "test", "test", PermissionTypePublish) - if err != nil { - t.Errorf("Auth.Login returned error: %v", err) - } - - expected := &AuthResult{ - Token: "1234", - Type: PermissionTypePublish, - CreatedAt: time.Date(2022, 5, 3, 12, 00, 00, 00, time.UTC), - } - if !cmp.Equal(result, expected) { - t.Errorf("Auth.Login returned %+v, expected: %+v", result, expected) - } -} - -func TestAuthService_Register(t *testing.T) { - client, mux, teardown := setup() - defer teardown() - - input := &credentialsDto{ - Username: "test", - Password: "test", - Type: PermissionTypePublish, - } - - mux.HandleFunc("/auth/register", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "POST") - testBodyJSON(t, r, input) - - fmt.Fprint(w, `{"token": "1234", "type": "Publish", "createdAt": "2022-05-03T12:00:00.000Z"}`) - }) - - ctx := context.Background() - result, _, err := client.Auth.Register(ctx, "test", "test", PermissionTypePublish) - if err != nil { - t.Errorf("Auth.Register returned error: %v", err) - } - - expected := &AuthResult{ - Token: "1234", - Type: PermissionTypePublish, - CreatedAt: time.Date(2022, 5, 3, 12, 00, 00, 00, time.UTC), - } - if !cmp.Equal(result, expected) { - t.Errorf("Auth.Register returned %+v, expected: %+v", result, expected) - } -} diff --git a/pkg/api/client.go b/pkg/api/client.go deleted file mode 100644 index 99abe09..0000000 --- a/pkg/api/client.go +++ /dev/null @@ -1,151 +0,0 @@ -package api - -import ( - "bytes" - "context" - "encoding/json" - "io" - "io/ioutil" - "net/http" - "net/url" -) - -type Option func(c *Client) error - -func BaseURL(baseUrl string) Option { - return func(c *Client) error { - parsedUrl, err := url.Parse(baseUrl) - if err != nil { - return err - } - c.baseUrl = parsedUrl - return nil - } -} - -func RoundTrip(t http.RoundTripper) Option { - return func(c *Client) error { - c.client.Transport = t - return nil - } -} - -var defaultBaseUrl = "https://vumm.bf3reality.com/api/v1/" - -type Client struct { - baseUrl *url.URL - client *http.Client - - common commonService - - Auth *AuthService - Mods *ModsService -} - -func New(opts ...Option) (*Client, error) { - baseUrl, _ := url.Parse(defaultBaseUrl) - - client := &Client{ - baseUrl: baseUrl, - client: &http.Client{}, - } - - for _, option := range opts { - err := option(client) - if err != nil { - return nil, err - } - } - - client.common.client = client - client.Auth = (*AuthService)(&client.common) - client.Mods = (*ModsService)(&client.common) - - return client, nil -} - -func (c *Client) NewRequest(method, path string, body interface{}) (*http.Request, error) { - reqUrl, err := c.baseUrl.Parse(path) - if err != nil { - return nil, err - } - - var buf io.ReadWriter - if body != nil { - buf = &bytes.Buffer{} - err := json.NewEncoder(buf).Encode(body) - if err != nil { - return nil, err - } - } - - req, err := http.NewRequest(method, reqUrl.String(), buf) - if err != nil { - return nil, err - } - - if body != nil { - req.Header.Set("Content-Type", "application/json") - } - - return req, nil -} - -func (c *Client) DoRequest(ctx context.Context, req *http.Request) (*http.Response, error) { - req = req.WithContext(ctx) - - res, err := c.client.Do(req) - if err != nil { - select { - case <-ctx.Done(): - return nil, ctx.Err() - default: - return nil, err - } - } - - err = c.checkResponse(res) - return res, err -} - -func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*http.Response, error) { - res, err := c.DoRequest(ctx, req) - if err != nil { - return nil, err - } - defer res.Body.Close() - - switch v := v.(type) { - case nil: - case io.Writer: - _, err = io.Copy(v, res.Body) - default: - err = json.NewDecoder(res.Body).Decode(v) - } - - return res, err -} - -func (c *Client) checkResponse(res *http.Response) error { - // All statuses between 200 <-> 299 are ok - if c := res.StatusCode; 200 <= c && c <= 299 { - return nil - } - - resErr := &GenericError{Response: res} - data, err := ioutil.ReadAll(res.Body) - if err == nil && data != nil { - json.Unmarshal(data, resErr) - } - - switch res.StatusCode { - case http.StatusUnauthorized: - return (*UnauthorizedError)(resErr) - case http.StatusBadRequest: - return (*BadRequestError)(resErr) - case http.StatusConflict: - return (*ConflictError)(resErr) - default: - return resErr - } -} diff --git a/pkg/api/client_test.go b/pkg/api/client_test.go deleted file mode 100644 index 5fa15d5..0000000 --- a/pkg/api/client_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package api - -import ( - "encoding/json" - "github.com/google/go-cmp/cmp" - "net/http" - "net/http/httptest" - "reflect" - "testing" -) - -func setup() (client *Client, mux *http.ServeMux, teardown func()) { - mux = http.NewServeMux() - - server := httptest.NewServer(mux) - - client, _ = New(BaseURL(server.URL)) - - return client, mux, server.Close -} - -func testMethod(t *testing.T, r *http.Request, expectedMethod string) { - t.Helper() - if r.Method != expectedMethod { - t.Errorf("Request method: %v, expected %v", r.Method, expectedMethod) - } -} - -func testBodyJSON(t *testing.T, r *http.Request, expected interface{}) { - t.Helper() - - bodyType := reflect.TypeOf(expected) - bodyValue := reflect.New(bodyType.Elem()) - value := bodyValue.Interface() - - json.NewDecoder(r.Body).Decode(&value) - - if !cmp.Equal(value, expected) { - t.Errorf("Request body: %v, expected %v", value, expected) - } -} - -func TestBaseURL(t *testing.T) { - baseUrl := "https://vumm.com/api/v1/" - c, _ := New(BaseURL(baseUrl)) - - if c.baseUrl.String() != baseUrl { - t.Errorf("Base url: %v, expected: %v", c.baseUrl, baseUrl) - } -} - -func TestRoundTrip(t *testing.T) { - ts := &TokenAuthTransport{} - c, _ := New(RoundTrip(ts)) - - if !cmp.Equal(c.client.Transport, ts) { - t.Errorf("Round trip: %v, expected: %v", c.client.Transport, ts) - } -} diff --git a/pkg/api/client_transport.go b/pkg/api/client_transport.go deleted file mode 100644 index 50a4fab..0000000 --- a/pkg/api/client_transport.go +++ /dev/null @@ -1,21 +0,0 @@ -package api - -import "net/http" - -var _ http.RoundTripper = (*TokenAuthTransport)(nil) - -type TokenAuthTransport struct { - Token string -} - -func (t TokenAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) { - if t.Token != "" { - req.Header.Set("Authorization", t.Token) - } - - return http.DefaultTransport.RoundTrip(req) -} - -type commonService struct { - client *Client -} diff --git a/pkg/api/client_transport_test.go b/pkg/api/client_transport_test.go deleted file mode 100644 index 46cb7c5..0000000 --- a/pkg/api/client_transport_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package api - -import ( - "net/http" - "testing" -) - -func TestTokenAuthTransport_RoundTrip_NoToken(t *testing.T) { - ts := TokenAuthTransport{Token: ""} - - res, _ := http.NewRequest(http.MethodGet, "/ok", nil) - ts.RoundTrip(res) - - if _, exists := res.Header["Authorization"]; exists { - t.Errorf("Request should not to contain a Authorization header") - } -} - -func TestTokenAuthTransport_RoundTrip_Token(t *testing.T) { - expected := "1234" - ts := TokenAuthTransport{Token: expected} - - res, _ := http.NewRequest(http.MethodGet, "/ok", nil) - ts.RoundTrip(res) - - if value := res.Header.Get("Authorization"); value != expected { - t.Errorf("Authorization header: %v, expected: %v", value, expected) - } -} diff --git a/pkg/api/errors.go b/pkg/api/errors.go deleted file mode 100644 index c6a5d9c..0000000 --- a/pkg/api/errors.go +++ /dev/null @@ -1,95 +0,0 @@ -package api - -import ( - "encoding/json" - "errors" - "fmt" - "net/http" - "strings" -) - -var ( - ErrModVersionNotFound = errors.New("mod version was not found") -) - -type GenericError struct { - Response *http.Response - Message string `json:"message"` - Errors map[string][]string `json:"errors"` -} - -func (e GenericError) Error() string { - return fmt.Sprintf("%v %v: %d, %v %+v", e.Response.Request.Method, e.Response.Request.URL, e.Response.StatusCode, e.Message, e.Errors) -} - -type UnauthorizedError GenericError - -func (e *UnauthorizedError) Error() string { - return (*GenericError)(e).Error() -} - -type BadRequestError GenericError - -func (e *BadRequestError) Error() string { - return (*GenericError)(e).Error() -} - -type ConflictError GenericError - -func (e *ConflictError) Error() string { - return (*GenericError)(e).Error() -} - -type ValidationError struct { - GenericError - errors map[string][]string -} - -func (e ValidationError) GetKeyValidationErrors(key string) ([]string, bool) { - val, ok := e.errors[key] - return val, ok -} - -func (e ValidationError) GetValidationErrors() []string { - var errs []string - for _, valErrs := range e.errors { - errs = append(errs, valErrs...) - } - - return errs -} - -func (e *ValidationError) UnmarshalJSON(b []byte) error { - var raw map[string]interface{} - if err := json.Unmarshal(b, &raw); err != nil { - return err - } - - e.errors = map[string][]string{} - - if errors, ok := raw["errors"]; ok { - for key, val := range errors.(map[string]interface{}) { - var errs []string - for _, valErr := range val.([]interface{}) { - errs = append(errs, valErr.(string)) - } - e.errors[key] = errs - } - } - - return nil -} - -func (e ValidationError) Error() string { - if len(e.errors) == 0 { - return e.GenericError.Error() - } - - builder := strings.Builder{} - builder.WriteString(e.Message) - for _, err := range e.GetValidationErrors() { - builder.WriteString(fmt.Sprintf("\n\t- %s", err)) - } - - return builder.String() -} diff --git a/pkg/api/mods.go b/pkg/api/mods.go deleted file mode 100644 index 5f645e3..0000000 --- a/pkg/api/mods.go +++ /dev/null @@ -1,127 +0,0 @@ -package api - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "github.com/Masterminds/semver/v3" - "github.com/vumm/cli/internal/common" - "net/http" - "sort" -) - -type ModVersion struct { - Name string `json:"name"` - Description string `json:"description"` - Author string `json:"author"` - Version *semver.Version `json:"version"` - Dependencies map[string]string `json:"dependencies"` -} - -func (m ModVersion) String() string { - str, err := json.Marshal(m) - if err != nil { - panic(err) - } - - return string(str) -} - -// ModVersions is a collection of ModVersion instances and implements the sort -// interface based on the semver version inside it. -type ModVersions []ModVersion - -// Len returns the length of a collection. -func (c ModVersions) Len() int { - return len(c) -} - -// Less checks if one is greater (reverse) than the other based on Semver. -func (c ModVersions) Less(i, j int) bool { - return c[i].Version.GreaterThan(c[j].Version) -} - -func (c ModVersions) Swap(i, j int) { - c[i], c[j] = c[j], c[i] -} - -type Mod struct { - Name string `json:"name"` - Description string `json:"description"` - Author string `json:"author"` - Tags map[string]string `json:"tags"` - Versions map[string]ModVersion `json:"versions"` - - // sorted list of mod versions - versions ModVersions -} - -// GetVersionByTag tries to find the version by tag name -func (m Mod) GetVersionByTag(tag string) (ModVersion, error) { - tagVersion, ok := m.Tags[tag] - if !ok { - return ModVersion{}, ErrModVersionNotFound - } - - version, ok := m.Versions[tagVersion] - if !ok { - return ModVersion{}, ErrModVersionNotFound - } - return version, nil -} - -// GetLatestVersionByConstraints tries to find the latest version satisfying the constraints -func (m *Mod) GetLatestVersionByConstraints(constraints *common.SemverConstraints) (ModVersion, error) { - // If versions are not sorted yet, do that now - if m.versions == nil { - m.versions = make(ModVersions, 0, len(m.Versions)) - for _, version := range m.Versions { - m.versions = append(m.versions, version) - } - sort.Sort(m.versions) - } - - for _, modVersion := range m.versions { - if constraints.Check(modVersion.Version) { - return modVersion, nil - } - } - - return ModVersion{}, ErrModVersionNotFound -} - -type ModsService commonService - -// GetMod fetches a mod from the registry -func (s ModsService) GetMod(ctx context.Context, modName string) (*Mod, *http.Response, error) { - req, err := s.client.NewRequest(http.MethodGet, fmt.Sprintf("mods/%s", modName), nil) - if err != nil { - return nil, nil, err - } - - mod := new(Mod) - res, err := s.client.Do(ctx, req, &mod) - - if err != nil { - return nil, res, err - } - - return mod, res, nil -} - -// DownloadModArchive fetches a mods archive from the registry -func (s ModsService) DownloadModArchive(ctx context.Context, modName string, modVersion *semver.Version) (*bytes.Buffer, *http.Response, error) { - req, err := s.client.NewRequest(http.MethodGet, fmt.Sprintf("mods/%s/%s/download", modName, modVersion), nil) - if err != nil { - return nil, nil, err - } - - buf := new(bytes.Buffer) - res, err := s.client.Do(ctx, req, buf) - if err != nil { - return nil, res, err - } - - return buf, res, nil -} diff --git a/pkg/api/mods_permissions.go b/pkg/api/mods_permissions.go deleted file mode 100644 index 8ff918c..0000000 --- a/pkg/api/mods_permissions.go +++ /dev/null @@ -1,62 +0,0 @@ -package api - -import ( - "context" - "fmt" - "net/http" -) - -type PermissionType string - -const ( - PermissionTypeReadonly PermissionType = "Readonly" - PermissionTypePublish = "Publish" -) - -type grantPermissionDto struct { - Username string `json:"username"` - Permission PermissionType `json:"permission,omitempty"` - Tag string `json:"tag"` -} - -func PermissionTypeFromString(in string) (permission PermissionType, err error) { - if in == "" { - return PermissionTypeReadonly, nil - } - - switch in { - case "readonly": - permission = PermissionTypeReadonly - case "publish": - permission = PermissionTypePublish - default: - err = fmt.Errorf("%s is not a valid permission type", in) - } - - return -} - -func (s ModsService) GrantModPermissions(ctx context.Context, modName string, modTag string, username string, permission PermissionType) (*http.Response, error) { - req, err := s.client.NewRequest(http.MethodPost, fmt.Sprintf("mods/%s/grant", modName), &grantPermissionDto{ - Tag: modTag, - Username: username, - Permission: permission, - }) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -func (s ModsService) RevokeModPermissions(ctx context.Context, modName string, modTag string, username string) (*http.Response, error) { - req, err := s.client.NewRequest(http.MethodPost, fmt.Sprintf("mods/%s/revoke", modName), &grantPermissionDto{ - Tag: modTag, - Username: username, - }) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} diff --git a/pkg/api/mods_permissions_test.go b/pkg/api/mods_permissions_test.go deleted file mode 100644 index 28c25e8..0000000 --- a/pkg/api/mods_permissions_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package api - -import ( - "context" - "fmt" - "net/http" - "testing" -) - -func TestModsService_GrantModPermissions(t *testing.T) { - client, mux, teardown := setup() - defer teardown() - - input := &grantPermissionDto{ - Username: "test", - Permission: PermissionTypeReadonly, - Tag: "qa", - } - - mux.HandleFunc("/mods/realitymod/grant", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "POST") - testBodyJSON(t, r, input) - - fmt.Fprint(w, `{"message": "OK"}`) - }) - - ctx := context.Background() - _, err := client.Mods.GrantModPermissions(ctx, "realitymod", "qa", "test", PermissionTypeReadonly) - if err != nil { - t.Errorf("Mods.GrantModPermissions returned error: %v", err) - } -} - -func TestModsService_RevokeModPermissions(t *testing.T) { - client, mux, teardown := setup() - defer teardown() - - input := &grantPermissionDto{ - Username: "test", - Tag: "qa", - } - - mux.HandleFunc("/mods/realitymod/revoke", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "POST") - testBodyJSON(t, r, input) - - fmt.Fprint(w, `{"message": "OK"}`) - }) - - ctx := context.Background() - _, err := client.Mods.RevokeModPermissions(ctx, "realitymod", "qa", "test") - if err != nil { - t.Errorf("Mods.RevokeModPermissions returned error: %v", err) - } -} diff --git a/pkg/api/mods_publish.go b/pkg/api/mods_publish.go deleted file mode 100644 index 1be3ff1..0000000 --- a/pkg/api/mods_publish.go +++ /dev/null @@ -1,70 +0,0 @@ -package api - -import ( - "context" - "encoding/base64" - "fmt" - "github.com/Masterminds/semver" - "github.com/vumm/cli/internal/common" - "io" - "io/ioutil" - "net/http" -) - -type modArchiveDto struct { - Data string `json:"data"` - Length int `json:"length"` - ContentType string `json:"content_type"` -} - -type publishModDto struct { - common.ModMetadata - Tag string `json:"tag"` - Archive modArchiveDto `json:"archive"` -} - -func (s ModsService) PublishMod(ctx context.Context, metadata common.ModMetadata, tag string, reader io.Reader) (*http.Response, error) { - archive, err := s.encodeModArchive(reader) - if err != nil { - return nil, fmt.Errorf("failed to encode archive: %v", err) - } - - publishUrl := fmt.Sprintf("mods/%s/%s", metadata.Name, metadata.Version) - - req, err := s.client.NewRequest(http.MethodPut, publishUrl, &publishModDto{ - ModMetadata: metadata, - Tag: tag, - Archive: archive, - }) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -func (s ModsService) UnpublishModVersion(ctx context.Context, modName string, modVersion *semver.Version) (*http.Response, error) { - req, err := s.client.NewRequest(http.MethodDelete, fmt.Sprintf("mods/%s/%s", modName, modVersion), nil) - if err != nil { - return nil, err - } - - return s.client.Do(ctx, req, nil) -} - -func (s ModsService) encodeModArchive(reader io.Reader) (modArchiveDto, error) { - buf, err := ioutil.ReadAll(reader) - if err != nil { - return modArchiveDto{}, err - } - - length := len(buf) - contentType := http.DetectContentType(buf) - data := base64.StdEncoding.EncodeToString(buf) - - return modArchiveDto{ - Data: data, - Length: length, - ContentType: contentType, - }, nil -} diff --git a/pkg/api/mods_publish_test.go b/pkg/api/mods_publish_test.go deleted file mode 100644 index bf7bdf7..0000000 --- a/pkg/api/mods_publish_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package api - -import ( - "bytes" - "context" - "fmt" - "github.com/Masterminds/semver" - "github.com/vumm/cli/internal/common" - "io" - "net/http" - "os" - "testing" -) - -func TestModsService_encodeModArchive(t *testing.T) { - service := ModsService{} - - file, err := os.Open("testdata/0.1.0.tgz") - if err != nil { - t.Errorf("Failed to open test file") - } - defer file.Close() - - archive, err := service.encodeModArchive(file) - if err != nil { - t.Errorf("Mods.encodeModArchive returned error: %v", err) - } - - if archive.Data == "" { - t.Errorf("Archive data is empty") - } - - if archive.ContentType != "application/x-gzip" { - t.Errorf("Archive content type: %v, expected application/x-gzip", archive.ContentType) - } -} - -func TestModsService_PublishMod(t *testing.T) { - client, mux, teardown := setup() - defer teardown() - - metadata := common.ModMetadata{ - Name: "realitymod", - Version: semver.MustParse("0.1.0"), - Dependencies: nil, - } - - file, err := os.Open("testdata/0.1.0.tgz") - if err != nil { - t.Errorf("Failed to open test file") - } - defer file.Close() - var buf bytes.Buffer - archive, _ := client.Mods.encodeModArchive(io.TeeReader(file, &buf)) - - input := &publishModDto{ - ModMetadata: metadata, - Tag: "qa", - Archive: archive, - } - - mux.HandleFunc("/mods/realitymod/0.1.0", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - testBodyJSON(t, r, input) - - fmt.Fprint(w, `{"message": "OK"}`) - }) - - ctx := context.Background() - _, err = client.Mods.PublishMod(ctx, metadata, "qa", &buf) - if err != nil { - t.Errorf("Mods.PublishMod returned error: %v", err) - } -} - -func TestModsService_UnpublishModVersion(t *testing.T) { - client, mux, teardown := setup() - defer teardown() - - mux.HandleFunc("/mods/realitymod/0.1.0", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - - fmt.Fprint(w, `{"message": "OK"}`) - }) - - ctx := context.Background() - _, err := client.Mods.UnpublishModVersion(ctx, "realitymod", semver.MustParse("0.1.0")) - if err != nil { - t.Errorf("Mods.UnpublishModVersion returned error: %v", err) - } -} diff --git a/pkg/api/mods_test.go b/pkg/api/mods_test.go deleted file mode 100644 index cceeb0b..0000000 --- a/pkg/api/mods_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package api - -import ( - "bytes" - "context" - "fmt" - "github.com/Masterminds/semver/v3" - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "net/http" - "testing" -) - -func TestModsService_GetMod(t *testing.T) { - client, mux, teardown := setup() - defer teardown() - - mux.HandleFunc("/mods/realitymod", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - - fmt.Fprint(w, ` -{ - "name": "realitymod", - "description": "Da best mod", - "author": "author", - "tags": { - "latest": "0.1.0" - }, - "versions": { - "0.1.0": { - "name": "realitymod", - "description": "Da best mod", - "author": "author", - "version": "0.1.0", - "dependencies": { - "vemanager": ">=0.1.0" - } - } - } -}`) - }) - - ctx := context.Background() - result, _, err := client.Mods.GetMod(ctx, "realitymod") - if err != nil { - t.Errorf("Mods.GetMod returned error: %v", err) - } - - expected := &Mod{ - Name: "realitymod", - Description: "Da best mod", - Author: "author", - Tags: map[string]string{"latest": "0.1.0"}, - Versions: map[string]ModVersion{"0.1.0": { - Name: "realitymod", - Description: "Da best mod", - Author: "author", - Version: semver.MustParse("0.1.0"), - Dependencies: map[string]string{"vemanager": ">=0.1.0"}, - }}, - } - if !cmp.Equal(result, expected, cmpopts.IgnoreUnexported(Mod{})) { - t.Errorf("Mods.GetMod returned %+v, expected: %+v", result, expected) - } -} - -func TestModsService_DownloadModArchive(t *testing.T) { - client, mux, teardown := setup() - defer teardown() - - mux.HandleFunc("/mods/realitymod/0.1.0/download", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - - fmt.Fprint(w, "test") - }) - - ctx := context.Background() - result, _, err := client.Mods.DownloadModArchive(ctx, "realitymod", semver.MustParse("0.1.0")) - if err != nil { - t.Errorf("Mods.DownloadModArchive returned error: %v", err) - } - - expected := bytes.NewBufferString("test") - if !cmp.Equal(result.String(), expected.String()) { - t.Errorf("Mods.DownloadModArchive returned %+v, expected: %+v", result.String(), expected.String()) - } -} diff --git a/pkg/api/testdata/0.1.0.tgz b/pkg/api/testdata/0.1.0.tgz deleted file mode 100644 index eaccb38..0000000 Binary files a/pkg/api/testdata/0.1.0.tgz and /dev/null differ diff --git a/pkg/ignorer/ignore.go b/pkg/ignorer/ignore.go deleted file mode 100644 index cbb2380..0000000 --- a/pkg/ignorer/ignore.go +++ /dev/null @@ -1,145 +0,0 @@ -package ignorer - -import ( - "io/ioutil" - "os" - "regexp" - "strings" -) - -type Ignorer interface { - Matches(filePath string) bool -} - -type noopIgnorer struct { -} - -func (noopIgnorer) Matches(filePath string) bool { - return false -} - -func NOOP() Ignorer { - return &noopIgnorer{} -} - -type ignorePattern struct { - regex *regexp.Regexp - negate bool -} - -type patternIgnorer struct { - patterns []*ignorePattern -} - -func parseRegexFromLine(line string) (*regexp.Regexp, bool) { - line = strings.TrimRight(line, "\r") - - // Strip comments [Rule 2] - if strings.HasPrefix(line, "#") { - return nil, false - } - - // Trim string [Rule 3] - line = strings.Trim(line, " ") - - if line == "" { - return nil, false - } - - // Handle [Rule 4] which negates the match for patterns leading with "!" - negatePattern := false - if line[0] == '!' { - negatePattern = true - line = line[1:] - } - - // Handle [Rule 2, 4], when # or ! is escaped with a \ - // Handle [Rule 4] once we tag negatePattern, strip the leading ! char - if regexp.MustCompile(`^(\#|\!)`).MatchString(line) { - line = line[1:] - } - - // Prepend with a / - if regexp.MustCompile(`([^\/+]/.*\*\.)`).MatchString(line) && line[0] != '/' { - line = "/" + line - } - - // Escape the "." char - line = regexp.MustCompile(`\.`).ReplaceAllString(line, `\.`) - - magicStar := "#$~" - - // Handle "/**/" usage - if strings.HasPrefix(line, "/**/") { - line = line[1:] - } - line = regexp.MustCompile(`/\*\*/`).ReplaceAllString(line, `(/|/.+/)`) - line = regexp.MustCompile(`\*\*/`).ReplaceAllString(line, `(|.`+magicStar+`/)`) - line = regexp.MustCompile(`/\*\*`).ReplaceAllString(line, `(|/.`+magicStar+`)`) - - // Handle escaping the "*" char - line = regexp.MustCompile(`\\\*`).ReplaceAllString(line, `\`+magicStar) - line = regexp.MustCompile(`\*`).ReplaceAllString(line, `([^/]*)`) - - // Handle escaping the "?" char - line = strings.Replace(line, "?", `\?`, -1) - - line = strings.Replace(line, magicStar, "*", -1) - - // Temporary regex - var expr = "" - if strings.HasSuffix(line, "/") { - expr = line + "(|.*)$" - } else { - expr = line + "(|/.*)$" - } - if strings.HasPrefix(expr, "/") { - expr = "^(|/)" + expr[1:] - } else { - expr = "^(|.*/)" + expr - } - pattern, _ := regexp.Compile(expr) - - return pattern, negatePattern -} - -func CompileIgnorerFromLines(lines ...string) Ignorer { - ignorer := &patternIgnorer{} - - for _, line := range lines { - regex, negate := parseRegexFromLine(line) - if regex != nil { - pattern := &ignorePattern{regex, negate} - ignorer.patterns = append(ignorer.patterns, pattern) - } - } - - return ignorer -} - -func CompileIgnorerFromFile(filePath string, additionalLines ...string) (Ignorer, error) { - bs, err := ioutil.ReadFile(filePath) - if err != nil { - return nil, err - } - - lines := append(strings.Split(string(bs), "\n"), additionalLines...) - return CompileIgnorerFromLines(lines...), nil -} - -func (ignorer patternIgnorer) Matches(filePath string) bool { - filePath = strings.ReplaceAll(filePath, string(os.PathSeparator), "/") - - matchesPath := false - for _, pattern := range ignorer.patterns { - if pattern.regex.MatchString(filePath) { - if !pattern.negate { - matchesPath = true - } else if matchesPath { - matchesPath = false - } - } - } - - return matchesPath -} diff --git a/pkg/tar/packager.go b/pkg/tar/packager.go deleted file mode 100644 index b89d562..0000000 --- a/pkg/tar/packager.go +++ /dev/null @@ -1,48 +0,0 @@ -package tar - -import ( - "archive/tar" - "compress/gzip" - "fmt" - "io" -) - -type Packager interface { - SetFileFilter(filter FileFilter) - Compress(src string, writer io.Writer) error - Decompress(reader io.Reader, dest string) error -} - -func NewPackager() Packager { - return &tarGzPackager{} -} - -type tarGzPackager struct { - filter FileFilter -} - -func (p *tarGzPackager) SetFileFilter(filter FileFilter) { - p.filter = filter -} - -func (p tarGzPackager) Compress(src string, writer io.Writer) error { - gzWriter := gzip.NewWriter(writer) - defer gzWriter.Close() - - tarWriter := tar.NewWriter(gzWriter) - defer tarWriter.Close() - - return tarballToWriter(src, tarWriter, p.filter) -} - -func (p tarGzPackager) Decompress(reader io.Reader, dest string) error { - gzReader, err := gzip.NewReader(reader) - if err != nil { - return fmt.Errorf("failed to decompress archive: %v", err) - } - defer gzReader.Close() - - tarReader := tar.NewReader(gzReader) - - return untarFromReader(tarReader, dest) -} diff --git a/pkg/tar/tar.go b/pkg/tar/tar.go deleted file mode 100644 index b3645c9..0000000 --- a/pkg/tar/tar.go +++ /dev/null @@ -1,151 +0,0 @@ -package tar - -import ( - "archive/tar" - "fmt" - "io" - "os" - "path/filepath" - "runtime" - "strings" -) - -type FileFilter func(filePath string) bool - -func tarballToWriter(src string, writer *tar.Writer, filter FileFilter) error { - //srcInfo, err := os.Stat(src) - //if err != nil { - // return fmt.Errorf("%s: stat: %v", src, err) - //} - - //var baseDir string - //if srcInfo.IsDir() { - // baseDir = filepath.Base(src) - //} - - return filepath.Walk(src, func(path string, info os.FileInfo, err error) error { - if err != nil { - return fmt.Errorf("error walking to %s: %v", path, err) - } - - // Ignore root directory - if path == src { - return nil - } - - header, err := tar.FileInfoHeader(info, path) - if err != nil { - return fmt.Errorf("%s: making header: %v", path, err) - } - - // Rewrite baseDir - //if baseDir != "" { - header.Name = strings.TrimPrefix(path, src+string(filepath.Separator)) - //} - - if info.IsDir() { - header.Name += "/" - } - - if filter != nil && !filter(header.Name) { - return nil - } - - err = writer.WriteHeader(header) - if err != nil { - return fmt.Errorf("%s: writing header: %v", path, err) - } - - // We done, nothing left to do for directories - if info.IsDir() { - return nil - } - - if header.Typeflag == tar.TypeReg { - file, err := os.Open(path) - if err != nil { - return fmt.Errorf("%s: open: %v", path, err) - } - defer file.Close() - - _, err = io.CopyN(writer, file, info.Size()) - if err != nil && err != io.EOF { - return fmt.Errorf("%s: copying contents: %v", path, err) - } - } - return nil - }) -} - -func untarFromReader(reader *tar.Reader, dest string) error { - for { - header, err := reader.Next() - if err == io.EOF { - break - } else if err != nil { - return err - } - - switch header.Typeflag { - case tar.TypeDir: - err = mkdir(filepath.Join(dest, header.Name)) - case tar.TypeReg: - err = writeNewFile(filepath.Join(dest, header.Name), reader, header.FileInfo().Mode()) - case tar.TypeSymlink: - err = writeNewSymbolicLink(filepath.Join(dest, header.Name), header.Linkname) - default: - return fmt.Errorf("%s: unknown type flag: %c", header.Name, header.Typeflag) - } - - if err != nil { - return err - } - } - return nil -} - -func writeNewFile(filePath string, in io.Reader, fm os.FileMode) error { - err := os.MkdirAll(filepath.Dir(filePath), 0755) - if err != nil { - return fmt.Errorf("%s: making directory for file: %v", filePath, err) - } - - out, err := os.Create(filePath) - if err != nil { - return fmt.Errorf("%s: creating new file: %v", filePath, err) - } - defer out.Close() - - err = out.Chmod(fm) - if err != nil && runtime.GOOS != "windows" { - return fmt.Errorf("%s: changing file mode: %v", filePath, err) - } - - _, err = io.Copy(out, in) - if err != nil { - return fmt.Errorf("%s: writing file: %v", filePath, err) - } - return nil -} - -func writeNewSymbolicLink(filePath string, target string) error { - err := os.MkdirAll(filepath.Dir(filePath), 0755) - if err != nil { - return fmt.Errorf("%s: making directory for file: %v", filePath, err) - } - - err = os.Symlink(target, filePath) - if err != nil { - return fmt.Errorf("%s: making symbolic link for: %v", filePath, err) - } - - return nil -} - -func mkdir(dirPath string) error { - err := os.MkdirAll(dirPath, 0755) - if err != nil { - return fmt.Errorf("%s: making directory: %v", dirPath, err) - } - return nil -} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b1d8bd6 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,6 @@ +use vumm_cli; + +// Wrapper Program +fn main() { + vumm_cli::run_cli(); +} diff --git a/vumm_api/Cargo.toml b/vumm_api/Cargo.toml new file mode 100644 index 0000000..c06d49f --- /dev/null +++ b/vumm_api/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "vumm_api" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +flate2 = "1.0" +futures = "0.3" +reqwest = { version = "0.11", features = ["json", "stream"] } +semver = { version = "1.0", features = ["serde"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +tar = "0.4" +thiserror = "1.0" +tokio = "1.35" diff --git a/vumm_api/src/lib.rs b/vumm_api/src/lib.rs new file mode 100644 index 0000000..6ca7bfd --- /dev/null +++ b/vumm_api/src/lib.rs @@ -0,0 +1,113 @@ +pub mod mods; + +use serde::de::DeserializeOwned; +use serde_json::Value; + +use crate::mods::ModsEndpoint; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("bad request")] + BadRequest(reqwest::Response), + + #[error("unauthorized")] + Unauthorized(reqwest::Response), + + #[error("forbidden")] + Forbidden(reqwest::Response), + + #[error("not found")] + NotFound(reqwest::Response), + + #[error("status code {}", reqwest::Response::status(.0))] + Unknown(reqwest::Response), + + #[error("failed to process request: {0}")] + Internal(#[from] reqwest::Error), +} + +pub type ClientResult = Result; + +pub struct Client { + http_client: reqwest::Client, + base_url: String, + bearer_token: Option, +} + +impl Client { + pub fn new() -> Self { + Self { + http_client: reqwest::Client::new(), + base_url: String::from("https://vumm.bf3reality.com/api/v1"), + bearer_token: None, + } + } + + pub fn mods(&self) -> ModsEndpoint { + ModsEndpoint { client: self } + } + + pub fn set_bearer_token(&mut self, token: String) { + self.bearer_token = Some(token); + } + + pub async fn get(&self, path: String) -> ClientResult { + self.request(reqwest::Method::GET, path, |req| req).await + } + + pub async fn post(&self, path: String, body: &Value) -> ClientResult { + self.request(reqwest::Method::POST, path, |req| req.json(body)) + .await + } + + pub async fn put(&self, path: String, body: &Value) -> ClientResult { + self.request(reqwest::Method::PUT, path, |req| req.json(body)) + .await + } + + pub async fn delete(&self, path: String, body: &Value) -> ClientResult { + self.request(reqwest::Method::DELETE, path, |req| req.json(body)) + .await + } + + async fn request( + &self, + method: reqwest::Method, + path: String, + request_builder: B, + ) -> ClientResult + where + B: FnOnce(reqwest::RequestBuilder) -> reqwest::RequestBuilder, + { + let url = format!("{}{}", self.base_url, path); + let mut request = self.http_client.request(method.clone(), url); + + if let Some(token) = &self.bearer_token { + request = request.header("Authorization", token); + } + + request = request_builder(request); + + let response = request.send().await?; + + if response.status().is_success() { + Ok(response) + } else { + Err(match response.status() { + // TODO: handle validation errors + reqwest::StatusCode::BAD_REQUEST => Error::BadRequest(response), + reqwest::StatusCode::UNAUTHORIZED => Error::Unauthorized(response), + reqwest::StatusCode::FORBIDDEN => Error::Forbidden(response), + reqwest::StatusCode::NOT_FOUND => Error::NotFound(response), + _ => Error::Unknown(response), + }) + } + } + + async fn parse_json_response( + &self, + response: reqwest::Response, + ) -> ClientResult { + response.json::().await.map_err(Into::into) + } +} \ No newline at end of file diff --git a/vumm_api/src/mods.rs b/vumm_api/src/mods.rs new file mode 100644 index 0000000..7759c67 --- /dev/null +++ b/vumm_api/src/mods.rs @@ -0,0 +1,275 @@ +use std::{collections::HashMap, fmt, io::Cursor}; + +use flate2::read::GzDecoder; +use semver::{Version, VersionReq}; +use serde::Deserialize; +use tar::Archive; + +use crate::{Client, ClientResult}; + +#[derive(Deserialize, Debug, Clone)] +pub struct Mod { + pub name: String, + pub description: Option, + pub author: Option, + pub tags: HashMap, + pub versions: HashMap, +} + +#[derive(Deserialize, Debug, Clone)] +pub struct ModVersion { + pub name: String, + pub description: Option, + pub author: Option, + pub version: Version, + pub dependencies: Option>, +} + +impl Mod { + pub fn get_version_by_tag(&self, tag: &str) -> Option { + let tag_version = self.tags.get(tag)?; + + self.versions.get(tag_version).cloned() + } + + pub fn get_version_by_constraint(&self, constraint: &VersionReq) -> Option { + let mut versions = self.versions.values().collect::>(); + + versions.sort_by(|a, b| b.version.cmp(&a.version)); + + for version in versions { + if constraint.matches(&version.version) { + return Some(version.clone()); + } + } + + return None; + } + + pub fn get_last_versions(&self, max_count: usize) -> Mod { + let mut versions: Vec<(&String, &ModVersion)> = self.versions.iter().collect(); + versions.sort_by(|a, b| b.1.version.cmp(&a.1.version)); + versions.truncate(max_count); + + let new_versions: HashMap = versions + .into_iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(); + let mut mod_clone = self.clone(); + mod_clone.versions = new_versions; + + mod_clone + } +} + +struct UnderlinedText(String); + +impl fmt::Display for UnderlinedText { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let start_underline = "\x1B[4m"; + let reset_formatting = "\x1B[0m"; + + write!(f, "{}{}{}", start_underline, self.0, reset_formatting) + } +} + +impl fmt::Display for ModVersion { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.version.pre.len() > 0 { + true => { + write!( + f, + "{}\n", + UnderlinedText(format!( + "{}.{}.{}-{}", + self.version.major, + self.version.minor, + self.version.patch, + self.version.pre + )) + )?; + } + false => { + write!( + f, + "{}\n", + UnderlinedText(format!( + "{}.{}.{}", + self.version.major, self.version.minor, self.version.patch + )) + )?; + } + } + + match &self.dependencies { + Some(dependencies) if !dependencies.is_empty() => { + write!(f, "Mod Dependencies:\n")?; + for (dep, version_req) in dependencies { + // Adjust the format as per the structure of VersionReq + write!(f, "- {}: {}\n", dep, version_req)?; + } + } + _ => write!(f, "No dependencies.")?, + } + + Ok(()) + } +} + +impl fmt::Display for Mod { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "Mod Name: {}", self.name)?; + if let Some(description) = &self.description { + writeln!(f, "Description: {}", description)?; + } + if let Some(author) = &self.author { + writeln!(f, "Author: {}", author)?; + } + writeln!(f, "Tags:")?; + for (tag, version) in &self.tags { + writeln!(f, "- {}: {}", tag, version)?; + } + writeln!(f, "Latest Versions:")?; + for (_version_number, mod_version) in &self.versions { + writeln!(f, "{}", mod_version)?; + } + Ok(()) + } +} + +pub struct ModsEndpoint<'a> { + pub client: &'a Client, +} + +impl ModsEndpoint<'_> { + /// Get a mod by it's name + /// # Example + /// + /// ```no_run + /// use vumm_api::Client; + /// + /// let client = Client::new(); + /// let mod_name = String::from("mapeditor"); + /// + /// let mod_response = client.mods().get(mod_name); + /// ``` + /// + /// # Arguments + /// + /// `mod_name` - The name of the mod to get + pub async fn get(&self, mod_name: String) -> ClientResult { + let path = format!("/mods/{}", mod_name); + + return self + .client + .parse_json_response::(self.client.get(path).await?) + .await; + } + + pub async fn get_version( + &self, + mod_name: String, + mod_version: String, + ) -> ClientResult { + let path = format!("/mods/{}/{}", mod_name, mod_version); + + return self + .client + .parse_json_response::(self.client.get(path).await?) + .await; + } + + pub async fn download_version( + &self, + mod_name: String, + mod_version: String, + ) -> ClientResult>>>> { + let path = format!("/mods/{}/{}/download", mod_name, mod_version); + + let res = self.client.get(path).await?; + + let bytes = res.bytes().await?.to_vec(); + + // Create a Cursor to read the downloaded bytes + let cursor = Cursor::new(bytes); + + // Open the gzipped tar archive + let decoder = GzDecoder::new(cursor); + let archive = Archive::new(decoder); + + return Ok(archive); + } +} + +#[cfg(test)] + +mod tests { + use super::*; + + #[test] + fn test_mod_get_version_by_tag() { + let mod_json = r#" + { + "name": "mapeditor", + "description": "A map editor for Voxel Universe", + "author": "Voxel Universe", + "tags": { + "latest": "0.1.0" + }, + "versions": { + "0.1.0": { + "name": "mapeditor", + "description": "A map editor for Voxel Universe", + "author": "Voxel Universe", + "version": "0.1.0", + "dependencies": {} + } + } + } + "#; + + let mod_obj: Mod = serde_json::from_str(mod_json).unwrap(); + + let version = mod_obj.get_version_by_tag("latest").unwrap(); + + assert_eq!(version.version, Version::parse("0.1.0").unwrap()); + } + + #[test] + fn test_mod_get_version_by_constraint() { + let mod_json = r#" + { + "name": "mapeditor", + "description": "A map editor for Voxel Universe", + "author": "Voxel Universe", + "tags": { + "latest": "0.1.0" + }, + "versions": { + "0.1.0": { + "name": "mapeditor", + "description": "A map editor for Voxel Universe", + "author": "Voxel Universe", + "version": "0.1.0", + "dependencies": {} + }, + "0.2.0": { + "name": "mapeditor", + "description": "A map editor for Voxel Universe", + "author": "Voxel Universe", + "version": "0.2.0", + "dependencies": {} + } + } + } + "#; + + let mod_obj: Mod = serde_json::from_str(mod_json).unwrap(); + + let version = mod_obj + .get_version_by_constraint(&VersionReq::parse(">= 0.2.0").unwrap()) + .unwrap(); + + assert_eq!(version.version, Version::parse("0.2.0").unwrap()); + } +} diff --git a/vumm_cli/Cargo.toml b/vumm_cli/Cargo.toml new file mode 100644 index 0000000..cf3d810 --- /dev/null +++ b/vumm_cli/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "vumm_cli" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tokio = { version = "1.35", features = ["full"] } +clap = { version = "4.4", features = ["derive"] } +semver = "1.0" +regex = "1.10" + +vumm_api = { path = "../vumm_api" } +vumm_installer = { path = "../vumm_installer" } diff --git a/vumm_cli/src/commands/get_info.rs b/vumm_cli/src/commands/get_info.rs new file mode 100644 index 0000000..252956a --- /dev/null +++ b/vumm_cli/src/commands/get_info.rs @@ -0,0 +1,71 @@ +use clap::Args; +use regex::Regex; +use semver::VersionReq; +use vumm_api::{Client, Error}; + +const SHOW_LAST_VERSION_COUNT: usize = 3; + +#[derive(Args)] +#[command( + about = "Get information about a specific mod", + arg_required_else_help = true +)] +pub struct ModInfo { + #[arg(help = "Name of the mod OR name@version of mod", required = true)] + mod_name: String, + #[arg(help = "Version/Tag of the mod OR Version comparator [e.g. '<0.5'] (optional)")] + mod_version: Option, +} + +impl ModInfo { + pub async fn run(&mut self) { + let client = Client::new(); + + let re = Regex::new(r"^(\w+)@(\d+\.\d+\.\d+)$").unwrap(); + if let Some(captures) = re.captures(self.mod_name.clone().as_str()) { + let mod_name_part = &captures[1]; + let version_part = &captures[2]; + self.mod_name = mod_name_part.to_owned(); + self.mod_version = Some(version_part.to_owned()); + } + + let mod_ = match client.mods().get(self.mod_name.clone()).await { + Ok(returned_mod) => returned_mod, + Err(Error::NotFound(response)) => { + println!("Mod not found: {}", response.status()); + return; + } + Err(e) => { + println!("Error retrieving mod: {}", e); + return; + } + }; + + if let Some(mod_version) = &self.mod_version { + match VersionReq::parse(mod_version) { + Ok(version_req) => { + // VersionConstraint provided + if let Some(mod_version) = mod_.get_version_by_constraint(&version_req) { + println!("Found matching version: {}", mod_version); + } else { + println!("No version found matching the provided constraint."); + } + } + Err(_) => { + // Invalid VersionConstraint treat as a tag + if let Some(mod_version) = mod_.get_version_by_tag(mod_version) { + println!("Found version by tag: {}", mod_version); + } else { + println!("No version found with the provided tag."); + } + } + } + } else { + // If no specific version requirement or tag is provided, simply print the mod + println!( + "Mod found: {}", + mod_.get_last_versions(SHOW_LAST_VERSION_COUNT) + ); + } + } +} diff --git a/vumm_cli/src/commands/mod.rs b/vumm_cli/src/commands/mod.rs new file mode 100644 index 0000000..c0829cc --- /dev/null +++ b/vumm_cli/src/commands/mod.rs @@ -0,0 +1 @@ +pub mod get_info; \ No newline at end of file diff --git a/vumm_cli/src/lib.rs b/vumm_cli/src/lib.rs new file mode 100644 index 0000000..778ec2e --- /dev/null +++ b/vumm_cli/src/lib.rs @@ -0,0 +1,26 @@ +use clap::{Parser, Subcommand}; + +mod commands; + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +#[command(propagate_version = true)] +struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +#[clap(version = env!("CARGO_PKG_VERSION"), author = env!("CARGO_PKG_AUTHORS"), about = env!("CARGO_PKG_DESCRIPTION"))] +enum Commands { + Info(commands::get_info::ModInfo), +} + +#[tokio::main] +pub async fn run_cli() { + let cli: Cli = Cli::parse(); + + match cli.command { + Commands::Info(mut cmd) => cmd.run().await, + } +} diff --git a/vumm_installer/Cargo.toml b/vumm_installer/Cargo.toml new file mode 100644 index 0000000..2e5bfd6 --- /dev/null +++ b/vumm_installer/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "vumm_installer" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0" +semver = "1.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +thiserror = "1.0" +tokio = { version = "1.35", features = ["full"] } +vumm_api = { path = "../vumm_api" } diff --git a/vumm_installer/src/dependency_resolver.rs b/vumm_installer/src/dependency_resolver.rs new file mode 100644 index 0000000..35c5ee5 --- /dev/null +++ b/vumm_installer/src/dependency_resolver.rs @@ -0,0 +1,140 @@ +use std::collections::{HashMap, VecDeque}; + +use vumm_api::{mods::ModVersion, Client}; + +use super::lock::{LockFile, LockedMod}; +use super::ModVersionConstraint; + +#[derive(thiserror::Error, Debug)] +pub enum DependencyResolverError { + #[error("Mod not found: {0}")] + ModNotFound(String), + + #[error("Insufficient permissions to access mod: {0}")] + ModNoAccess(String), + + #[error("Mod version not found: {0}@{1}")] + ModVersionNotFound(String, String), + + #[error(transparent)] + Other(#[from] anyhow::Error), +} + +pub struct DependencyResolver { + api_client: Client, +} + +impl DependencyResolver { + pub fn new(api_client: Client) -> DependencyResolver { + DependencyResolver { + api_client: api_client, + } + } + + pub async fn resolve_dependencies( + &self, + mod_name: String, + mod_version: String, + ) -> Result { + let mut unresolved = VecDeque::new(); + let mut lock_file = LockFile { + mods: HashMap::new(), + }; + + unresolved.push_back(ModVersionConstraint::new(mod_name, mod_version)); + + while let Some(constraint) = unresolved.pop_front() { + // Check if installed mod matches version constraint + // if let Some(installed) = self.lock.get(*name) { + // if let Some(constraint_version) = &constraint.version { + // if !constraint_version.matches(&installed.version) { + // println!("Version mismatch"); + // continue; + // } + // } + // } + + println!("Resolving dependency constraint {}", constraint); + + let resolved_version = self.resolve_dependency_version(&constraint).await?; + + println!("Resolved version: {:?}", resolved_version); + + // TODO: Should I check if the mod was already added? + + lock_file.mods.insert( + constraint.name.to_string(), + LockedMod { + name: constraint.name.to_string(), + version: resolved_version.version.clone(), + dependencies: resolved_version.dependencies.clone().unwrap_or_default(), + }, + ); + + if let Some(dependencies) = resolved_version.dependencies { + for (dep_name, dep_version) in dependencies.iter() { + // Skip internal veniceext mod + if dep_name == "veniceext" { + continue; + } + + // TODO: Check if dependency is already part of the lock file + + // TODO: Check if not already resolving this dependency and whether the version matches + + unresolved.push_back(ModVersionConstraint { + name: dep_name.clone(), + tag: None, + version: Some(dep_version.clone()), + }); + } + } + } + + return Ok(lock_file); + } + + pub async fn resolve_dependency_version( + &self, + mod_constraint: &ModVersionConstraint, + ) -> Result { + let mod_response = self + .api_client + .mods() + .get(mod_constraint.name.to_string()) + .await; + + match mod_response { + Ok(mod_info) => { + if let Some(tag) = &mod_constraint.tag { + mod_info.get_version_by_tag(tag).ok_or( + DependencyResolverError::ModVersionNotFound( + mod_constraint.name.to_string(), + tag.to_string(), + ), + ) + } else if let Some(version) = &mod_constraint.version { + mod_info.get_version_by_constraint(version).ok_or( + DependencyResolverError::ModVersionNotFound( + mod_constraint.name.to_string(), + version.to_string(), + ), + ) + } else { + Err(DependencyResolverError::Other(anyhow::anyhow!( + "Invalid mod version constraint" + ))) + } + } + Err(err) => Err(match err { + vumm_api::Error::NotFound(_) => { + DependencyResolverError::ModNotFound(mod_constraint.name.to_string()) + } + vumm_api::Error::Forbidden(_) => { + DependencyResolverError::ModNoAccess(mod_constraint.name.to_string()) + } + _ => DependencyResolverError::Other(err.into()), + }), + } + } +} diff --git a/vumm_installer/src/lib.rs b/vumm_installer/src/lib.rs new file mode 100644 index 0000000..b7916da --- /dev/null +++ b/vumm_installer/src/lib.rs @@ -0,0 +1,109 @@ +mod dependency_resolver; +mod lock; + +use core::fmt; +use semver::VersionReq; + +pub use dependency_resolver::{DependencyResolver, DependencyResolverError}; +pub use lock::{LockFile, LockedMod}; + +#[derive(Clone, Debug)] +pub struct ModVersionConstraint { + name: String, + tag: Option, + version: Option, +} + +impl ModVersionConstraint { + pub fn new(mod_name: String, mod_version: String) -> Self { + let req = VersionReq::parse(mod_version.as_str()); + + match req { + Ok(version_req) => ModVersionConstraint { + name: mod_name, + tag: None, + version: Some(version_req), + }, + Err(_) => ModVersionConstraint { + name: mod_name, + tag: Some(mod_version), + version: None, + }, + } + } + + pub fn get_name(&self) -> &String { + &self.name + } + + pub fn get_tag(&self) -> &Option { + &self.tag + } + + pub fn get_version(&self) -> &Option { + &self.version + } +} + +impl fmt::Display for ModVersionConstraint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(version) = &self.version { + write!(f, "{}@{}", self.name, version) + } else { + write!(f, "{}@{}", self.name, self.tag.as_ref().unwrap()) + } + } +} + +#[cfg(test)] +mod tests { + use vumm_api::Client; + + use super::*; + + // #[test] + // fn test_resolve_version_constraint() { + // let mod_name = String::from("test"); + // let mod_version = String::from("1.0.0"); + + // let constraint = resolve_mod_version_constraint(mod_name, mod_version); + + // assert_eq!(constraint.name, mod_name); + // assert_eq!(constraint.tag, None); + // assert_eq!( + // constraint.version, + // Some(VersionReq::parse(mod_version.as_str()).unwrap()) + // ); + // } + + // #[test] + // fn test_resolve_version_constraint_tag() { + // let mod_name = String::from("test"); + // let mod_version = String::from("latest"); + + // let constraint = resolve_mod_version_constraint(mod_name, mod_version); + + // assert_eq!(constraint.name, mod_name); + // assert_eq!(constraint.tag, Some(mod_version)); + // assert_eq!(constraint.version, None); + // } + + #[tokio::test] + async fn test_resolve_dependencies() { + let api_client = Client::new(); + let resolver = DependencyResolver::new(api_client); + + let lock_file = resolver + .resolve_dependencies("mapeditor".to_string(), "preview".to_string()) + .await; + + match lock_file { + Ok(lock_file) => { + println!("Lock file: {:#?}", lock_file); + } + Err(err) => { + println!("Error: {}", err); + } + } + } +} diff --git a/vumm_installer/src/lock.rs b/vumm_installer/src/lock.rs new file mode 100644 index 0000000..fa00539 --- /dev/null +++ b/vumm_installer/src/lock.rs @@ -0,0 +1,34 @@ +use std::{collections::HashMap, fs}; + +use semver::{Version, VersionReq}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct LockedMod { + pub name: String, + pub version: Version, + pub dependencies: HashMap, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct LockFile { + pub mods: HashMap, +} + +impl LockFile { + pub fn new() -> Self { + LockFile { + mods: HashMap::new(), + } + } + + pub fn load(path: &str) -> Result { + let json = fs::read_to_string(path)?; + serde_json::from_str(json.as_str()).map_err(|e| e.into()) + } + + pub fn save(&self, path: &str) -> Result<(), anyhow::Error> { + let json = serde_json::to_string_pretty(self)?; + fs::write(path, json.as_bytes()).map_err(|e| e.into()) + } +}