Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/go: go run package@version vargs... from module directory and outside it #49720

Closed
cardil opened this issue Nov 22, 2021 · 1 comment
Closed

Comments

@cardil
Copy link

cardil commented Nov 22, 2021

Proposal

To allow executing Go tools without the need to install them. This is similar to how npx is operating. For example, using npx, you can invoke the following command, and npx will fetch snyk package and run it passing args:

$ npx snyk@v1 test --print-deps

I think similar behavior could be added to go run command. It already allows executing packages that are part of our GOPATH. When a given package isn't part of our module (or we are not within the module), we can create an ad-hoc module in user home directory, install the requested package there, and run it in the original directory for user profit.

$ go run github.com/cli/cli/v2/cmd/gh@v2 pr list --repo knative-sandbox/kn-plugin-event

What did you do?

To achieve that behavior with current Go, I use the following Bash functions:

# go.get-tool will 'go get' any package $2 and install it to $1. Replaces, can
# be set with $GO_GETTOOL_REPLACES.
function go.get-tool {
  local tmp_dir
  if ! [ -f "${1}" ]; then
    tmp_dir="$(mktemp -d)"
    # shellcheck disable=SC2064
    trap "rm -rf ${tmp_dir}" EXIT
    pushd "$tmp_dir" >/dev/null 2>&1
    go mod init tmp
    if [ -n "${GO_GETTOOL_REPLACES:-}" ]; then
      go mod edit -replace "${GO_GETTOOL_REPLACES}"
    fi
    echo "Downloading ${2}"
    GOBIN="$(dirname "${1}")" go get "${2}"
    popd >/dev/null 2>&1
  fi
  echo "Using ${2} in ${1}"
}

# go.run-tool will 'go get' package $1 and install it to temp path. Replaces, 
# can be set with $GO_GETTOOL_REPLACES. You could pass arguments to the tool by
# setting $2 and up.
function go.run-tool {
  local path_id systmp_dir bin_dir package package_id bin
  package="${1:?'Pass a GO executable package ref as arg[1]'}"
  shift
  path_id="$(echo "${BASH_SOURCE[0]:-$0}" | sha1sum - | awk '{print $1}')"
  package_id="$(echo "$package" | sha1sum - | awk '{print $1}')"
  systmp_dir="$(dirname "$(mktemp -d -u)")"
  bin_dir="${systmp_dir}/go-run-tool/${path_id}/${package_id}"
  mkdir -p "$bin_dir"
  bin="${package%@*}"
  bin="${bin_dir}/${bin##*/}"

  go.get-tool "$bin" "$package"

  "$bin" "$@"
}

By having those, I could execute command like:

$ go.run-tool \
    github.com/cli/cli/v2/cmd/gh@v2.2.1-0.20211122114001-a3940020f938 \
    pr list

What did you expect to see?

I'd like to have my Go tool fetched and executed, just as it does with my script wrapper go.run-tool.

What did you see instead?

package github.com/cli/cli/v2/cmd/gh@v2.2.1-0.20211122114001-a3940020f938: can only use path@version syntax with 'go get' and 'go install' in module-aware mode

or when outside of module

no required module provides package github.com/cli/cli/v2/cmd/gh: working directory is not part of a module
@seankhliao
Copy link
Member

This is available in 1.17+

@golang golang locked and limited conversation to collaborators Nov 22, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants