#!/usr/bin/env bash

# Copyright (c) 2021-2022, NVIDIA CORPORATION.  All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Dependencies:
#   regctl
#

function assert_usage() {
cat >&2 << EOF
Incorrect arguments: $*
$(basename "${BASH_SOURCE[0]}") DIST-ARCH
    DIST: The distribution.
    ARCH: The architecture.

Environment Variables
    ARTIFACTORY_TOKEN: must contain an auth token. [required]
    LIB_TAG: optional package tag.
    CI_COMMIT_REF_NAME: provided by CI/CD system.
    CI_COMMIT_SHA: provided by CI/CD system.
EOF
    exit 1
}

SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../scripts && pwd )"
PROJECT_ROOT="$( cd "${SCRIPTS_DIR}/.." && pwd )"

source "${SCRIPTS_DIR}"/utils.sh

if [[ $# -ne 1 ]]; then
    assert_usage "$@"
fi

DISTARCH=$1
ARTIFACTORY_PATH=$2
DIST=${DISTARCH%-*}
ARCH=${DISTARCH##*-}

CURL=${CURL:-curl}

if [[ -z "${DIST}" || -z "${ARCH}" ]]; then
    echo "ERROR: Distro and Architecture must be specified." >&2
    assert_usage "$@"
fi

if [[ -z "${ARTIFACTORY_PATH}" ]]; then
    echo "ERROR: Package repo must be specified." >&2
    assert_usage "$@"
fi

if [[ -z "${ARTIFACTORY_TOKEN}" ]]; then
    echo "ERROR: ARTIFACTORY_TOKEN must be defined." >&2
    assert_usage "$@"
fi

# TODO: accept PACKAGES_DIR as a command-line argument
: "${ARTIFACTS_DIR="${PROJECT_ROOT}/artifacts"}"
: "${PACKAGES_DIR="${ARTIFACTS_DIR}/packages"}"

eval $(${SCRIPTS_DIR}/get-component-versions.sh)

# Returns the key=value property if the value isn't empty
# Prepends with ";" if needed
set_prop_value() {
    local key=$1
    local value=$2
    if [ -n "${value}" ]; then
        if [ -z "${PROPS}" ]; then
            echo "${key}=${value}"
        else
            echo ";${key}=${value}"
        fi
    fi
}

process_props() {
    local dist=$1
    local arch=$2
    local file=$3
    local component_name="${file%%.*}"
    component_name="${component_name%-*}"
    local pkg_type="$(package_type $dist)"

    ## Component owner is free to define these
    # PROPS+=$(set_prop_value "version" "${VERSION}")
    # PROPS+=$(set_prop_value "lws_version" "${LWS_VER}")
    # PROPS+=$(set_prop_value "platform" "${DISTARCH}")

    # TODO: Use `git describe` to get this information if it's not available.
    PROPS+=$(set_prop_value "changelist" "${CI_COMMIT_SHA}")
    PROPS+=$(set_prop_value "branch" "${CI_COMMIT_REF_NAME}")

    # PROPS+=$(set_prop_value "category" "utils")
    # PROPS+=$(set_prop_value "platform" "${DISTARCH}")

    # Gitlab variables to expose
    for var in CI_PROJECT_ID CI_PIPELINE_ID CI_JOB_ID CI_JOB_URL CI_PROJECT_PATH; do
        if [ -n "${!var}" ]; then
            PROPS+=$(set_prop_value "${var}" "${!var}")
        fi
    done

    # We also set the package-specific properties to allow this to be used for other artifactory repositories
    PROPS+=$(set_prop_value "${pkg_type}.distribution" "${dist}")
    PROPS+=$(set_prop_value "${pkg_type}.architecture" "${arch}")
    PROPS+=$(set_prop_value "${pkg_type}.component" "${component_name}")
}

# Uploads file ARTIFACTORY_PATH
# Relies on global variables: DIST, ARCH, ARTIFACTORY_TOKEN, ARTIFACTORY_PATH
upload_file() {
    local dist=$1
    local arch=$2
    local file=$3

    # TODO: These should be set by envvars
    local artifactory_host="urm.nvidia.com"
    local artifactory_repo="$(get_artifactory_repository $dist)"

    if [ ! -r "${file}" ]; then
        echo "ERROR: File not found or not readable: ${file}"
        exit 1
    fi

    local PROPS
    process_props "${dist}" "${arch}" "${file}"

    # Collect sum
    SHA1_SUM=$(sha1sum -b "${file}" | awk '{ print $1 }')

    url="https://${artifactory_host}/artifactory/${artifactory_repo}/${dist}/${arch}/$(basename "${file}")"
    # NOTE: The URL to set the properties through the API is:
    # "https://${artifactory_host}/artifactory/api/storage/${artifactory_repo}/${dist}/${arch}/$(basename ${file})"

    echo "Uploading ${file} to ${url}"
    if ! ${CURL} -f \
          -H "X-JFrog-Art-Api: ${ARTIFACTORY_TOKEN}" \
          -H "X-Checksum-Sha1: ${SHA1_SUM}" \
          ${file:+-T ${file}} -X PUT \
            "${url};${PROPS}" ;
        then
            echo "ERROR: upload file failed: ${file}"
            exit 1
    fi
}

function push-artifactory() {
    local dist="$1"
    local arch="$2"

    source="${ARTIFACTS_DIR}/packages/${dist}/${arch}"

    find "${source}" -maxdepth 1 | while read -r f ; do
        upload_file "$dist" "$arch" "$f"
    done
}

# TODO: use this to adapt as a general purpose command-line tool
# case "${COMMAND}" in
#   set)
#     set_props
#     ;;
#   upload)
#     if [ -z "${UPLOAD_FILE}" ]; then
#       echo "ERROR: Upload package filename must be set using -f"
#       usage
#     fi
#
#     upload_file
#     ;;
#   *)
#     echo "ERROR: Invalid command ${COMMAND}"
#     usage
#     ;;
# esac

push-artifactory "${DIST}" "${ARCH}"