#!/bin/bash

# SPDX-FileCopyrightText: 2023 SUSE LLC
#
# SPDX-License-Identifier: Apache-2.0

function usage() {
cat << EOF
mkchlog - Create changelog entries for Uyuni packages

Usage: mkchlog [OPTIONS] [MESSAGE]

When called from a subdirectory of any Uyuni package, create a changelog file in
the following format:

    <package_name>.changes.<username>.<feature_name>

If not explicitly specified, fetch username and feature_name from git email's
username part and the current branch name.

With no MESSAGE, open a text editor for manual input.
The default editor can be specified by setting the EDITOR environment variable.

  -f, --feature         set the feature name to use as a filename part
  -u, --username        set the username to use as a filename part
  -r, --remove          remove existing changelog file
  -n, --no-wrap         do not wrap automatically the message at 67 characters
  -h, --help            display this help and exit

Uyuni project: <https://github.com/uyuni-project/uyuni>
EOF
}

# Out of the box macOS ships with BSD getopt which doesn't support long args
if [ "$(uname -s)" == "Darwin" ] && $(man getopt | grep -i -q "bsd"); then
    echo "Error: This tool requires GNU getopt, but your system is using BSD getopt. Please install GNU getopt and add it to your PATH."
    exit 1
fi

ARGS=$(getopt -n mkchlog -o rhnf:u: --long remove,help,no-wrap,feature:username: -- "$@")
if [ $? -ne 0 ]; then
    exit 1
fi

eval set -- "$ARGS"
while [ : ]; do
    case "$1" in
        -h|--help)
            usage
            exit
            ;;
        -f|--feature)
            FEATURE=$2
            shift 2
            ;;
        -u|--username)
            USER=$2
            shift 2
            ;;
        -r|--remove)
            REMOVE=1
            shift
            ;;
        -n|--no-wrap)
            NO_WRAP=1
            shift
            ;;
        --)
            shift
            break
            ;;
    esac
done

if ! command -v git &>/dev/null; then
    echo "Error: git is not available in your system."
    exit 1
fi

GITROOT=`git rev-parse --show-toplevel 2>/dev/null`
if [ $? -ne 0 ]; then
    echo "Error: not in a git repository."
    exit 1
fi
    
PKG_DIR=`ls -d $GITROOT/{.tito,rel-eng}/packages 2>/dev/null`
if [ -z "$PKG_DIR" ]; then
    echo "Error: Not in Uyuni working directory."
    exit 1
fi

CURDIR=`git rev-parse --show-prefix` || exit 1

if [ -z "$USER" ]; then
    GITMAIL=`git config --get user.email 2>/dev/null`
    if [ -n "$GITMAIL" ]; then
        USER=${GITMAIL%@*}
    else
        echo "Cannot read the username from git config. Omitting the username part."
    fi
fi

if [ -z "$FEATURE" ]; then
    FEATURE=`git rev-parse --abbrev-ref HEAD 2>/dev/null`
    if [ -z "$FEATURE" ] || [ "HEAD" == "$FEATURE" ]; then
        echo "Cannot read the branch name from the current HEAD. Omitting the feature name part."
        unset FEATURE
    fi
fi

if [ -z $USER ] && [ -z $FEATURE ]; then
    echo "Error: Neither username nor branch name could be read. Please specify the values using --feature and --username options or create a changelog file manually."
    exit 1
fi

# Returns the changelog file name in format <package>.changes.<username>.<feature>.
# Loops through the base directories of each package and tries to match one with the current directory.
# Returns 1 if no match found, which means the user is outside of a package directory.
function getChangelogFile() {
    for pkg in $(cat $PKG_DIR/* | cut -d' ' -f2)
    do
        if [ "$pkg" = "./" ]; then
            pkg=""
        fi

        if echo $CURDIR | grep -q "^$pkg"; then
            local chfile=$(ls $GITROOT/$pkg*.changes)
            echo $chfile${USER:+.$USER}${FEATURE:+.$FEATURE}
            return
        fi
    done
    exit 1
}

# Get user's default text editor, falling back to vi.
function getEditorCmd() {
    local cmd
    if [ -n "$EDITOR" ]; then
        cmd=$EDITOR
    elif command -v vim &>/dev/null; then
        cmd=vim
    else
        cmd=vi
    fi

    # Specific CLI options for common text editors
    case "$cmd" in
        vi*)
            cmd="$cmd +1 +startinsert!"
            ;;
        *)
            cmd="$cmd +1:3"
            ;;
    esac

    echo $cmd
}

CHFILE=$(getChangelogFile)
if [ $? -ne 0 ]; then
    echo "Error: Not in a package directory."
    exit 1
fi

# Remove option
if ! [ -z $REMOVE ]; then
    if [ -f $CHFILE ]; then
        git restore --staged $CHFILE 2>/dev/null
        rm $CHFILE 2>/dev/null
        exit
    else
        echo "Error: '$CHFILE' does not exist."
        exit 1
    fi
fi

# Add the new entry
if [ -z $NO_WRAP ]; then
    echo "$1" | fold -s -w 65 | sed '1s/^.*$/- &/;2,$s/^.*$/  &/' > $CHFILE.new
else
    echo "- $1" > $CHFILE.new
fi

# Append older entries
cat $CHFILE >> $CHFILE.new 2>/dev/null

# Open file for edit
if [ -z "$1" ]; then
    $(getEditorCmd) $CHFILE.new
fi

# Move file into place
if [ -s $CHFILE.new ]; then
    mv $CHFILE.new $CHFILE
    # Stage in git
    git add $CHFILE
else
    # Unstage and remove
    echo "No entries written. Discarding the changelog file."
    git restore --staged $CHFILE 2>/dev/null
    rm $CHFILE.new $CHFILE 2>/dev/null
fi
