#!/bin/sh
# ------------------------------------------------------------------------------
#
# git-qimport.sh: Implement the Git-MQ "git qimport" extension command.
#
# Import third party patches, reinstate previously deleted patches, (for
# which a patch file remains available), or create patches from existing
# commits, moving them to the managed patch queue.
#
# $Id$
#
# ------------------------------------------------------------------------------
#
mq_facility="git qimport"
#
# I'd have liked to call this a "SYNOPSIS", (which is what it is), but git's
# git-sh-setup script requires the much less appropriate name "OPTIONS_SPEC",
# (which describes only a small subset of its actual content).
#
OPTIONS_SPEC="\
git qimport [-efP] [-n <name>] [[-r <rev>] ...] [[<patch-file>] ...]

Add new, or existing unregistered patches to the series, and/or convert
existing committed revisions to patches; converted revisions, which must
be contiguous with the first applied patch, are inserted as new patches,
considered as applied, at the start of the patch series; in other cases,
newly imported patches are inserted, but normally not applied, after the
topmost applied patch (if any) in the series.
--
e,existing!  register existing patch directory files
f,force!     overwrite existing files in the patch directory
n,name=!     set imported name; (may differ from <patch-file>)
r,rev=!      existing revision, or revision range to convert
P,push!      apply new patch(es), after import"
#
# ------------------------------------------------------------------------------
#
# $Id$
#
# Written by Keith Marshall <keith@users.osdn.me>
# Copyright (C) 2018-2020, 2022, 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/>.
#
# ------------------------------------------------------------------------------
#
# Although they may not always have any effect, all Git-MQ commands, like
# their hg counterparts, are expected to accept the global verbosity, and
# colour control options; ensure that they are declared:
#
OPTIONS_SPEC="$OPTIONS_SPEC
colour?*     generic output colour control -- may have no effect"
${OPTION_VERBOSE_DEFINED-false} || OPTIONS_SPEC="$OPTIONS_SPEC
v,verbose!*  generic verbosity selector -- may have no effect"

# For Git-MQ options, such as "--colour", we prefer a spelling convention
# which conforms to "World English" standards; however, git itself adopts
# "US English" convention.  Thus, we must also accommodate users who will
# specify "--color" instead of "--colour", without creating any ambiguity
# in the possible abbreviations; to achieve this, we check for "--color",
# among the command-line arguments, replacing it with "--colour", BEFORE
# we allow git to parse them.
#
for mq_argv
do case "$mq_argv" in
     --color*) mq_argv=`echo $mq_argv | sed 's/^--colo/&u/'` ;;
     --no-color) mq_argv="--no-colour" ;;
   esac
   ${mq_argv_init-true} && { set -- "$mq_argv"; mq_argv_init=false
   } || set -- "$@" "$mq_argv"
done

# Now, we may let git parse the command line, and set up its shell script
# processing environment, for use within a git working directory tree.
#
SUBDIRECTORY_OK=true . "`git --exec-path`/git-sh-setup" && require_work_tree

libexecdir=`dirname "$0"`
test `basename "$libexecdir"` = bin && libexecdir=`dirname "$libexecdir"`
libexecdir="$libexecdir/libexec/git-mq/${VERSION=1.0}"

mq_require(){ test -f "$1" || die "fatal: '$1' not found."; . "$1"; }
mq_require "$libexecdir/git-mq-setup.sh"

# Process any options which the user may have specified on the command
# line; shift them out of the way, leaving only non-option arguments.
#
while git_mq_getopt "$@"
do case $1 in
     -n) mq_patchname="$2"; shift ;;
     -r) mq_collect mq_rev_list "'$2'"; shift ;;
     -e) mq_import_existing=true ;;
     -f) mq_allow_overwrite=true ;;
     -P) mq_push_on_import=true ;;
   esac; shift
done

# Before proceeding any further, we must verify the integrity of the
# patch queue; if any patches have been applied, then the "qtip" tag
# MUST refer to the HEAD commit.
#
mq_require git-mq-integrity-check fatal qtip HEAD

# Check for possible violation of restrictions on usage of options.
#
mq_check_arg_limit() {
  test $# -gt 1 && test "${mq_patchname+set}" = set &&
  mq_abort 2 "error: option '-n' not allowed when importing multiple patches"
}
eval mq_check_arg_limit '"$@"' $mq_rev_list

# We will need access to the patch queue "series", and "status" files,
# but we have no need to refer to the "guards" file; the patch queue
# directory MUST already exist, before we can proceed any further!
#
test -d "$mq_patchdir" || mkdir -p "$mq_patchdir"
mq_map_control_file_refs "$mq_patchdir" series status

# Before processing any residual command arguments, we must handle
# any specified conversions of existing non-patch commit objects, to
# manage them as Git-MQ patches; in common with subsequent argument
# processing, this requires the use of temporary files.
#
mq_require mq-tmpfile
${mq_rev_list+mq_require git-rev-import $mq_rev_list}

# Any residual arguments should name patches for import.  We process
# these in two passes; in the first, we check that the specified patch
# files actually exist, that their names do not conflict with patches
# which are already named in the "series" file, and that, unless the
# user has indicated intent to overwrite, or to import patches which
# already exist there, that no similarly named files are present in
# the patch directory.
#
for mq_srcname
do mq_destname=${mq_patchname-`basename "$mq_srcname"`}
   test -f "$mq_series_file" && {
     awk '$1 == "'"$mq_destname"'" {exit 1}' "$mq_series_file" || {
       mq_abort 2 "error: '$mq_destname' is already in the patch series"
     }
   }
   ${mq_import_existing-false} && {
     test -f "$mq_patchdir/$mq_destname" || ${mq_allow_overwrite-false} || {
       mq_abort 2 "error: patch '$mq_destname' already exists"
     }
     mq_srcname="$mq_patchdir/"`basename "$mq_srcname"`
   }
   test -f "$mq_srcname" || {
     ${mq_import_existing-false} && mq_srcname=`basename "$mq_srcname"`
     mq_abort 2 "error: patch '$mq_srcname' does not exist"
   }
done

mq_tmpfile mq_series_file_tmp '`mktemp --tmpdir="$mq_patchdir"` ||
  $fatal "cannot establish series file update cache"'

exec 5>&1
for mq_srcname
do mq_destname=${mq_patchname-`basename "$mq_srcname"`}
   ${mq_import_existing-false} &&
   test `basename "$mq_srcname"` = "$mq_destname" || {
     cp "$mq_srcname" "$mq_patchdir/$mq_destname"
   }
   echo >&5 "$mq_facility: adding '$mq_destname' to the patch series"
   echo "$mq_destname"
done | awk "$mq_series $mq_status"' END {
  series_file = "'"$mq_series_file_tmp"'";
  if( (entries > 0) && (applied >= 0) )
    for( idx = 0; applied >= idx; idx++ ) print series[idx] > series_file;
  while( ("cat" | getline) > 0 ) print > series_file;
  while( idx < entries ) print series[idx++] > series_file;
}' "$mq_series_file" "$mq_status_file"
mq_series_file="$mq_patchdir/series" mq_update mq_series_file

${mq_push_on_import-false} && {
# The '-P' option is in effect, so we must emulate the "git qpush"
# operation, for the imported patch sequence; this MUST be performed
# with the git root directory as current working directory, requires
# the patch series indexing helper functions, and since the series
# control file may have been created, as new on import, we remap
# the entire control file set, before proceeding.
#
  cd ${GIT_ROOT}
  mq_require mq-series-index
  mq_map_control_file_refs "$mq_patchdir" guards series status
  mq_require git-qpush-backend "$mq_destname"
}
#
# ------------------------------------------------------------------------------
# $RCSfile$: end of file
