From cd2d8deb7bd9ded1eaa549bfcb9dfb2579342bab Mon Sep 17 00:00:00 2001 From: Will Roden Date: Sat, 9 Dec 2023 18:13:00 -0600 Subject: [PATCH] add self-wrapping --- cmd/bindown/cli.go | 13 +- cmd/bindown/cli_test.go | 31 +++ cmd/bindown/completion.go | 4 + .../testdata/golden/bootstrap/bootstrap.sh | 166 ++++++--------- .../testdata/golden/wrap/wrap-bindown/bindown | 194 +++++++----------- .../golden/wrap/wrap-bindown/runnable | 15 ++ internal/bindown/config.go | 55 ++++- internal/bindown/install.go | 67 +++++- internal/bindown/util.go | 9 + .../assets/bootstrap-bindown.gotmpl | 7 +- .../assets/bootstrap-main.sh | 24 +++ internal/build-bootstrapper/assets/lib.sh | 52 +++++ internal/build-bootstrapper/assets/main.sh | 78 ------- internal/build-bootstrapper/assets/shlib.sh | 39 ---- .../build-bootstrapper/assets/wrap-main.sh | 12 ++ internal/build-bootstrapper/build.go | 24 ++- script/fmt | 8 +- script/generate | 1 + script/generate-jsonschema | 4 +- script/generate-wrappers | 7 + script/gofumpt | 15 ++ script/golangci-lint | 15 ++ script/lint | 8 +- script/shellcheck | 15 ++ script/shfmt | 15 ++ script/yq | 15 ++ 26 files changed, 521 insertions(+), 372 deletions(-) rename internal/build-bootstrapper/testdata/want.txt => cmd/bindown/testdata/golden/wrap/wrap-bindown/bindown (52%) create mode 100644 cmd/bindown/testdata/golden/wrap/wrap-bindown/runnable create mode 100644 internal/build-bootstrapper/assets/bootstrap-main.sh create mode 100644 internal/build-bootstrapper/assets/lib.sh delete mode 100644 internal/build-bootstrapper/assets/main.sh create mode 100644 internal/build-bootstrapper/assets/wrap-main.sh create mode 100755 script/generate-wrappers create mode 100755 script/gofumpt create mode 100755 script/golangci-lint create mode 100755 script/shellcheck create mode 100755 script/shfmt create mode 100755 script/yq diff --git a/cmd/bindown/cli.go b/cmd/bindown/cli.go index d144fd49..0134ee20 100644 --- a/cmd/bindown/cli.go +++ b/cmd/bindown/cli.go @@ -29,7 +29,7 @@ var kongVars = kong.Vars{ "config_install_completions_help": `install shell completions`, "config_extract_path_help": `output path to directory where the downloaded archive is extracted`, "install_force_help": `force install even if it already exists`, - "output_help": `where to write the file. when multiple dependencies are selected, this is the directory to write to.`, + "output_help": `where to write the file. this is a directory unless a single dependency is selected and the path isn't an existing directory`, "download_force_help": `force download even if the file already exists`, "allow_missing_checksum": `allow missing checksums`, "download_help": `download a dependency but don't extract or install it`, @@ -222,7 +222,7 @@ func runCompletion(ctx context.Context, parser *kong.Kong) { defer cancel() kongplete.Complete(parser, kongplete.WithPredictor("bin", binCompleter(ctx)), - kongplete.WithPredictor("wrap_bin", binCompleter(ctx)), + kongplete.WithPredictor("wrap_bin", wrapBinCompleter(ctx)), kongplete.WithPredictor("allSystems", allSystemsCompleter), kongplete.WithPredictor("templateSource", templateSourceCompleter(ctx)), kongplete.WithPredictor("system", systemCompleter(ctx)), @@ -318,11 +318,13 @@ func (d *installCmd) Run(ctx *runContext) error { } type wrapCmd struct { - Dependency []string `kong:"arg,name=dependency,help=${dependency_help},predictor=bin"` + Dependency []string `kong:"arg,name=dependency,help=${dependency_help},predictor=wrap_bin"` All bool `kong:"help=${all_deps_help}"` Output string `kong:"type=path,name=output,type=file,help=${output_help}"` AllowMissingChecksum bool `kong:"name=allow-missing-checksum,help=${allow_missing_checksum}"` BindownExec string `kong:"name=bindown,help=${install_bindown_help}"` + BindownTag string `kong:"hidden,default=${bootstrap_tag_default}"` + BaseURL string `kong:"hidden,name='base-url',default='https://github.com'"` } func (d *wrapCmd) Run(ctx *runContext) error { @@ -333,9 +335,12 @@ func (d *wrapCmd) Run(ctx *runContext) error { return config.WrapDependencies(d.Dependency, &bindown.ConfigWrapDependenciesOpts{ Output: d.Output, AllowMissingChecksum: d.AllowMissingChecksum, - BindownPath: d.BindownExec, + BindownExec: d.BindownExec, Stdout: ctx.stdout, AllDeps: d.All, + BindownTag: d.BindownTag, + BindownWrapped: os.Getenv("BINDOWN_WRAPPED"), + BaseURL: d.BaseURL, }) } diff --git a/cmd/bindown/cli_test.go b/cmd/bindown/cli_test.go index 0488dc43..0ab6efdd 100644 --- a/cmd/bindown/cli_test.go +++ b/cmd/bindown/cli_test.go @@ -507,4 +507,35 @@ url_checksums: require.NoError(t, err) require.Equal(t, "Hello world", strings.TrimSpace(string(out))) }) + + t.Run("wrap bindown", func(t *testing.T) { + runner := newCmdRunner(t) + servePath := testdataPath("downloadables/runnable.tar.gz") + ts := testutil.ServeFiles(t, map[string]string{ + "/runnable/runnable.tar.gz": servePath, + "/WillAbides/bindown/releases/download/v4.8.0/checksums.txt": "testdata/bootstrap/checksums.txt", + }) + depURL := ts.URL + "/runnable/runnable.tar.gz" + runner.writeConfigYaml(fmt.Sprintf(` +dependencies: + runnable: + archive_path: bin/runnable.sh + url: %s +url_checksums: + %s: fb2fe41a34b77ee180def0cb9a222d8776a6e581106009b64f35983da291ab6e +`, depURL, depURL)) + outputDir := filepath.Join(runner.tmpDir, "output") + runnable := filepath.Join(outputDir, "runnable") + bindown := filepath.Join(outputDir, "bindown") + result := runner.run( + "wrap", "runnable", "bindown", + "--bindown-tag", "v4.8.0", + "--output", outputDir, + "--base-url", ts.URL, + ) + result.assertState(resultState{stdout: bindown + "\n" + runnable}) + testutil.AssertFile(t, runnable, true, false) + testutil.AssertFile(t, bindown, true, false) + testutil.CheckGoldenDir(t, outputDir, filepath.FromSlash("testdata/golden/wrap/wrap-bindown")) + }) } diff --git a/cmd/bindown/completion.go b/cmd/bindown/completion.go index 2d476dae..f524bb83 100644 --- a/cmd/bindown/completion.go +++ b/cmd/bindown/completion.go @@ -153,6 +153,10 @@ func binCompleter(ctx context.Context) complete.PredictFunc { } } +func wrapBinCompleter(ctx context.Context) complete.Predictor { + return complete.PredictOr(binCompleter(ctx), complete.PredictSet("bindown")) +} + func systemCompleter(ctx context.Context) complete.PredictFunc { return func(a complete.Args) []string { cfg := completionConfig(ctx, a.Completed) diff --git a/cmd/bindown/testdata/golden/bootstrap/bootstrap.sh b/cmd/bindown/testdata/golden/bootstrap/bootstrap.sh index 2e8cbaee..38f439ee 100644 --- a/cmd/bindown/testdata/golden/bootstrap/bootstrap.sh +++ b/cmd/bindown/testdata/golden/bootstrap/bootstrap.sh @@ -2,9 +2,9 @@ set -e -TAG="v4.8.0" +bindown_tag="v4.8.0" -CHECKSUMS=" +bindown_checksums=" 26fcbc738bf9bb910b070f236816b2dfe5bc9589be3a578135f37d950ebaf771 bindown_4.8.0_freebsd_amd64.tar.gz 2fa6460ebe8d7c6be33576acf5b63f7208780af72d758e82313f6c5772e097d5 bindown_4.8.0_linux_386.tar.gz 32e3fbfaecf41a1b2bced22c1842b3905f4e6de1e879a4db68402799c206415d bindown_4.8.0_windows_386.exe @@ -109,45 +109,6 @@ uname_arch() { esac echo "${arch}" } -uname_os_check() { - os=$(uname_os) - case "$os" in - darwin) return 0 ;; - dragonfly) return 0 ;; - freebsd) return 0 ;; - linux) return 0 ;; - android) return 0 ;; - nacl) return 0 ;; - netbsd) return 0 ;; - openbsd) return 0 ;; - plan9) return 0 ;; - solaris) return 0 ;; - windows) return 0 ;; - esac - log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib" - return 1 -} -uname_arch_check() { - arch=$(uname_arch) - case "$arch" in - 386) return 0 ;; - amd64) return 0 ;; - arm64) return 0 ;; - armv5) return 0 ;; - armv6) return 0 ;; - armv7) return 0 ;; - ppc64) return 0 ;; - ppc64le) return 0 ;; - mips) return 0 ;; - mipsle) return 0 ;; - mips64) return 0 ;; - mips64le) return 0 ;; - s390x) return 0 ;; - amd64p32) return 0 ;; - esac - log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib" - return 1 -} untar() { tarball=$1 case "${tarball}" in @@ -241,81 +202,82 @@ End of functions from https://github.com/client9/shlib ------------------------------------------------------------------------ EOF -FORMAT=tar.gz -GITHUB_DOWNLOAD=https://github.com/WillAbides/bindown/releases/download - -usage() { - this=$1 - cat << EOT -Usage: $this [-b bindir] [-d] - -b sets bindir or installation directory, Defaults to ./bin - -d turns on debug logging - -EOT - exit 2 -} - -parse_args() { - #BINDIR is ./bin unless set be ENV - # over-ridden by flag below - - BINDIR=${BINDIR:-./bin} - while getopts "b:dh?x" arg; do - case "$arg" in - b) BINDIR="$OPTARG" ;; - d) log_set_priority 10 ;; - h | \?) usage "$0" ;; - x) set -x ;; - esac - done - shift $((OPTIND - 1)) -} - bindown_name() { - if [ "$OS" = "windows" ]; then + if [ "$(uname_os)" = "windows" ]; then echo bindown.exe else echo bindown fi } -execute() { - tmpdir=$(mktemp -d) - echo "$CHECKSUMS" > "${tmpdir}/checksums.txt" - log_debug "downloading files into ${tmpdir}" - http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}" - hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/checksums.txt" - srcdir="${tmpdir}" - (cd "${tmpdir}" && untar "${TARBALL}") - test ! -d "${BINDIR}" && install -d "${BINDIR}" - install "${srcdir}/$(bindown_name)" "${BINDIR}/" - log_info "installed ${BINDIR}/$(bindown_name)" - rm -rf "${tmpdir}" -} - already_installed() { - VERSION="$1" - [ -f "${BINDIR}/$(bindown_name)" ] && - "${BINDIR}/$(bindown_name)" version 2> /dev/null | grep -q "$VERSION" + version="$1" + bindir="$2" + use_checksum_path="$3" + [ -f "$bindir/$(bindown_name)" ] || return 1 + if [ -n "$use_checksum_path" ]; then + return + fi + "$bindir/$(bindown_name)" version 2> /dev/null | grep -q "$version" } -OS=$(uname_os) -ARCH=$(uname_arch) +install_bindown() { + tag="$1" + checksums="$2" + bindir="$3" + use_checksum_path="$4" + repo_url="$5" + + version=${tag#v} + tarball="bindown_${version}_$(uname_os)_$(uname_arch).tar.gz" + tarball_url="$repo_url/releases/download/${tag}/${tarball}" + + if [ -n "$use_checksum_path" ]; then + tarball_checksum="$(echo "$checksums" | grep "$tarball" | tr '\t' ' ' | cut -d ' ' -f 1)" + bindir="${bindir}/${tarball_checksum}" + fi + + echo "$bindir/$(bindown_name)" + + if already_installed "$version" "$bindir" "$use_checksum_path"; then + log_info "bindown $version already installed in $bindir" + return + fi -uname_os_check "$OS" -uname_arch_check "$ARCH" + tmpdir=$(mktemp -d) + echo "$checksums" > "${tmpdir}/checksums.txt" + http_download "${tmpdir}/${tarball}" "${tarball_url}" + hash_sha256_verify "${tmpdir}/${tarball}" "${tmpdir}/checksums.txt" + (cd "${tmpdir}" && untar "${tarball}") + test ! -d "${bindir}" && install -d "${bindir}" + install "$tmpdir/$(bindown_name)" "${bindir}/" + log_info "installed ${bindir}/$(bindown_name)" + rm -rf "${tmpdir}" +} -parse_args "$@" +bindown_bindir="./bin" -VERSION=${TAG#v} +BINDOWN_REPO_URL="${BINDOWN_REPO_URL:-"https://github.com/WillAbides/bindown"}" -if already_installed "$VERSION"; then - log_debug "bindown ${VERSION} is already installed" - exit 0 +if [ -n "$BINDIR" ]; then + bindown_bindir="$BINDIR" fi -NAME=bindown_${VERSION}_${OS}_${ARCH} -TARBALL=${NAME}.${FORMAT} -TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL} +while getopts "b:cdh?x" arg; do + case "$arg" in + b) bindown_bindir="$OPTARG" ;; + c) opt_use_checksum_path=1 ;; + d) log_set_priority 10 ;; + h | \?) + echo "Usage: $0 [-b bindir] [-c] [-d] [-x] + -b sets bindir or installation directory, Defaults to ./bin + -c includes checksum in the output path + -d turns on debug logging + -x turns on bash debugging" >&2 + exit 2 + ;; + x) set -x ;; + esac +done -execute +install_bindown "${bindown_tag:?}" "${bindown_checksums:?}" "$bindown_bindir" "$opt_use_checksum_path" "$BINDOWN_REPO_URL" > /dev/null diff --git a/internal/build-bootstrapper/testdata/want.txt b/cmd/bindown/testdata/golden/wrap/wrap-bindown/bindown similarity index 52% rename from internal/build-bootstrapper/testdata/want.txt rename to cmd/bindown/testdata/golden/wrap/wrap-bindown/bindown index 21877563..92f564f0 100644 --- a/internal/build-bootstrapper/testdata/want.txt +++ b/cmd/bindown/testdata/golden/wrap/wrap-bindown/bindown @@ -2,25 +2,31 @@ set -e -TAG="v4.0.0" +bindown_tag="v4.8.0" -CHECKSUMS=" -056365714e2438ef942c725092159021d9e7bec42cffc3665345b1b8cf5293dd bindown_4.0.0_windows_amd64.exe -1ad02524a30511aaf7dcbfe3d4f7fb33aed10fae7397dca2ac8eab7c85d0e470 bindown_4.0.0_darwin_arm64 -2613c93fd3b1bbce01114fb754a4914191fd93ef314529231a6496e0274adee2 bindown_4.0.0_windows_arm64.tar.gz -3451cc078d32d9276cb14799c807f495cf1b10e349c774b289129a49fd517594 bindown_4.0.0_darwin_amd64 -3797f47297cd31aba1c8a1f146eb730052b45fbdc80ebbf3e394ec4095a28051 bindown_4.0.0_windows_386.tar.gz -55a760b68d4d351996d79b7a1685474ce45b73fb1cc348be3799d2abfe682007 bindown_4.0.0_linux_386 -5e9abe1e3ef306dc317e6e7b77cc8bcd3b7b70938e327839ab170e6a08b3232b bindown_4.0.0_windows_amd64.tar.gz -73efc42607b313ab827e9c139bea5030556d1c12a564b10f8dd60708da63452d bindown_4.0.0_darwin_arm64.tar.gz -83d5d4a6ff7bde23332751952a96e76f5af20d003dee438da8adc75408741652 bindown_4.0.0_windows_arm64.exe -8af964af162984afd36867f10b15a83490fe6f031d820f7311923f775247cac9 bindown_4.0.0_linux_amd64 -a15c275742903c696bb82f378c95b99f63533e89058e2653d4516d8f3ab6aa5e bindown_4.0.0_linux_386.tar.gz -c9f8667fa3323e7aabb87f1512d2743680105ea7c9bf017fc020ac02ea9cd0dc bindown_4.0.0_linux_arm64 -d023077a482c8ed99d2b8a80c2b265055d9fba5d1e82a525d2697d0f3f7eb59e bindown_4.0.0_linux_arm64.tar.gz -d19a6b2c460dc824db7c9c5a41c225007cedc33046ed8a2f03ea64367b779cba bindown_4.0.0_linux_amd64.tar.gz -d1d4fa85249f7f97286b65330a0244dbadef0a49894c95b1a2d679a68c40c67f bindown_4.0.0_windows_386.exe -d8455b74d2897b97efdc8a029d8fe099468cba41813abb0e1f1afe369e88c18a bindown_4.0.0_darwin_amd64.tar.gz +bindown_checksums=" +26fcbc738bf9bb910b070f236816b2dfe5bc9589be3a578135f37d950ebaf771 bindown_4.8.0_freebsd_amd64.tar.gz +2fa6460ebe8d7c6be33576acf5b63f7208780af72d758e82313f6c5772e097d5 bindown_4.8.0_linux_386.tar.gz +32e3fbfaecf41a1b2bced22c1842b3905f4e6de1e879a4db68402799c206415d bindown_4.8.0_windows_386.exe +335802ed91fa6f040e10570479a6c817c7e42bd57fe98c959890a821099d3e1f bindown_4.8.0_freebsd_arm64 +372846f7edd9d93df0cb17889790f595f17cb083e093f3e6437d34e3253fd378 bindown_4.8.0_windows_amd64.exe +40acf94b7c69e5d4101cb46ea99641d302ff23579cd7ead29a5abfceb1a5d9ba bindown_4.8.0_linux_arm64.tar.gz +66aca230d9aea549ecd3647082b63752f5bb5307ef6954a08cc0eaf9c70723f1 bindown_4.8.0_windows_amd64.tar.gz +752c78a926be1287312eea3c831e841e223de4780d1e4a8a813432d0a73f890b bindown_4.8.0_linux_amd64.tar.gz +7f1f1c883beceb6ec3919484511fb20c3ceb41088e814d6fc234b015e98b78d9 bindown_4.8.0_darwin_arm64 +7fdfbc007c0c285a498bf251bd4ab7469f334752581b45fda5ad6450ddd23377 bindown_4.8.0_windows_arm64.exe +95764bf76b54d5b13b9b8a801635d82447ee349c3545145ddd8a0a84246d66e2 bindown_4.8.0_freebsd_arm64.tar.gz +966087f13a6cf82804456119289ab982f2eee3ad04d8d4fb6ce74bd7eabdf74e bindown_4.8.0_windows_386.tar.gz +9b29e37ba273bc0dca9c8227ee4b58153289073ede7d900e9c84ae3c71f3dff5 bindown_4.8.0_windows_arm64.tar.gz +a625900e52f4413bee3863062463cc24f9c0669841fd6bc9979ee599edd88f3e bindown_4.8.0_freebsd_amd64 +ba09df557edc4499f41ddadc26369d7f70ed20bfb8310662f1290e6a355343e8 bindown_4.8.0_darwin_amd64.tar.gz +cd7b917d2737fe9fa087aea172d9b581757e9b300fa1d1dbd83c1b765be05bdb bindown_4.8.0_freebsd_386.tar.gz +d5d35274d4eab337c107940fc5b326c51f5bfd70d00924c79011684e2a0d4f22 bindown_4.8.0_freebsd_386 +d71d6c436ad33bb3aa01468698b86d5423127a19f9b1c664e346cc502501d415 bindown_4.8.0_darwin_arm64.tar.gz +d9361698bc1571c34915496da9c624e89fa12d87731711efd2cbbc9136c6fa85 bindown_4.8.0_darwin_amd64 +d93eae8638b96682d0e9b55bcbe92fecb296afd442e0526cc94ce0160c108c13 bindown_4.8.0_linux_arm64 +ec3d19abd00fbf099a98edb64c569842fa5b909222fb10da86d668f5597885be bindown_4.8.0_linux_amd64 +fa7e87f49aa30e42485431bd9dd021a32924ab11e4d39065533e9bccce182de4 bindown_4.8.0_linux_386 " cat /dev/null << EOF @@ -103,45 +109,6 @@ uname_arch() { esac echo "${arch}" } -uname_os_check() { - os=$(uname_os) - case "$os" in - darwin) return 0 ;; - dragonfly) return 0 ;; - freebsd) return 0 ;; - linux) return 0 ;; - android) return 0 ;; - nacl) return 0 ;; - netbsd) return 0 ;; - openbsd) return 0 ;; - plan9) return 0 ;; - solaris) return 0 ;; - windows) return 0 ;; - esac - log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib" - return 1 -} -uname_arch_check() { - arch=$(uname_arch) - case "$arch" in - 386) return 0 ;; - amd64) return 0 ;; - arm64) return 0 ;; - armv5) return 0 ;; - armv6) return 0 ;; - armv7) return 0 ;; - ppc64) return 0 ;; - ppc64le) return 0 ;; - mips) return 0 ;; - mipsle) return 0 ;; - mips64) return 0 ;; - mips64le) return 0 ;; - s390x) return 0 ;; - amd64p32) return 0 ;; - esac - log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib" - return 1 -} untar() { tarball=$1 case "${tarball}" in @@ -235,81 +202,70 @@ End of functions from https://github.com/client9/shlib ------------------------------------------------------------------------ EOF -FORMAT=tar.gz -GITHUB_DOWNLOAD=https://github.com/WillAbides/bindown/releases/download - -usage() { - this=$1 - cat << EOT -Usage: $this [-b bindir] [-d] - -b sets bindir or installation directory, Defaults to ./bin - -d turns on debug logging - -EOT - exit 2 -} - -parse_args() { - #BINDIR is ./bin unless set be ENV - # over-ridden by flag below - - BINDIR=${BINDIR:-./bin} - while getopts "b:dh?x" arg; do - case "$arg" in - b) BINDIR="$OPTARG" ;; - d) log_set_priority 10 ;; - h | \?) usage "$0" ;; - x) set -x ;; - esac - done - shift $((OPTIND - 1)) -} - bindown_name() { - if [ "$OS" = "windows" ]; then + if [ "$(uname_os)" = "windows" ]; then echo bindown.exe else echo bindown fi } -execute() { - tmpdir=$(mktemp -d) - echo "$CHECKSUMS" > "${tmpdir}/checksums.txt" - log_debug "downloading files into ${tmpdir}" - http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}" - hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/checksums.txt" - srcdir="${tmpdir}" - (cd "${tmpdir}" && untar "${TARBALL}") - test ! -d "${BINDIR}" && install -d "${BINDIR}" - install "${srcdir}/$(bindown_name)" "${BINDIR}/" - log_info "installed ${BINDIR}/$(bindown_name)" - rm -rf "${tmpdir}" -} - already_installed() { - VERSION="$1" - [ -f "${BINDIR}/$(bindown_name)" ] && - "${BINDIR}/$(bindown_name)" version 2> /dev/null | grep -q "$VERSION" + version="$1" + bindir="$2" + use_checksum_path="$3" + [ -f "$bindir/$(bindown_name)" ] || return 1 + if [ -n "$use_checksum_path" ]; then + return + fi + "$bindir/$(bindown_name)" version 2> /dev/null | grep -q "$version" } -OS=$(uname_os) -ARCH=$(uname_arch) +install_bindown() { + tag="$1" + checksums="$2" + bindir="$3" + use_checksum_path="$4" + repo_url="$5" + + version=${tag#v} + tarball="bindown_${version}_$(uname_os)_$(uname_arch).tar.gz" + tarball_url="$repo_url/releases/download/${tag}/${tarball}" + + if [ -n "$use_checksum_path" ]; then + tarball_checksum="$(echo "$checksums" | grep "$tarball" | tr '\t' ' ' | cut -d ' ' -f 1)" + bindir="${bindir}/${tarball_checksum}" + fi + + echo "$bindir/$(bindown_name)" + + if already_installed "$version" "$bindir" "$use_checksum_path"; then + log_info "bindown $version already installed in $bindir" + return + fi + + tmpdir=$(mktemp -d) + echo "$checksums" > "${tmpdir}/checksums.txt" + http_download "${tmpdir}/${tarball}" "${tarball_url}" + hash_sha256_verify "${tmpdir}/${tarball}" "${tmpdir}/checksums.txt" + (cd "${tmpdir}" && untar "${tarball}") + test ! -d "${bindir}" && install -d "${bindir}" + install "$tmpdir/$(bindown_name)" "${bindir}/" + log_info "installed ${bindir}/$(bindown_name)" + rm -rf "${tmpdir}" +} -uname_os_check "$OS" -uname_arch_check "$ARCH" +bindown_bindir="../cache/bootstrapped" -parse_args "$@" +BINDOWN_REPO_URL="${BINDOWN_REPO_URL:-"https://github.com/WillAbides/bindown"}" -VERSION=${TAG#v} +script_dir="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd -P)" +bindown_bindir="$script_dir/$bindown_bindir" -if already_installed "$VERSION"; then - log_debug "bindown ${VERSION} is already installed" - exit 0 -fi +log_set_priority 3 # log at error level -NAME=bindown_${VERSION}_${OS}_${ARCH} -TARBALL=${NAME}.${FORMAT} -TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL} +bindown_exec="$(install_bindown "${bindown_tag:?}" "${bindown_checksums:?}" "$bindown_bindir" "1" "$BINDOWN_REPO_URL")" -execute +BINDOWN_WRAPPED="${BINDOWN_WRAPPED:-"$script_dir/$(basename "$0")"}" +export BINDOWN_WRAPPED +exec "$bindown_exec" "$@" diff --git a/cmd/bindown/testdata/golden/wrap/wrap-bindown/runnable b/cmd/bindown/testdata/golden/wrap/wrap-bindown/runnable new file mode 100644 index 00000000..19f44613 --- /dev/null +++ b/cmd/bindown/testdata/golden/wrap/wrap-bindown/runnable @@ -0,0 +1,15 @@ +#!/bin/sh +# Code generated by bindown. DO NOT EDIT. + +set -e + +bindown_bin="$( + CDPATH="" cd -- "$(dirname -- "$0")" + + "./bindown" install "runnable" \ + --to-cache \ + --configfile "../.bindown.yaml" \ + --cache "../cache" +)" + +exec "$bindown_bin" "$@" diff --git a/internal/bindown/config.go b/internal/bindown/config.go index 30e6409b..106661c8 100644 --- a/internal/bindown/config.go +++ b/internal/bindown/config.go @@ -497,7 +497,10 @@ func (c *Config) InstallDependencies(deps []string, system System, opts *ConfigI type ConfigWrapDependenciesOpts struct { Output string - BindownPath string + BindownExec string + BindownTag string + BindownWrapped string + BaseURL string AllowMissingChecksum bool AllDeps bool Stdout io.Writer @@ -510,18 +513,64 @@ func (c *Config) WrapDependencies(deps []string, opts *ConfigWrapDependenciesOpt if opts.AllDeps { deps = c.DependencyNames() } + if len(deps) == 0 { + return nil + } + output := opts.Output - outputIsDir := opts.AllDeps || len(deps) > 1 + outputIsDir := opts.AllDeps || len(deps) > 1 || dirExists(output) if output == "" { output = c.InstallDir outputIsDir = true } + outputDir := output + if !outputIsDir { + outputDir = filepath.Dir(output) + } + + bindownIdx := slices.Index(deps, "bindown") + wrapsSelf := false + if bindownIdx != -1 && c.Dependencies["bindown"] == nil { + wrapsSelf = true + deps = slices.Delete(deps, bindownIdx, bindownIdx+1) + } + + if wrapsSelf { + target := output + if outputIsDir { + target = filepath.Join(output, "bindown") + } + out, err := createBindownWrapper(target, c.Cache, opts.BindownTag, opts.BaseURL) + if err != nil { + return err + } + if opts.Stdout != nil { + _, err = fmt.Fprintln(opts.Stdout, out) + if err != nil { + return err + } + } + } + + bindownExec := opts.BindownExec + if bindownExec == "" { + bindownExec = opts.BindownWrapped + } + if bindownExec == "" { + if FileExists(filepath.Join(outputDir, "bindown")) { + bindownExec = filepath.Join(outputDir, "bindown") + } + } + for _, name := range deps { target := output if outputIsDir { target = filepath.Join(output, name) } - out, err := createWrapper(name, target, opts.BindownPath, c.Cache, c.Filename, opts.AllowMissingChecksum) + if name == "bindown" && wrapsSelf { + continue + } + out, err := createWrapper(name, target, bindownExec, c.Cache, c.Filename, opts.AllowMissingChecksum) if err != nil { return err } diff --git a/internal/bindown/install.go b/internal/bindown/install.go index 107c6bcb..2b48dbc1 100644 --- a/internal/bindown/install.go +++ b/internal/bindown/install.go @@ -8,6 +8,7 @@ import ( "strings" "text/template" + bootstrapper "github.com/willabides/bindown/v4/internal/build-bootstrapper" "github.com/willabides/bindown/v4/internal/cache" ) @@ -23,14 +24,19 @@ func install( if toCache { instCache := &cache.Cache{Root: filepath.Join(cacheDir, "bin")} key := dep.cacheKey() - dir, unlock, err := instCache.Dir(key, nil, func(dir string) error { + validateFn := func(dir string) error { filename := filepath.Join(dir, dep.binName()) - if FileExists(filename) { - return nil + if !FileExists(filename) { + return fmt.Errorf("file %q does not exist", filename) } + return nil + } + popFn := func(dir string) error { + filename := filepath.Join(dir, dep.binName()) _, err := install(dep, filename, cacheDir, force, false, missingSums) return err - }) + } + dir, unlock, err := instCache.Dir(key, validateFn, popFn) if err != nil { return "", err } @@ -167,26 +173,69 @@ func createWrapper(name, target, bindownExec, cacheDir, configFile string, missi return target, nil } +func createBindownWrapper(target, cacheDir, tag, baseURL string) (string, error) { + wrapperDir := filepath.Dir(target) + err := os.MkdirAll(wrapperDir, 0o750) + if err != nil { + return "", err + } + binDir := filepath.Join(cacheDir, "bootstrapped") + err = os.MkdirAll(binDir, 0o750) + if err != nil { + return "", err + } + binDir, err = relPath(wrapperDir, binDir) + if err != nil { + return "", err + } + content, err := bootstrapper.Build(tag, &bootstrapper.BuildOpts{ + BinDir: binDir, + Wrap: true, + BaseURL: baseURL, + }) + if err != nil { + return "", err + } + err = os.WriteFile(target, []byte(content), 0o750) + if err != nil { + return "", err + } + return target, nil +} + // relPath returns target relative to base and converted to slash-separated path. // Unlike filepath.Rel, it converts both paths to absolute paths before calculating the relative path. func relPath(base, target string) (string, error) { - absBase, err := filepath.Abs(base) + // if it works without abs, use that + rel, err := filepath.Rel(base, target) + if err == nil { + return filepath.ToSlash(rel), nil + } + + // convert to abs and try again + base, err = filepath.Abs(base) if err != nil { return "", err } - absBase, err = filepath.EvalSymlinks(absBase) + target, err = filepath.Abs(target) if err != nil { return "", err } - absTarget, err := filepath.Abs(target) + rel, err = filepath.Rel(base, target) + if err == nil { + return filepath.ToSlash(rel), nil + } + + // resolve symlinks and try again + base, err = filepath.EvalSymlinks(base) if err != nil { return "", err } - absTarget, err = filepath.EvalSymlinks(absTarget) + target, err = filepath.EvalSymlinks(target) if err != nil { return "", err } - rel, err := filepath.Rel(absBase, absTarget) + rel, err = filepath.Rel(base, target) if err != nil { return "", err } diff --git a/internal/bindown/util.go b/internal/bindown/util.go index c4ae4bf5..8030d409 100644 --- a/internal/bindown/util.go +++ b/internal/bindown/util.go @@ -122,6 +122,15 @@ func FileExists(path string) bool { return !os.IsNotExist(statErr) } +// dirExists asserts that a directory exists. +func dirExists(path string) bool { + info, err := os.Stat(filepath.FromSlash(path)) + if err != nil { + return false + } + return info.IsDir() +} + // fileExistsWithChecksum returns true if the file both exists and has a matching checksum func fileExistsWithChecksum(filename, checksum string) (bool, error) { if !FileExists(filename) { diff --git a/internal/build-bootstrapper/assets/bootstrap-bindown.gotmpl b/internal/build-bootstrapper/assets/bootstrap-bindown.gotmpl index c1245330..40edd7ba 100644 --- a/internal/build-bootstrapper/assets/bootstrap-bindown.gotmpl +++ b/internal/build-bootstrapper/assets/bootstrap-bindown.gotmpl @@ -2,11 +2,14 @@ set -e -TAG="{{ .tag }}" +bindown_tag="{{ .tag }}" -CHECKSUMS=" +bindown_checksums=" {{ .checksums }} " {{ .shlib }} +{{ .lib }} +bindown_bindir="{{ .bindir }}" + {{ .main }} diff --git a/internal/build-bootstrapper/assets/bootstrap-main.sh b/internal/build-bootstrapper/assets/bootstrap-main.sh new file mode 100644 index 00000000..85a8e461 --- /dev/null +++ b/internal/build-bootstrapper/assets/bootstrap-main.sh @@ -0,0 +1,24 @@ +BINDOWN_REPO_URL="${BINDOWN_REPO_URL:-"https://github.com/WillAbides/bindown"}" + +if [ -n "$BINDIR" ]; then + bindown_bindir="$BINDIR" +fi + +while getopts "b:cdh?x" arg; do + case "$arg" in + b) bindown_bindir="$OPTARG" ;; + c) opt_use_checksum_path=1 ;; + d) log_set_priority 10 ;; + h | \?) + echo "Usage: $0 [-b bindir] [-c] [-d] [-x] + -b sets bindir or installation directory, Defaults to ./bin + -c includes checksum in the output path + -d turns on debug logging + -x turns on bash debugging" >&2 + exit 2 + ;; + x) set -x ;; + esac +done + +install_bindown "${bindown_tag:?}" "${bindown_checksums:?}" "$bindown_bindir" "$opt_use_checksum_path" "$BINDOWN_REPO_URL" > /dev/null diff --git a/internal/build-bootstrapper/assets/lib.sh b/internal/build-bootstrapper/assets/lib.sh new file mode 100644 index 00000000..1b4b5ac0 --- /dev/null +++ b/internal/build-bootstrapper/assets/lib.sh @@ -0,0 +1,52 @@ +bindown_name() { + if [ "$(uname_os)" = "windows" ]; then + echo bindown.exe + else + echo bindown + fi +} + +already_installed() { + version="$1" + bindir="$2" + use_checksum_path="$3" + [ -f "$bindir/$(bindown_name)" ] || return 1 + if [ -n "$use_checksum_path" ]; then + return + fi + "$bindir/$(bindown_name)" version 2> /dev/null | grep -q "$version" +} + +install_bindown() { + tag="$1" + checksums="$2" + bindir="$3" + use_checksum_path="$4" + repo_url="$5" + + version=${tag#v} + tarball="bindown_${version}_$(uname_os)_$(uname_arch).tar.gz" + tarball_url="$repo_url/releases/download/${tag}/${tarball}" + + if [ -n "$use_checksum_path" ]; then + tarball_checksum="$(echo "$checksums" | grep "$tarball" | tr '\t' ' ' | cut -d ' ' -f 1)" + bindir="${bindir}/${tarball_checksum}" + fi + + echo "$bindir/$(bindown_name)" + + if already_installed "$version" "$bindir" "$use_checksum_path"; then + log_info "bindown $version already installed in $bindir" + return + fi + + tmpdir=$(mktemp -d) + echo "$checksums" > "${tmpdir}/checksums.txt" + http_download "${tmpdir}/${tarball}" "${tarball_url}" + hash_sha256_verify "${tmpdir}/${tarball}" "${tmpdir}/checksums.txt" + (cd "${tmpdir}" && untar "${tarball}") + test ! -d "${bindir}" && install -d "${bindir}" + install "$tmpdir/$(bindown_name)" "${bindir}/" + log_info "installed ${bindir}/$(bindown_name)" + rm -rf "${tmpdir}" +} diff --git a/internal/build-bootstrapper/assets/main.sh b/internal/build-bootstrapper/assets/main.sh deleted file mode 100644 index 07cb52af..00000000 --- a/internal/build-bootstrapper/assets/main.sh +++ /dev/null @@ -1,78 +0,0 @@ -FORMAT=tar.gz -GITHUB_DOWNLOAD=https://github.com/WillAbides/bindown/releases/download - -usage() { - this=$1 - cat << EOT -Usage: $this [-b bindir] [-d] - -b sets bindir or installation directory, Defaults to ./bin - -d turns on debug logging - -EOT - exit 2 -} - -parse_args() { - #BINDIR is ./bin unless set be ENV - # over-ridden by flag below - - BINDIR=${BINDIR:-./bin} - while getopts "b:dh?x" arg; do - case "$arg" in - b) BINDIR="$OPTARG" ;; - d) log_set_priority 10 ;; - h | \?) usage "$0" ;; - x) set -x ;; - esac - done - shift $((OPTIND - 1)) -} - -bindown_name() { - if [ "$OS" = "windows" ]; then - echo bindown.exe - else - echo bindown - fi -} - -execute() { - tmpdir=$(mktemp -d) - echo "$CHECKSUMS" > "${tmpdir}/checksums.txt" - log_debug "downloading files into ${tmpdir}" - http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}" - hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/checksums.txt" - srcdir="${tmpdir}" - (cd "${tmpdir}" && untar "${TARBALL}") - test ! -d "${BINDIR}" && install -d "${BINDIR}" - install "${srcdir}/$(bindown_name)" "${BINDIR}/" - log_info "installed ${BINDIR}/$(bindown_name)" - rm -rf "${tmpdir}" -} - -already_installed() { - VERSION="$1" - [ -f "${BINDIR}/$(bindown_name)" ] && - "${BINDIR}/$(bindown_name)" version 2> /dev/null | grep -q "$VERSION" -} - -OS=$(uname_os) -ARCH=$(uname_arch) - -uname_os_check "$OS" -uname_arch_check "$ARCH" - -parse_args "$@" - -VERSION=${TAG#v} - -if already_installed "$VERSION"; then - log_debug "bindown ${VERSION} is already installed" - exit 0 -fi - -NAME=bindown_${VERSION}_${OS}_${ARCH} -TARBALL=${NAME}.${FORMAT} -TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL} - -execute diff --git a/internal/build-bootstrapper/assets/shlib.sh b/internal/build-bootstrapper/assets/shlib.sh index b8979518..09fd856b 100644 --- a/internal/build-bootstrapper/assets/shlib.sh +++ b/internal/build-bootstrapper/assets/shlib.sh @@ -78,45 +78,6 @@ uname_arch() { esac echo "${arch}" } -uname_os_check() { - os=$(uname_os) - case "$os" in - darwin) return 0 ;; - dragonfly) return 0 ;; - freebsd) return 0 ;; - linux) return 0 ;; - android) return 0 ;; - nacl) return 0 ;; - netbsd) return 0 ;; - openbsd) return 0 ;; - plan9) return 0 ;; - solaris) return 0 ;; - windows) return 0 ;; - esac - log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib" - return 1 -} -uname_arch_check() { - arch=$(uname_arch) - case "$arch" in - 386) return 0 ;; - amd64) return 0 ;; - arm64) return 0 ;; - armv5) return 0 ;; - armv6) return 0 ;; - armv7) return 0 ;; - ppc64) return 0 ;; - ppc64le) return 0 ;; - mips) return 0 ;; - mipsle) return 0 ;; - mips64) return 0 ;; - mips64le) return 0 ;; - s390x) return 0 ;; - amd64p32) return 0 ;; - esac - log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib" - return 1 -} untar() { tarball=$1 case "${tarball}" in diff --git a/internal/build-bootstrapper/assets/wrap-main.sh b/internal/build-bootstrapper/assets/wrap-main.sh new file mode 100644 index 00000000..35bdb4e0 --- /dev/null +++ b/internal/build-bootstrapper/assets/wrap-main.sh @@ -0,0 +1,12 @@ +BINDOWN_REPO_URL="${BINDOWN_REPO_URL:-"https://github.com/WillAbides/bindown"}" + +script_dir="$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd -P)" +bindown_bindir="$script_dir/$bindown_bindir" + +log_set_priority 3 # log at error level + +bindown_exec="$(install_bindown "${bindown_tag:?}" "${bindown_checksums:?}" "$bindown_bindir" "1" "$BINDOWN_REPO_URL")" + +BINDOWN_WRAPPED="${BINDOWN_WRAPPED:-"$script_dir/$(basename "$0")"}" +export BINDOWN_WRAPPED +exec "$bindown_exec" "$@" diff --git a/internal/build-bootstrapper/build.go b/internal/build-bootstrapper/build.go index a853cafb..1357902a 100644 --- a/internal/build-bootstrapper/build.go +++ b/internal/build-bootstrapper/build.go @@ -17,6 +17,8 @@ var assets embed.FS type BuildOpts struct { BaseURL string // defaults to https://github.com + BinDir string + Wrap bool } // Build builds a bootstrapper for the given tag @@ -28,9 +30,10 @@ func Build(tag string, opts *BuildOpts) (_ string, errOut error) { if baseURL == "" { baseURL = "https://github.com" } + repoURL := fmt.Sprintf("%s/WillAbides/bindown", baseURL) checksumsURL := fmt.Sprintf( - `%s/WillAbides/bindown/releases/download/%s/checksums.txt`, - baseURL, tag, + `%s/releases/download/%s/checksums.txt`, + repoURL, tag, ) resp, err := http.Get(checksumsURL) if err != nil { @@ -48,7 +51,15 @@ func Build(tag string, opts *BuildOpts) (_ string, errOut error) { if err != nil { return "", err } - mainContent, err := assets.ReadFile("assets/main.sh") + mainSrc := "assets/bootstrap-main.sh" + if opts.Wrap { + mainSrc = "assets/wrap-main.sh" + } + mainContent, err := assets.ReadFile(mainSrc) + if err != nil { + return "", err + } + libContent, err := assets.ReadFile("assets/lib.sh") if err != nil { return "", err } @@ -60,12 +71,19 @@ func Build(tag string, opts *BuildOpts) (_ string, errOut error) { if err != nil { return "", err } + binDir := "./bin" + if opts.BinDir != "" { + binDir = opts.BinDir + } var tmplOut bytes.Buffer err = tmpl.Execute(&tmplOut, map[string]string{ "tag": tag, "checksums": strings.TrimSpace(string(checksums)), "shlib": string(shlibContent), + "lib": string(libContent), "main": string(mainContent), + "bindir": binDir, + "repo_url": repoURL, }) if err != nil { return "", err diff --git a/script/fmt b/script/fmt index 0577df90..74c99fac 100755 --- a/script/fmt +++ b/script/fmt @@ -4,12 +4,10 @@ set -e CDPATH="" cd -- "$(dirname -- "$0")/.." -script/bindown -q install gofumpt shfmt - -bin/gofumpt -w internal/*/*.go cmd/*/*.go +script/gofumpt -w internal/*/*.go cmd/*/*.go find script -type f -not -name 'bootstrap-bindown.sh' | grep -v "/.*/" | - xargs bin/shfmt -w -i 2 -ci -sr + xargs script/shfmt -w -i 2 -ci -sr -bin/shfmt -w -i 2 -ci -sr internal/build-bootstrapper/assets/*.sh +script/shfmt -w -i 2 -ci -sr internal/build-bootstrapper/assets/*.sh diff --git a/script/generate b/script/generate index ddb1324a..a069c154 100755 --- a/script/generate +++ b/script/generate @@ -31,6 +31,7 @@ if [ "$1" = "--check" ]; then exit 0 fi +script/generate-wrappers script/generate-jsonschema go generate ./... diff --git a/script/generate-jsonschema b/script/generate-jsonschema index 78658a4e..c69edae3 100755 --- a/script/generate-jsonschema +++ b/script/generate-jsonschema @@ -4,8 +4,6 @@ set -e CDPATH="" cd -- "$(dirname -- "$0")/.." -script/bindown -q install yq - go run ./internal/genjsonschema > bindown.schema.json cp bindown.schema.json ./internal/bindown/bindown.schema.json -bin/yq -P . < bindown.schema.json > bindown.schema.yml +script/yq -P . < bindown.schema.json > bindown.schema.yml diff --git a/script/generate-wrappers b/script/generate-wrappers new file mode 100755 index 00000000..54db23c3 --- /dev/null +++ b/script/generate-wrappers @@ -0,0 +1,7 @@ +#!/bin/bash + +set -e + +CDPATH="" cd -- "$(dirname -- "$0")/.." + +script/bindown -q wrap yq gofumpt shfmt golangci-lint shellcheck --output ./script diff --git a/script/gofumpt b/script/gofumpt new file mode 100755 index 00000000..3b4c873b --- /dev/null +++ b/script/gofumpt @@ -0,0 +1,15 @@ +#!/bin/sh +# Code generated by bindown. DO NOT EDIT. + +set -e + +bindown_bin="$( + CDPATH="" cd -- "$(dirname -- "$0")" + + "./bindown" install "gofumpt" \ + --to-cache \ + --configfile "../bindown.yml" \ + --cache "../bin/.bindown" +)" + +exec "$bindown_bin" "$@" diff --git a/script/golangci-lint b/script/golangci-lint new file mode 100755 index 00000000..eda0fbd0 --- /dev/null +++ b/script/golangci-lint @@ -0,0 +1,15 @@ +#!/bin/sh +# Code generated by bindown. DO NOT EDIT. + +set -e + +bindown_bin="$( + CDPATH="" cd -- "$(dirname -- "$0")" + + "./bindown" install "golangci-lint" \ + --to-cache \ + --configfile "../bindown.yml" \ + --cache "../bin/.bindown" +)" + +exec "$bindown_bin" "$@" diff --git a/script/lint b/script/lint index 16106418..7f11e2ef 100755 --- a/script/lint +++ b/script/lint @@ -4,9 +4,7 @@ set -e CDPATH="" cd -- "$(dirname -- "$0")/.." -script/bindown -q install golangci-lint shellcheck - -bin/golangci-lint run +script/golangci-lint run # Don't check bootstrap-bindown.sh because it's dynamically generated -find script -type f -not -name 'bootstrap-bindown.sh' -print0 | xargs -0 bin/shellcheck -bin/shellcheck -s sh internal/build-bootstrapper/assets/*.sh +find script -type f -not -name 'bootstrap-bindown.sh' -print0 | xargs -0 script/shellcheck +script/shellcheck -s sh internal/build-bootstrapper/assets/*.sh diff --git a/script/shellcheck b/script/shellcheck new file mode 100755 index 00000000..57bbc3e1 --- /dev/null +++ b/script/shellcheck @@ -0,0 +1,15 @@ +#!/bin/sh +# Code generated by bindown. DO NOT EDIT. + +set -e + +bindown_bin="$( + CDPATH="" cd -- "$(dirname -- "$0")" + + "./bindown" install "shellcheck" \ + --to-cache \ + --configfile "../bindown.yml" \ + --cache "../bin/.bindown" +)" + +exec "$bindown_bin" "$@" diff --git a/script/shfmt b/script/shfmt new file mode 100755 index 00000000..9957eb0a --- /dev/null +++ b/script/shfmt @@ -0,0 +1,15 @@ +#!/bin/sh +# Code generated by bindown. DO NOT EDIT. + +set -e + +bindown_bin="$( + CDPATH="" cd -- "$(dirname -- "$0")" + + "./bindown" install "shfmt" \ + --to-cache \ + --configfile "../bindown.yml" \ + --cache "../bin/.bindown" +)" + +exec "$bindown_bin" "$@" diff --git a/script/yq b/script/yq new file mode 100755 index 00000000..a81f30bb --- /dev/null +++ b/script/yq @@ -0,0 +1,15 @@ +#!/bin/sh +# Code generated by bindown. DO NOT EDIT. + +set -e + +bindown_bin="$( + CDPATH="" cd -- "$(dirname -- "$0")" + + "./bindown" install "yq" \ + --to-cache \ + --configfile "../bindown.yml" \ + --cache "../bin/.bindown" +)" + +exec "$bindown_bin" "$@"