# git-qpush-backend.sh
# ------------------------------------------------------------------------------
#
# Script to handle the "git qpush" operation, either when invoked directly,
# or on behalf of any other command which must apply patches to the stack.
#
# ------------------------------------------------------------------------------
#
# $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/>.
#
# ------------------------------------------------------------------------------
#
# When invoked with the "-v" (a.k.a. "--verbose") option, then we must
# set up some additional "git qpush" progress reporting hooks.
#
  test ${mq_function_why_guarded+set} || mq_require mq-why-guarded
  if ${mq_verbose-false}
  then
    mq_push_report_if_guarded='
      else if( state[$1] == "G" )
	print why_guarded( skipping $1 "\47 -- guarded by" );'
    mq_push_verbose_report='skipping = "'"$mq_facility"': skipping \47"; '
  else
    mq_filter='2>&1 | grep -v -e \47^Checking\47 -e \47^Applied .* cleanly\47'
  fi

# Unless already set, e.g. by the "qselect --reapply" driver command,
# ensure that the diagnostic text, which is to be used when reporting
# a guarded destination request, is appropriately defined.
#
  mq_cannot_push="$mq_facility: ${mq_cannot_push-error: cannot push}"
  mq_guarded_by="$mq_facility: ${mq_guarded_by-error: it is guarded by}"

# The actual "git qpush" operation is implemented by means of this dynamically
# generated awk script, operating on the guards, series, and status files, in
# conjunction with the git repository and associated patch files.
#
  mq_commit="git commit --quiet --no-verify"
  awk "$mq_guards $mq_series $mq_status
    $mq_function_why_guarded $mq_error_handler"' END {
    $0 = target = "'"$1"'"; apply_all = entries - 1;
    if( apply_all == (idxinit = applied) ) apply_all = "";
    if( NF == 0 ) $0 = '"${mq_push_pop_all+apply_all}"' "";
    applied_msg = "the patch series is already fully applied";
    if( (NF == 0) && (($0 = applied + 1) >= entries) )
      errout( "error", applied_msg );'"
    $mq_series_index_lookup"'if( (idfinal = entry[$1]) == applied )
      errout( "error", "\47" $1 "\47 is already the topmost applied patch" );
    if( idfinal < applied )
      errout( "error", "cannot push backwards to patch \47" $1 "\47" );
    if( target && (state[$1] == "G") )
    { fault = "'"$mq_cannot_push"'"; $0 = series[idfinal];
      reason = why_guarded( "'"$mq_guarded_by"'" );
      printf "%s \47%s\47\n%s\n", fault, $1, reason;
      exit 2;
    }'"$mq_assert"'if( applied < 0 )
      system( "git tag qparent 2> /dev/null >&2" );
    do { $0 = series[idx = idfinal]; if( state[$1] == "G" ) ++idfinal;
       } while( (idfinal > idx) && (idfinal < entries) );
    git_apply = "git apply --index --reject \47'"$mq_patchdir"'/";
    '"$mq_push_verbose_report"'for( idx = applied; idx < idfinal; )
    { $0 = series[++idx]; if( state[$1] == "U" )
      { print "'"$mq_facility"': applying patch \47" $1 "\47";
	system( git_apply $1 "\47 '"$mq_filter"'" );
	git_qheader = "echo \47[Git-MQ]: " $1 "\47";
	git_qheader_validator = "git qheader \47" $1 "\47";
	while( (git_qheader_validator | getline) > 0 )
	  if( NF > 0 ) { git_qheader = git_qheader_validator; break; }
	close( git_qheader_validator ); $0 = series[idx];
	system( git_qheader " | '"$mq_commit"' -F- --allow-empty" );
	system( "git show --no-patch --format=\47%H:" $1 \
	    "\47 >> '"$mq_patchdir"'/status" \
	  );
	system( "git tag > /dev/null " $1 );
	if( applied < 0 ) system( "git tag qbase 2> /dev/null >&2" );
	applied = idx;
      }'"$mq_push_report_if_guarded"'
    }
    if( applied >= 0 )
    { if( applied > idxinit ) system( "git tag --force qtip > /dev/null" );
      if( $1 ) applied_msg = "\47" $1 "\47 is now the topmost applied patch.";
      print "'"$mq_facility"':", applied_msg;
    }
  }' "$mq_guards_file" "$mq_series_file" "$mq_status_file"
#
# ------------------------------------------------------------------------------
# $RCSfile$: end of file
