# git-qgoto-init.sh
# ------------------------------------------------------------------------------
#
# Initialization script to handle the common set up elements of execution
# for each of the git-qgoto, git-qpush, and git-qpop commands.
#
# ------------------------------------------------------------------------------
#
# $Id$
#
# Written by Keith Marshall <keith@users.osdn.me>
# Copyright (C) 2019, Keith Marshall
#
#
# This file is part of the Git-MQ program suite.
#
# The Git-MQ program suite is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public Licence
# as published by the Free Software Foundation, either version 3 of
# the Licence, or (at your option) any later version.
#
# The Git-MQ program suite is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public Licence for more details.
#
# You should have received a copy of the GNU General Public Licence
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
# ------------------------------------------------------------------------------
#
# Parse any command line options, which the user may have specified;
# the git_mq_getopt function will implicitly handle the default global
# options, but we must explicitly handle command specific effects.
#
  while git_mq_getopt "$@"
  do case $1 in
       --no-backup)    mq_push_pop_backup=false ;;
       --keep-changes) mq_push_pop_keep_changes=true ;;
       --move)         mq_argc_check="eq" mq_push_reorder=true ;;

	-a) mq_argc_check="lt" mq_push_pop_all=true ;;
	-f) mq_push_pop_discard_changes=true ;;
	-v) mq_verbose=true ;;
     esac
     shift
  done

# After option processing, only zero or one arguments are permitted.
#
  test $# -gt 1 && { printf >&2 "%s\n" "error: too many arguments"; usage; }

# Set up functions to kill the process, in the event that incompatible
# options are specified, an unwanted patch reference argument is given,
# or a required patch reference argument is omitted.
#
  mq_die_if(){
    eval \${$1-false} && { printf >&2 "%s\n" "error: $2"; usage; }
  }
  mq_die_if_push_all_reorder(){
    ${mq_push_pop_all-false} && mq_die_if mq_push_reorder "$1"
  }

# In the case of the "git qgoto" command, irrespective of options,
# exactly one destination patch reference argument is required.
#
  case $0 in *git-qgoto) mq_argc_check="eq" mq_goto_nowhere=true ;; esac

# Check specified options are consistent, and that argument requirements
# are satisfied; abort if not.
#
  mq_incompatible(){ echo  "option '$1' is incompatible with option '$2'"; }
  ${mq_push_pop_discard_changes-false} && {
    mq_disallowed=`mq_incompatible '--force' '--keep-changes'`
    mq_die_if mq_push_pop_keep_changes "$mq_disallowed"
  }
  test $# -${mq_argc_check-"le"} 1 || {
    mq_need_patch_reference="requires a patch reference argument"
    mq_die_if mq_goto_nowhere "action 'qgoto' $mq_need_patch_reference"
    mq_die_if mq_push_pop_all "patch reference '$1' not allowed with option '-a'"
    mq_die_if mq_push_reorder "option '--move' $mq_need_patch_reference"
  }
  mq_die_if_push_all_reorder "`mq_incompatible '-a' '--move'`"

# Any command using this initialization code must be run directly
# within the top level directory of the working repository tree.
#
  cd "$GIT_ROOT"

# Set up references for the patch series control files; abort if the
# directory, in which these should be found, is not present.
#
  test -d "$mq_patchdir" || $fatal "there is no active patch series"
  mq_map_control_file_refs "$mq_patchdir" guards series status

# If any patches have been applied, there should be no other commits
# following them, which are not themselves managed as patches; while
# Mercurial would not allow violation of this constraint, git offers
# no mechanism to allow us to enforce it, so we verify that the HEAD
# commit refers to the topmost applied patch, which is identified by
# the qtip tag, if any, and abort if these disagree.
#
  mq_require git-mq-integrity-check fatal qtip HEAD

# Pushing, or popping changesets may overwrite locally modified files;
# we must check for, and safeguard any such files, before proceeding.
#
# FIXME: Is there a better way to handle this?
# Git's index creates a layer of complexity, which is not evident in
# Mercurial's mq implementation; staged, but uncommitted changes will
# get in the way of any patch queue push, or pop operation.  What is
# the best way to handle them?  For now, we decline to proceed, and
# leave the user to resolve the issue.
#
  mq_require git-mq-cache-check || {
    mq_complain "warning: operation unsupported in current cache state;"
    mq_abort 2 "error: there are staged, but uncommitted changes."
  }

# FIXME: We have yet to devise a strategy for implementation of this:
#
  ${mq_push_pop_keep_changes-false} &&
    mq_abort 2 "fixme: '--keep-changes' option yet to be implemented"

# OTOH, we can tolerate local changes which have not yet been staged;
# by default, we create backup copies of modified files, initially in
# a temporary backup directory, ultimately restoring any which become
# overwritten, in place, with a ".orig" file name suffix.
# 
  git diff-files --quiet --ignore-submodules || {
    ${mq_push_pop_discard_changes-false} && {
      ${mq_push_pop_backup-true} && {
	mq_tmpdir=`mktemp -d` || mq_abort 2 "fatal: cannot create backup"
	mq_backup_store(){ mq_backup_files $@ | (cd $mq_tmpdir && tar xf -); }
	mq_backup_files(){ eval tar chf - `"$@" | awk '{print "\47"$0"\47"}'`; }
	mq_backup_store git diff-files --name-only --ignore-submodules

	mq_require mq-atexit "mq_backup_restore $mq_tmpdir .orig"
	mq_backup_restore(){ local F mq_tmpdir="$1" mq_ext="$2"
	  cd "$1"; eval set -- `find -type f | awk '{print "\47"$0"\47"}'`
	  for F; do test -f "$GIT_ROOT/$F" && cmp -s "$F" "$GIT_ROOT/$F" ||
	    cp "$F" "$GIT_ROOT/$F$mq_ext"
	  done
	  cd "$GIT_ROOT" && rm -rf "$mq_tmpdir"
	}
      }
    } || {
      mq_assert='errout( "error", "there are local changes; refresh first" );'
    }
  }

# Prepare the patch series indexing interface, before relinquishing
# control back to the client program.
#
  mq_require mq-series-index
#
# ------------------------------------------------------------------------------
# $RCSfile$: end of file
