# hg.sh
# ------------------------------------------------------------------------------
#
# mingw-pkg plug-in to facilitate the use of mercurial for tracking of changes
# made to the upstream package code, and generation of patch-sets, as required
# for building with MinGW, and for creation of MinGW source distributables.
#
# ------------------------------------------------------------------------------
#
# $Id: hg.sh,v 8cf2344bbd55 2020/01/07 20:53:10 keith $
#
# Written by Keith Marshall <keith@users.osdn.me>
# Copyright (C) 2011-2013, 2016-2019, MinGW.org Project
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ------------------------------------------------------------------------------
#
  ARCH_DEFAULT=${ARCH_DEFAULT-"mingw32"}
  STAGED_PKGROOT=${STAGED_PKGROOT-"`pwd`"}

# When running hg, on behalf of this plug-in, we may need to ensure that
# it is run in the top source directory; invoking it as $HG_CMD guarantees
# that this requirement is satisfied.
#
  HG_CMD='eval hg --cwd "$PACKAGE_ABS_SRCDIR"'

# The hg_plugin_initialize function hooks into the "mingw-pkg initialize"
# action, to set up the requisite hg repository whence any distributable
# package images will be constructed.  Note that this runs a sequence of
# hg commands within a sub-shell; changing the working directory for this
# sub-shell obviates the need to use $HG_CMD.
#
  defn_add_hook initialize plugin hg_plugin_initialize
  hg_plugin_initialize() {
    phase "initialize local mercurial repository"
    ( cd $PACKAGE_SRCDIR
      hg init
      step `hg branch origin | sed 1q`; echo
      cat > .hgignore <<-EOF
	syntax: glob
	.hgignore
	**.pkgspec
	**.patch
	build/
	dist/
	EOF
      hg add . > /dev/null
      hg commit -m "Initial import of upstream $PACKAGE-$VERSION."
      hg log
      step `hg branch master | sed 1q`; echo
      hg commit -m "Initialize master branch for upstream patches."
      hg log -l 1
      step `hg branch ${ARCH-"$ARCH_DEFAULT"} | sed 1q`; echo
    )
  }

# The hg_plugin_load_package_specs function overrides the default loader,
# to ensure that the default choice of package specs file location matches
# the build architecture specific directory which corresponds to the name
# of the active hg branch.
#
  action_load_package_specs() { hg_plugin_load_package_specs; }
  hg_plugin_load_package_specs() { action_prepare_package_specs
    test -f $PACKAGE_SRCDIR/arch/${ARCH="`$HG_CMD branch 2> /dev/null \
      || echo $ARCH_DEFAULT`"}/$PACKAGE-$VERSION-$ARCH.pkgspec && \
      . $PACKAGE_SRCDIR/arch/$ARCH/$PACKAGE-$VERSION-$ARCH.pkgspec
  }

# The hg_plugin_stage_srcdist function hooks the "mingw-pkg distribute"
# action, to take control of generating the source code package; it uses
# the content associated with the hg "origin" branch as the basis for the
# original source code, then adds the architecture specific files, and
# any applied patches, which must be managed by MQ.
#
  defn_set_hook stage_srcdist plugin hg_plugin_stage_srcdist
  hg_plugin_stage_srcdist() { local HG_ROOT=`$HG_CMD root`
    step "check source tree integrity"
    #
    # The "mingw-pkg distribute" action is not allowed to proceed, if
    # the source code repository is contaminated by untracked files, or
    # any uncommitted changes.
    #
    ( EXIT_CODE=0
      show_status() {
	warning "$1"; printf >&2 '%s\n\n' "$warning_colour$2$unbold"
      }
      untracked="`$HG_CMD status | grep '^?'`" && {
	show_status "untracked files in source tree..." "$untracked"
	${ignore_untracked_files-false} || EXIT_CODE=1
      }
      uncommitted="`$HG_CMD status | grep '^[AMR!]'`" && {
	show_status "locally modified files in source tree..." "$uncommitted"
	EXIT_CODE=1
      }
      exit $EXIT_CODE
    ) || die "source tree is not clean"

    # Provided the source repository is clean, we proceed to create
    # a staged image of its distributable content, which...
    #
    STAGED_PKGDIR=${STAGED_PKGDIR-"$STAGED_PKGROOT/dist"}
    STAGED_INSTALLDIR="$STAGED_PKGDIR/staged"
    rm -rf "${STAGED_SRCDIR=$STAGED_PKGDIR/$PACKAGE-$VERSION}"
    mkdir -p "$STAGED_SRCDIR/arch/${ARCH=`hg -R $HG_ROOT branch`}"
    ( cd "$HG_ROOT"
      ${MINGW_PORT_DISTRIBUTION-false} || {
      # ...in the case of a full distribution, is initially populated
      # with an image of the original (upstream) package content...
      #
	step "replicate original source tree"
	hg archive -r origin -X '.hg*' "$STAGED_SRCDIR"

	# ...subsequently adding any third party patches...
	#
	for patchfile in arch/any/*
	do test -f $patchfile && {
	     tar chf - --hard-dereference arch/any | (
	       cd "$STAGED_SRCDIR" && tar xf -
	     )
	     break
	   }
	done
      }

      # ...and, for either a full distribution, or a mingw-port,
      # any architecture specific files which we have added, (but
      # excluding any unmanaged patches)...
      #
      test -f arch/$ARCH/$PACKAGE-$VERSION-$ARCH.pkgspec && {
	echo; step "add mingw-pkg specific arch/$ARCH files"
	tar chf - --hard-dereference --exclude='*.patch' arch/$ARCH/* | (
	  cd "$STAGED_SRCDIR" && tar xvf -
	)
	# ...and finally, the sequence of applied MQ patches, if any.
	#
	local PATCHLIST="`hg qapplied --verbose 2> /dev/null`"
	test -n "$PATCHLIST" && {
	  echo; step "export locally applied patches"
	  local HG_PATCHDIR="$HG_ROOT/.hg/patches"
	  local STAGED_PATCHDIR="$STAGED_SRCDIR/arch/$ARCH"
	  rm -f "$STAGED_PATCHDIR"/*.patch
	  cd "$STAGED_PATCHDIR" && echo "$PATCHLIST" | awk '
	    $2 == "A" { patch[top = 1 + $1] = $3; }
	    END { if((width = 1 + int( log( top ) / log( 10 ))) < 2) width = 2;
	      cmd = "ln -fs \42'"$HG_PATCHDIR"'/%3$s\42 \42./%2$0*1$d-%3$s\42";
	      for( idx = 1; top >= idx; idx++ ) if( idx in patch )
	      { printf "%2$0*1$d-%3$s\n", width, idx, patch[idx];
		system( sprintf( cmd, width, idx, patch[idx] ) );
	      }
	    }
	  '
	}
      }
    )
  }
#
# ------------------------------------------------------------------------------
# $RCSfile: hg.sh,v $: end of file
