bsd-doc-import.ksh (snapshot import script)

Giorgos Keramidas keramida at ceid.upatras.gr
Fri Feb 1 04:09:43 EET 2008


Καλησπέρα,

Το script που ακολουθεί το έγραψα απόψε, για να αυτοματοποιήσω κάπως τη
διαδικασία του 'import' ενός 'clean' snapshot από το /home/ncvs/doc του
τοπικού CVSup μου, σε ένα hg workspace.

Η χρήση είναι απλή:

    % ./bsd-doc-import.ksh ~/hg/doc/bsd-import

Στο ~/hg/doc/bsd-import έχω ένα clone από το

    http://hg.hellug.gr/freebsd/doc/

που χρησιμοποιείται *μόνο* για τα imports.  Δε γίνεται απευθείας commit
σε αυτό από μένα, και δεν γίνεται απευθείας push στο `hg.hellug.gr'.

Οταν τελειώσει ένα επιτυχημένο import, κάνω κάτι σαν:

    % cd ~/hg/doc/bsd
    % hg pull ../bsd-import
    % rm -fr * ; hg up -C
    % cd en_US.ISO8859-1 && make FORMATS=html-split

Κι αν πετύχει αυτό, τότε κάνω push από το ~/hg/doc/bsd στο online clone
στη διεύθυνση http://hg.hellug.gr/freebsd/doc/

Τυπικά μπορεί να αυτοματοποιηθεί και το build check, αλλά απόψε είναι
πολύ αργά πια για τέτοια.

Ακολουθεί το importer script, μήπως φανεί και σε άλλον χρήσιμο...

----- begin bsd-doc-import.ksh -----
#!/usr/bin/ksh -p
#
# Copyright (c) 2008 Giorgos Keramidas <keramida at FreeBSD.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

#
# This script can be run from cron to periodically import snapshots of
# the FreeBSD doc/ tree into a target Mercurial repository.  The target
# repository can be specified either as a command-line argument, or as
# the local filesystem path pointed at by GATEREPO.
#

# ==================== basic script startup ==================================

# Save the original program invocation name, and the real path of the
# startup directory, for later use.
progname=$(basename "$0")
progdir=$( cd $(dirname "$0") ; /bin/pwd -P )

# If TMPDIR is not set, use /tmp as a safe fallback value.
TMPDIR="${TMPDIR:-/var/tmp}"
export TMPDIR

# ==================== useful script functions ===============================

#
# err exitval [message ...]
#	Display message to stderr and log to the syslog, and exit with
#	exitval as the return code of the script.
#
function err
{
        exitval=$1
        shift

        log "${progname}: ERROR: $*"
        exit "${exitval:-1}"
}

#
# warn [message ...]
#	Display message to stderr and the log file, if any.
#
function warn
{
	log "${progname}: WARNING: $*"
}

#
# info [message ...]
#	Display informational message to stdout and to the logfile,
#	if one is defined.
#
function info
{
	log "${progname}: INFO: $*"
}

#
# debug [message ...]
#	Output message to stderr if debug_output_enabled is set to
#	'yes', 'true' or '1'.  Please AVOID calling any shell
#	subroutine that may recursively call debug().
#
function debug
{
	case ${debug_output_enabled} in
	[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1)
		log "${progname}: DEBUG: $*"
		;;
	esac
}

#
# log [message ...]
#	Display time-stamped message and log it to "${LOGFILE}",
#	if one is defined.
#
function log
{
	__timestamp="`date -u '+%Y-%m-%d %H:%M:%S'`"
	print -u2 "${__timestamp} -- $*"
	if [ -n "${LOGFILE}" ]; then
		print "${__timestamp} -- $*" >> "${LOGFILE}"
	fi
}

#
# msg [message ...]
#	Display message and log it to "${LOGFILE}", if one is defined.
#
function msg
{
	print -u2 "$*"
	if [ -n "${LOGFILE}" ]; then
		print "$*" >> "${LOGFILE}"
	fi
}

#
# compat_realpath $directory
#	Use /bin/pwd to determine the real path of a directory, or print
#	a warning and return non-zero.
#
function compat_realpath
{
	dpath="$1"
	if [ -z "${dpath}" ]; then
		warn "compat_realpath: missing path."
		return 1
	fi

	( cd "${dpath}" ; /bin/pwd -P ) 2>/dev/null
	if [ $? -ne 0 ]; then
		warn "${dpath}: cannot determine real path."
		return 1
	fi

	return 0
}

# ==================== gate repository related functions =====================

#
# repo_hg_root
#	Find the root of a Mercurial workspace (if it is a real Mercurial
#	workspace), or return a non-zero status.
#
function repo_hg_root
{
	repo="$1"

	if [ -z "${repo}" ]; then
		warn "Empty gate repository path."
		return 1
	fi

	savedir=$( /bin/pwd -P )

	log "Switching to repo at ${repo}"
	cd "${repo}"
	if [ $? -ne 0 ]; then
		warn "${repo}: cannot change into directory."
		cd "${savedir}"
		return 1
	fi

	log "Locating hg root of ${repo}"
	root=$( hg root 2>/dev/null )
	if [ -z "${root}" ]; then
		warn "${repo}: cannot locate hg root"
		cd "${savedir}"
		return 1
	fi
	realrepo=$( compat_realpath "${repo}" ) || return 1
	realroot=$( compat_realpath "${root}" ) || return 1
	if [ ! "${realrepo}" = "${realroot}" ]; then
		warn "${repo}: Switching to real hg root at ${realroot}"
		realrepo="${realroot}"
		repo="${realroot}"
	fi

	# All seems fine; try to restore the working dir.
	cd "${savedir}" || return 1
	print "${repo}"
	return 0
}

#
# repo_hg_import_clean $repo
#	Clean all the files in a Mercurial workspace, but set the 'parent' of
#	the workspace to the 'default' branch, in preparation for a new import.
#
function repo_hg_import_clean
{
	repo="$1"
	if [ -z "${repo}" ]; then
		warn "Empty gate repository path."
		return 1
	fi

	savedir=$( /bin/pwd -P )

	repo=$( repo_hg_root "${repo}" )
	if [ $? -ne 0 ]; then
		cd "${savedir}"
		return 1
	fi

	log "Cleaning up workspace at ${repo} for a new import"
	( cd "${repo}" && hg up -C default && rm -fr * && \
	    hg debugsetparent default )
	if [ $? -ne 0 ]; then
		warn "Failed to clean workspace at ${repo} for a new import"
		cd "${savedir}"
		return 1
	fi

	cd "${savedir}" || return 1
	return 0
}

#
# repo_cvs_import_checkout "${repo}"
#	Check out a new partial snapshot of the doc/ tree from CVS, which
#	contains only the sub-modules/parts of the doc tree that we are
#	interested in.
#
function repo_cvs_import_checkout
{
	repo="$1"
	if [ -z "${repo}" ]; then
		warn "Empty gate repository path."
		return 1
	fi

	savedir=$( /bin/pwd -P )

	repo=$( repo_hg_root "${repo}" )
	if [ $? -ne 0 ]; then
		cd "${savedir}"
		return 1
	fi

	log "Checking out a new snapshot of the doc/ tree at ${repo}"
	( cd "${repo}" && \
	    cvs -QR -d /home/ncvs co -d . -l doc && \
	    cvs -QR -d /home/ncvs update -APd * share en_US.ISO8859-1 \
		el_GR.ISO8859-7 )
	if [ $? -ne 0 ]; then
		warn "CVS checkout of doc/ snapshot failed at ${repo}"
		cd "${savedir}"
		return 1
	fi

	cd "${savedir}" || return 1
	return 0
}

#
# repo_cvs_stamp [file ...]
#	Find the timestamp of the last CVS commit, and print the time in
#	ISO date format to stdout.  This runs 'cvs log' on all the files
#	passed as arguments to the timestamp function, so it may take
#	quite a while on *HUGE* CVS trees.
#
function repo_cvs_stamp
{
	cvs -qR log "$@" | \
	    grep '^date: [0-9][0-9]*/.*state: Exp;  lines:.*' | \
	    awk '{print $2,$3}' | sort -n | tail -1 | \
	    sed -e 's@/@- at g' -e 's/;//' -e 's/$/ +0000/'
}

#
# repo_validate $repo
#	Validate that our only argument is the root path of a valid
#	Mercurial workspace, or at least *part* of a valid Mercurial
#	workspace, and that the workspace passes 'hg verify' checks.
#
function repo_validate
{
	repo="$1"
	if [ -z "${repo}" ]; then
		warn "Empty gate repository path."
		return 1
	fi

	savedir=$( /bin/pwd -P )

	repo=$( repo_hg_root "${repo}" )
	if [ $? -ne 0 ]; then
		cd "${savedir}"
		return 1
	fi

	log "Verifying hg workspace at ${repo}"
	log "This may take a bit..."
	hg verify
	if [ $? -ne 0 ]; then
		warn "Workspace verify failed at ${repo}"
		cd "${savedir}"
		return 1
	fi

	# All seems fine; try to restore the working dir.
	cd "${savedir}" || return 1
	return 0
}

#
# repo_import $repo
#	Import a fresh snapshot of the FreeBSD doc/ tree we use for the
#	Greek translation project into the Mercurial repository at $repo.
#
function repo_import
{
	repo="$1"
	if [ -z "${repo}" ]; then
		warn "Empty gate repository path."
		return 1
	fi

	savedir=$( /bin/pwd -P )

	repo=$( repo_hg_root "${repo}" )
	if [ $? -ne 0 ]; then
		cd "${savedir}"
		return 1
	fi

	repo_hg_import_clean "${repo}"
	if [ $? -ne 0 ]; then
		warn "Failed to clean workspace at ${repo}"
		cd "${savedir}"
		return 1
	fi

	repo_cvs_import_checkout "${repo}"
	if [ $? -ne 0 ] ; then
		repo_hg_import_clean "${repo}"
		cd "${savedir}"
		return 1
	fi

	#
	# Try out best shot at guessing the time of the last CVS commit in the
	# partial checkout at ${repo}.
	#
	log "Guesstimating the timestamp of the last CVS commit at ${repo}"
	stamp=$( cd "${repo}" ; repo_cvs_stamp * )
	if [ $? -ne 0 ]; then
		warn "Failed to find CVS timestamp."
		repo_hg_import_clean "${repo}"
		cd "${savedir}"
		return 1
	else
		log "CVS timestamp = ${stamp}"
	fi

	log "Removing CVS/ metadata subdirs at ${repo}"
	( cd "${repo}" ; find * -type d -name CVS -exec rm -r {} + )
	if [ $? -ne 0 ]; then
		warn "Failed to delete CVS/ subdirs at ${repo}"
		repo_hg_import_clean "${repo}"
		cd "${savedir}"
		return 1
	fi

	log "Pre-import workspace status at ${repo}"
	( cd "${repo}" && hg status )
	if [ $? -ne 0 ]; then
		warn "hg status failed at ${repo}"
		repo_hg_import_clean "${repo}"
		cd "${savedir}"
		return 1
	fi

	log "Hg addremoving at ${repo}"
	( cd "${repo}" && hg addremove )
	if [ $? -ne 0 ]; then
		warn "hg addremove failed at ${repo}"
		repo_hg_import_clean "${repo}"
		cd "${savedir}"
		return 1
	fi

	log "Committing new import in ${repo}"
	( cd "${repo}" && hg commit -u ncvs -d "${stamp}" \
	    -m "Import FreeBSD doc/ snapshot at ${stamp}" )
	if [ $? -ne 0 ]; then
		warn "Commit error in ${repo}"
		repo_hg_import_clean "${repo}"
		cd "${savedir}"
		return 1
	fi

	return 0
}

# ==================== main script body ======================================

function usage
{
	print -u2 "usage: ${progname} [gaterepo]"
	exit 1
}

# Start with an invalid ${GATEREPO} at first, unless it is already set
# to something in our startup environment.
GATEREPO="${GATEREPO:-/dev/null}"
if [ $# -gt 1 ]; then
	usage ; exit 1
fi
if [ $# -eq 1 ]; then
	GATEREPO="$1"
fi
if [ "${GATEREPO}" = ' /dev/null' ]; then
	usage ; exit 1
fi

log "Validating GATEREPO at ${GATEREPO}"
repo_validate "${GATEREPO}" || err 1 "Abort."

log "Importing new bsd doc snapshot at ${GATEREPO}"
repo_import "${GATEREPO}" || err 1 "Abort."

log "Done."
exit 0
----- end bsd-doc-import.ksh -----




More information about the Freebsd-doc-el mailing list