#!/bin/sh
set -e
# Code generated by godownloader on 2023-12-14T06:36:11Z. DO NOT EDIT.
#

usage() {
  this=$1
  cat <<EOF
$this: download go binaries for DeepSourceCorp/cli

Usage: $this [-b] bindir [-d] [tag]
  -b sets bindir or installation directory, Defaults to ./bin
  -d turns on debug logging
   [tag] is a tag from
   https://github.com/DeepSourceCorp/cli/releases
   If tag is missing, then the latest will be used.

 Generated by godownloader
  https://github.com/goreleaser/godownloader

EOF
  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))
  TAG=$1
}
# this function wraps all the destructive operations
# if a curl|bash cuts off the end of the script due to
# network, either nothing will happen or will syntax error
# out preventing half-done work
execute() {
  tmpdir=$(mktemp -d)
  log_debug "downloading files into ${tmpdir}"
  http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}"
  http_download "${tmpdir}/${CHECKSUM}" "${CHECKSUM_URL}"
  hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/${CHECKSUM}"
  srcdir="${tmpdir}"
  (cd "${tmpdir}" && untar "${TARBALL}")
  test ! -d "${BINDIR}" && install -d "${BINDIR}"
  for binexe in $BINARIES; do
    if [ "$OS" = "windows" ]; then
      binexe="${binexe}.exe"
    fi
    install "${srcdir}/${binexe}" "${BINDIR}/"
    log_info "installed ${BINDIR}/${binexe}"
  done
  rm -rf "${tmpdir}"
}
get_binaries() {
  case "$PLATFORM" in
  darwin/amd64) BINARIES="deepsource" ;;
  darwin/arm64) BINARIES="deepsource" ;;
  linux/amd64) BINARIES="deepsource" ;;
  linux/arm64) BINARIES="deepsource" ;;
  windows/amd64) BINARIES="deepsource" ;;
  *)
    log_crit "platform $PLATFORM is not supported. Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new"
    exit 1
    ;;
  esac
}
tag_to_version() {
  if [ -z "${TAG}" ]; then
    log_info "checking GitHub for latest tag"
  else
    log_info "checking GitHub for tag '${TAG}'"
  fi
  REALTAG=$(github_release "$OWNER/$REPO" "${TAG}") && true
  if test -z "$REALTAG"; then
    if [ -z "${TAG}" ]; then
      log_crit "failed to get latest release information after 3 attempts"
    else
      log_crit "tag '${TAG}' not found - see https://github.com/${PREFIX}/releases for available versions"
    fi
    exit 1
  fi
  # if version starts with 'v', remove it
  TAG="$REALTAG"
  VERSION=${TAG#v}
}
adjust_format() {
  # change format (tar.gz or zip) based on OS
  true
}
adjust_os() {
  # code was removed,
  # see https://goreleaser.com/deprecations/#archivesreplacements
  true
}
adjust_arch() {
  # code was removed,
  # see https://goreleaser.com/deprecations/#archivesreplacements
  true
}

cat /dev/null <<EOF
------------------------------------------------------------------------
https://github.com/client9/shlib - portable posix shell functions
Public domain - http://unlicense.org
https://github.com/client9/shlib/blob/master/LICENSE.md
but credit (and pull requests) appreciated.
------------------------------------------------------------------------
EOF
is_command() {
  command -v "$1" >/dev/null
}
echoerr() {
  echo "$@" 1>&2
}
log_prefix() {
  echo "$0"
}
_logp=6
log_set_priority() {
  _logp="$1"
}
log_priority() {
  if test -z "$1"; then
    echo "$_logp"
    return
  fi
  [ "$1" -le "$_logp" ]
}
log_tag() {
  case $1 in
  0) echo "emerg" ;;
  1) echo "alert" ;;
  2) echo "crit" ;;
  3) echo "err" ;;
  4) echo "warning" ;;
  5) echo "notice" ;;
  6) echo "info" ;;
  7) echo "debug" ;;
  *) echo "$1" ;;
  esac
}
log_debug() {
  log_priority 7 || return 0
  echoerr "$(log_prefix)" "$(log_tag 7)" "$@"
}
log_info() {
  log_priority 6 || return 0
  echoerr "$(log_prefix)" "$(log_tag 6)" "$@"
}
log_err() {
  log_priority 3 || return 0
  echoerr "$(log_prefix)" "$(log_tag 3)" "$@"
}
log_crit() {
  log_priority 2 || return 0
  echoerr "$(log_prefix)" "$(log_tag 2)" "$@"
}
uname_os() {
  os=$(uname -s | tr '[:upper:]' '[:lower:]')
  case "$os" in
  cygwin_nt*) os="windows" ;;
  mingw*) os="windows" ;;
  msys_nt*) os="windows" ;;
  esac
  echo "$os"
}
uname_arch() {
  arch=$(uname -m)
  case $arch in
  x86_64) arch="amd64" ;;
  x86) arch="386" ;;
  i686) arch="386" ;;
  i386) arch="386" ;;
  aarch64) arch="arm64" ;;
  armv5*) arch="armv5" ;;
  armv6*) arch="armv6" ;;
  armv7*) arch="armv7" ;;
  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
  *.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;;
  *.tar) tar --no-same-owner -xf "${tarball}" ;;
  *.zip) unzip "${tarball}" ;;
  *)
    log_err "untar unknown archive format for ${tarball}"
    return 1
    ;;
  esac
}
http_download_curl() {
  local_file=$1
  source_url=$2
  header=$3
  if [ -z "$header" ]; then
    code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url")
  else
    code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url")
  fi
  if [ "$code" != "200" ]; then
    log_debug "http_download_curl received HTTP status $code"
    return 1
  fi
  return 0
}
http_download_wget() {
  local_file=$1
  source_url=$2
  header=$3
  if [ -z "$header" ]; then
    wget -q -O "$local_file" "$source_url"
  else
    wget -q --header "$header" -O "$local_file" "$source_url"
  fi
}
http_download() {
  log_debug "http_download $2"
  if is_command curl; then
    http_download_curl "$@"
    return
  elif is_command wget; then
    http_download_wget "$@"
    return
  fi
  log_crit "http_download unable to find wget or curl"
  return 1
}
http_copy() {
  tmp=$(mktemp)
  http_download "${tmp}" "$1" "$2" || return 1
  body=$(cat "$tmp")
  rm -f "${tmp}"
  echo "$body"
}
# Get HTTP status code and headers using curl
http_status_curl() {
  local_file=$1
  source_url=$2
  header=$3
  headers_file=$4

  if [ -z "$header" ]; then
    code=$(curl -w '%{http_code}' -sL -D "$headers_file" -o "$local_file" "$source_url")
  else
    code=$(curl -w '%{http_code}' -sL -D "$headers_file" -H "$header" -o "$local_file" "$source_url")
  fi
  echo "$code"
}

# Get HTTP status code using wget (wget doesn't provide status codes directly)
# We use curl-like exit codes: 200 for success, others for failure
http_status_wget() {
  local_file=$1
  source_url=$2
  header=$3
  headers_file=$4

  # wget writes server response headers to stderr when using --server-response
  # We redirect stderr to our headers file and capture the exit code
  # Use 'set +e' temporarily to prevent wget errors from killing the script
  set +e
  if [ -z "$header" ]; then
    wget -q --server-response -O "$local_file" "$source_url" 2>"$headers_file"
    wget_exit=$?
  else
    wget -q --server-response --header "$header" -O "$local_file" "$source_url" 2>"$headers_file"
    wget_exit=$?
  fi
  set -e

  if [ $wget_exit -eq 0 ]; then
    # Success - try to extract status code from headers, default to 200
    status=$(grep -o 'HTTP/[0-9.]* [0-9]*' "$headers_file" 2>/dev/null | tail -1 | sed 's/.*HTTP\/[0-9.]* //' || echo "200")
    echo "$status"
  else
    # Try to extract real HTTP status from headers first (for server errors like 503)
    real_status=$(grep -o 'HTTP/[0-9.]* [0-9]*' "$headers_file" 2>/dev/null | tail -1 | sed 's/.*HTTP\/[0-9.]* //' 2>/dev/null || echo "")
    if [ -n "$real_status" ]; then
      # Got real HTTP status from headers despite wget error
      echo "$real_status"
    else
      # No HTTP status in headers, map wget exit codes to appropriate HTTP-like codes
      # NOTE: We map network/temporary failures to retryable codes (5xx),
      # only map actual HTTP errors to their real status codes
      case $wget_exit in
        4) echo "503" ;;  # Network failure - should be retryable (Service Unavailable)
        5) echo "403" ;;  # SSL verification failure - likely permanent
        6) echo "401" ;;  # Username/password authentication failure - likely permanent
        7) echo "502" ;;  # Protocol errors - could be temporary (Bad Gateway)
        8) echo "502" ;;  # Server issued an error response - could be temporary
        *) echo "500" ;;  # Other failures - unknown, assume retryable
      esac
    fi
  fi
}

# Extract Retry-After header value from headers file (works for both curl and wget output)
get_retry_after() {
  headers_file=$1
  # Handle both curl format (Header: value) and wget format (  Header: value)
  grep -i 'retry-after:' "$headers_file" 2>/dev/null | tail -1 | sed 's/^[[:space:]]*[^:]*:[[:space:]]*//' | tr -d '\r' | grep '^[0-9][0-9]*$' || true
}

http_copy_with_retry() {
  url=$1
  header=$2
  max_retries=3
  attempt=1
  backoff=2

  while [ $attempt -le $max_retries ]; do
    tmp=$(mktemp)
    tmp_headers=$(mktemp)

    # Get status code using appropriate tool
    # We also track which tool failed to give better error messages
    tool_used=""
    if is_command curl; then
      tool_used="curl"
      code=$(http_status_curl "$tmp" "$url" "$header" "$tmp_headers")
    elif is_command wget; then
      tool_used="wget"
      code=$(http_status_wget "$tmp" "$url" "$header" "$tmp_headers")
    else
      log_crit "http_copy_with_retry requires curl or wget"
      rm -f "$tmp" "$tmp_headers"
      return 1
    fi

    # Success case
    if [ "$code" = "200" ]; then
      body=$(cat "$tmp")
      rm -f "$tmp" "$tmp_headers"
      if [ -n "$body" ]; then
        echo "$body"
        return 0
      fi
      # Empty body, treat as failure and retry
      log_info "request to GitHub API returned empty response, retrying in ${backoff}s (attempt $attempt/$max_retries)"
      sleep $backoff
      backoff=$((backoff * 2))
      attempt=$((attempt + 1))
      continue
    fi

    # Check if code is a valid number for comparison
    case "$code" in
      ''|*[!0-9]*)
        # Empty or non-numeric code - could be network failure or script error
        if [ -z "$code" ]; then
          log_info "request failed with $tool_used (no status code received), retrying in ${backoff}s (attempt $attempt/$max_retries)"
        else
          log_info "request failed with $tool_used (invalid status code: $code), retrying in ${backoff}s (attempt $attempt/$max_retries)"
        fi
        rm -f "$tmp" "$tmp_headers"
        sleep $backoff
        backoff=$((backoff * 2))
        attempt=$((attempt + 1))
        continue
        ;;
    esac

    # Retryable status codes: 000 (curl network failure), 429 (rate limit), 5xx (server errors)
    if [ "$code" = "000" ] || [ "$code" = "429" ] || [ "$code" -ge 500 ]; then
      # Check for Retry-After header
      retry_after=$(get_retry_after "$tmp_headers")

      if [ -n "$retry_after" ] && [ "$retry_after" -gt 0 ] && [ "$retry_after" -le 300 ]; then
        # Use Retry-After if it's between 1-300 seconds
        wait_time=$retry_after
      else
        wait_time=$backoff
      fi

      log_info "request to GitHub API failed (HTTP $code), retrying in ${wait_time}s (attempt $attempt/$max_retries)"
      rm -f "$tmp" "$tmp_headers"
      sleep "$wait_time"
      backoff=$((backoff * 2))
      attempt=$((attempt + 1))
      continue
    fi

    # Non-retryable error (4xx except 429)
    log_debug "http_copy_with_retry received HTTP status $code"
    rm -f "$tmp" "$tmp_headers"
    return 1
  done

  # All retries exhausted
  log_debug "all retries exhausted, giving up"
  rm -f "$tmp" "$tmp_headers" 2>/dev/null
  return 1
}
github_release() {
  owner_repo=$1
  version=$2
  test -z "$version" && version="latest"
  giturl="https://github.com/${owner_repo}/releases/${version}"
  json=$(http_copy_with_retry "$giturl" "Accept:application/json")
  test -z "$json" && return 1
  version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//')
  test -z "$version" && return 1
  echo "$version"
}
hash_sha256() {
  TARGET=${1:-/dev/stdin}
  if is_command gsha256sum; then
    hash=$(gsha256sum "$TARGET") || return 1
    echo "$hash" | cut -d ' ' -f 1
  elif is_command sha256sum; then
    hash=$(sha256sum "$TARGET") || return 1
    echo "$hash" | cut -d ' ' -f 1
  elif is_command shasum; then
    hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1
    echo "$hash" | cut -d ' ' -f 1
  elif is_command openssl; then
    hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1
    echo "$hash" | cut -d ' ' -f a
  else
    log_crit "hash_sha256 unable to find command to compute sha-256 hash"
    return 1
  fi
}
hash_sha256_verify() {
  TARGET=$1
  checksums=$2
  if [ -z "$checksums" ]; then
    log_err "hash_sha256_verify checksum file not specified in arg2"
    return 1
  fi
  BASENAME=${TARGET##*/}
  want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
  if [ -z "$want" ]; then
    log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'"
    return 1
  fi
  got=$(hash_sha256 "$TARGET")
  if [ "$want" != "$got" ]; then
    log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got"
    return 1
  fi
}
cat /dev/null <<EOF
------------------------------------------------------------------------
End of functions from https://github.com/client9/shlib
------------------------------------------------------------------------
EOF

PROJECT_NAME="deepsource"
OWNER=DeepSourceCorp
REPO="cli"
BINARY=deepsource
FORMAT=tar.gz
OS=$(uname_os)
ARCH=$(uname_arch)
PREFIX="$OWNER/$REPO"

# use in logging routines
log_prefix() {
  echo "$PREFIX"
}
PLATFORM="${OS}/${ARCH}"
GITHUB_DOWNLOAD=https://github.com/${OWNER}/${REPO}/releases/download

uname_os_check "$OS"
uname_arch_check "$ARCH"

parse_args "$@"

get_binaries

tag_to_version

adjust_format

adjust_os

adjust_arch

log_info "found version: ${VERSION} for ${TAG}/${OS}/${ARCH}"

NAME=deepsource_${VERSION}_${OS}_${ARCH}
TARBALL=${NAME}.${FORMAT}
TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL}
CHECKSUM=checksums.txt
CHECKSUM_URL=${GITHUB_DOWNLOAD}/${TAG}/${CHECKSUM}

execute
