--- /dev/null
+=========================
+Horde Administrator Tools
+=========================
+
+Introduction
+------------
+
+This directory contains various utility scripts for Horde administrators.
+
+
+Script Index
+------------
+
+horde-remove-prefs.php
+ Remove all entries of a preference name/scope combination from an
+ SQL prefs backend.
+
+horde-update.sh
+ Facilitates the updating and/or installation of horde and its
+ applications.
--- /dev/null
+<?php
+// Use the HORDE_BASE environment variable if it's set.
+if ((($base = getenv('HORDE_BASE')) ||
+ (!empty($_ENV['HORDE_BASE']) && $base = $_ENV['HORDE_BASE'])) &&
+ is_dir($base) && is_readable($base)) {
+ $horde_base = $base;
+} elseif (is_file(getcwd() . '/lib/core.php')) {
+ $horde_base = getcwd();
+} else {
+ $horde_base = dirname(dirname(dirname(__FILE__)));
+}
--- /dev/null
+#!@php_bin@
+<?php
+/**
+ * $Horde: framework/admintools/horde-create-sequence.php,v 1.9 2009/07/22 06:40:30 slusarz Exp $
+ *
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @package admintools
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ */
+
+// Do CLI checks and environment setup first.
+require_once dirname(__FILE__) . '/horde-base.php';
+require_once $horde_base . '/lib/core.php';
+
+// Make sure no one runs this from the web.
+if (!Horde_Cli::runningFromCLI()) {
+ exit("Must be run from the command line\n");
+}
+
+// Load the CLI environment - make sure there's no time limit, init
+// some variables, etc.
+$cli = Horde_Cli::singleton();
+$cli->init();
+
+// Include needed libraries.
+$horde_authentication = 'none';
+require_once HORDE_BASE . '/lib/base.php';
+
+$db_lib = 'DB';
+$sequence = null;
+if (isset($_SERVER['argv']) && count($_SERVER['argv']) >= 2) {
+ array_shift($_SERVER['argv']);
+ while ($arg = array_shift($_SERVER['argv'])) {
+ if ($arg == '--mdb2') {
+ $db_lib = 'MDB2';
+ } else {
+ $sequence = $arg;
+ }
+ }
+}
+if (is_null($sequence)) {
+ $sequence = $cli->prompt(_("What sequence do you want to create (_seq will be added automatically)?"));
+}
+
+switch ($db_lib) {
+case 'DB':
+ require_once 'DB.php';
+ $dbh = DB::connect($conf['sql']);
+ break;
+
+case 'MDB2':
+ require_once 'MDB2.php';
+ $params = $conf['sql'];
+ unset($params['charset']);
+ $dbh = MDB2::factory($params);
+ break;
+
+default:
+ throw new Horde_Exception('Unknown database abstraction library');
+}
+if (is_a($dbh, 'PEAR_Error')) {
+ throw new Horde_Exception($dbh);
+}
+
+if (!preg_match('/^\w+$/', $sequence)) {
+ $cli->fatal('Invalid sequence name');
+}
+
+switch ($db_lib) {
+case 'DB':
+ $result = $dbh->createSequence($sequence);
+ break;
+
+case 'MDB2':
+ $dbh->loadModule('Manager', null, true);
+ $result = $dbh->manager->createSequence($sequence);
+ break;
+}
+if (is_a($result, 'PEAR_Error')) {
+ $cli->fatal($result->getMessage());
+}
+
+$cli->green('Sequence created.');
+exit(0);
--- /dev/null
+#!@php_bin@
+<?php
+/**
+ * Dump the requested tables (or all) from the Horde database to XML data
+ * format.
+ *
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @category Horde
+ * @package admintools
+ */
+
+// Do CLI checks and environment setup first.
+require_once dirname(__FILE__) . '/horde-base.php';
+require_once $horde_base . '/lib/core.php';
+
+// Make sure no one runs this from the web.
+if (!Horde_Cli::runningFromCLI()) {
+ exit("Must be run from the command line\n");
+}
+
+// Load the CLI environment - make sure there's no time limit, init
+// some variables, etc.
+$cli = Horde_Cli::singleton();
+$cli->init();
+
+// Include needed libraries.
+$horde_authentication = 'none';
+require_once HORDE_BASE . '/lib/base.php';
+
+$manager = Horde_SQL_Manager::getInstance();
+if (is_a($manager, 'PEAR_Error')) {
+ $cli->fatal($manager->toString());
+}
+
+// Get rid of the script name
+array_shift($_SERVER['argv']);
+$tables = array_values($_SERVER['argv']);
+
+$result = $manager->dumpData('php://stdout', $tables);
+if (is_a($result, 'PEAR_Error')) {
+ $cli->fatal($result->toString());
+}
+
+exit(0);
--- /dev/null
+#!@php_bin@
+<?php
+/**
+ * Dump the requested tables (or all) from the Horde database to XML schema
+ * format.
+ *
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @category Horde
+ * @package admintools
+ */
+
+// Do CLI checks and environment setup first.
+require_once dirname(__FILE__) . '/horde-base.php';
+require_once $horde_base . '/lib/core.php';
+
+// Make sure no one runs this from the web.
+if (!Horde_Cli::runningFromCLI()) {
+ exit("Must be run from the command line\n");
+}
+
+// Load the CLI environment - make sure there's no time limit, init
+// some variables, etc.
+$cli = Horde_Cli::singleton();
+$cli->init();
+
+// Include needed libraries.
+$horde_authentication = 'none';
+require_once HORDE_BASE . '/lib/base.php';
+
+$manager = Horde_SQL_Manager::getInstance();
+if (is_a($manager, 'PEAR_Error')) {
+ $cli->fatal($manager->toString());
+}
+
+// Get rid of the script name
+array_shift($_SERVER['argv']);
+$tables = array_values($_SERVER['argv']);
+
+$xml = $manager->dumpSchema($tables);
+if (is_a($xml, 'PEAR_Error')) {
+ $cli->fatal($xml->toString());
+}
+
+echo $xml;
+exit(0);
--- /dev/null
+#!@php_bin@
+<?php
+/**
+ * Update database definitions from the given .xml data file.
+ *
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @category Horde
+ * @package admintools
+ */
+
+// Do CLI checks and environment setup first.
+require_once dirname(__FILE__) . '/horde-base.php';
+require_once $horde_base . '/lib/core.php';
+
+// Make sure no one runs this from the web.
+if (!Horde_Cli::runningFromCLI()) {
+ exit("Must be run from the command line\n");
+}
+
+// Load the CLI environment - make sure there's no time limit, init
+// some variables, etc.
+$cli = Horde_Cli::singleton();
+$cli->init();
+
+// Include needed libraries.
+$horde_authentication = 'none';
+require_once HORDE_BASE . '/lib/base.php';
+
+$manager = Horde_SQL_Manager::getInstance();
+if (is_a($manager, 'PEAR_Error')) {
+ $cli->fatal($manager->toString());
+}
+
+// Get arguments.
+array_shift($_SERVER['argv']);
+if (!count($_SERVER['argv'])) {
+ exit("You must specify the data file to update.\n");
+}
+$file = array_shift($_SERVER['argv']);
+$debug = count($_SERVER['argv']) && array_shift($_SERVER['argv']) == 'debug';
+
+$result = $manager->updateData($file, $debug);
+if (is_a($result, 'PEAR_Error')) {
+ $cli->fatal('Failed to update database data: ' . $result->toString());
+ exit(1);
+} elseif ($debug) {
+ echo $result;
+} else {
+ $cli->message('Successfully updated the database with data from "' . $file . '".', 'cli.success');
+}
+exit(0);
--- /dev/null
+#!@php_bin@
+<?php
+/**
+ * Update database definitions from the given .xml schema file.
+ *
+ * Copyright 2008-2009 The Horde Project (http://www.horde.org/)
+ *
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ * @category Horde
+ * @package admintools
+ */
+
+// Do CLI checks and environment setup first.
+require_once dirname(__FILE__) . '/horde-base.php';
+require_once $horde_base . '/lib/core.php';
+
+// Make sure no one runs this from the web.
+if (!Horde_Cli::runningFromCLI()) {
+ exit("Must be run from the command line\n");
+}
+
+// Load the CLI environment - make sure there's no time limit, init
+// some variables, etc.
+$cli = Horde_Cli::singleton();
+$cli->init();
+
+// Include needed libraries.
+$horde_authentication = 'none';
+require_once HORDE_BASE . '/lib/base.php';
+
+$manager = Horde_SQL_Manager::getInstance();
+if (is_a($manager, 'PEAR_Error')) {
+ $cli->fatal($manager->toString());
+}
+
+// Get arguments.
+array_shift($_SERVER['argv']);
+if (!count($_SERVER['argv'])) {
+ exit("You must specify the schema file to update.\n");
+}
+$file = array_shift($_SERVER['argv']);
+$debug = count($_SERVER['argv']) && array_shift($_SERVER['argv']) == 'debug';
+
+$result = $manager->updateSchema($file, $debug);
+if (is_a($result, 'PEAR_Error')) {
+ $cli->fatal('Failed to update database definitions: ' . $result->toString());
+ exit(1);
+} elseif ($debug) {
+ echo $result;
+} else {
+ $cli->message('Successfully updated the database with definitions from "' . $file . '".', 'cli.success');
+}
+exit(0);
--- /dev/null
+#!@php_bin@
+<?php
+/**
+ * $Horde: framework/admintools/horde-remove-pref.php,v 1.4 2009/07/22 06:40:30 slusarz Exp $
+ *
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * This script removes a pref from users' settings. Helps when a setting is
+ * to be moved from locked = false, to locked = true and there have already
+ * been prefs set by the users.
+ *
+ * @package admintools
+ */
+
+/**
+ ** Set this to true if you want DB modifications done.
+ **/
+$live = false;
+
+// Do CLI checks and environment setup first.
+require_once dirname(__FILE__) . '/horde-base.php';
+require_once $horde_base . '/lib/core.php';
+
+// Make sure no one runs this from the web.
+if (!Horde_Cli::runningFromCLI()) {
+ exit("Must be run from the command line\n");
+}
+
+// Load the CLI environment - make sure there's no time limit, init
+// some variables, etc.
+$cli = Horde_Cli::singleton();
+$cli->init();
+
+$horde_authentication = 'none';
+$horde_no_compress = true;
+require_once HORDE_BASE . '/lib/base.php';
+
+$scope = $cli->prompt(_("Enter value for pref_scope:"));
+$name = $cli->prompt(_("Enter value for pref_name:"));
+
+/* Open the database. */
+$db = DB::connect($conf['sql']);
+if (is_a($db, 'PEAR_Error')) {
+ var_dump($db);
+ exit;
+}
+
+// Set DB portability options.
+switch ($db->phptype) {
+case 'mssql':
+ $db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS | DB_PORTABILITY_RTRIM);
+ break;
+default:
+ $db->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
+}
+
+if ($live) {
+ $sql = 'DELETE FROM horde_prefs WHERE pref_scope = ? AND pref_name = ?';
+ $values = array($scope, $name);
+ $result = $db->getAll($sql, $values);
+ if (is_a($result, 'PEAR_Error')) {
+ var_dump($result);
+ } elseif (empty($result)) {
+ $cli->writeln(sprintf(_("No preference \"%s\" found in scope \"%s\"."), $name, $scope));
+ } else {
+ $cli->writeln(sprintf(_("Preferences \"%s\" deleted in scope \"%s\"."), $name, $scope));
+ }
+} else {
+ $sql = 'SELECT * FROM horde_prefs WHERE pref_scope = ? AND pref_name = ?';
+ $values = array($scope, $name);
+ $result = $db->getAll($sql, $values);
+ if (empty($result)) {
+ $cli->writeln(sprintf(_("No preference \"%s\" found in scope \"%s\"."), $name, $scope));
+ } else {
+ var_dump($result);
+ }
+}
--- /dev/null
+#!@php_bin@
+<?php
+/**
+ * $Horde: framework/admintools/horde-sql-shell.php,v 1.10 2009/07/22 06:40:30 slusarz Exp $
+ *
+ * Copyright 2007-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @package admintools
+ * @author Chuck Hagenbuch <chuck@horde.org>
+ */
+
+// Do CLI checks and environment setup first.
+require_once dirname(__FILE__) . '/horde-base.php';
+require_once $horde_base . '/lib/core.php';
+
+// Make sure no one runs this from the web.
+if (!Horde_Cli::runningFromCLI()) {
+ exit("Must be run from the command line\n");
+}
+
+// Load the CLI environment - make sure there's no time limit, init some
+// variables, etc.
+Horde_Cli::init();
+
+// Include needed libraries.
+$horde_authentication = 'none';
+require_once HORDE_BASE . '/lib/base.php';
+
+$dbh = DB::connect($conf['sql']);
+if (is_a($dbh, 'PEAR_Error')) {
+ throw new Horde_Exception($dbh);
+}
+$dbh->setOption('portability', DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS);
+
+// list databases command
+// $result = $dbh->getListOf('databases');
+
+// list tables command
+// $result = $dbh->getListOf('tables');
+
+// read sql file for statements to run
+$statements = new Horde_Db_StatementParser($_SERVER['argv'][1]);
+foreach ($statements as $stmt) {
+ echo "Running:\n " . preg_replace('/\s+/', ' ', $stmt) . "\n";
+ $result = $dbh->query($stmt);
+ if (is_a($result, 'PEAR_Error')) {
+ var_dump($result);
+ exit;
+ }
+
+ echo " ...done\n\n";
+}
--- /dev/null
+#!/bin/sh
+# $Horde: framework/admintools/horde-update.sh,v 1.1 2006/09/11 05:01:14 chuck Exp $
+#
+# update_horde.sh - Marcus I. Ryan <marcus@riboflavin.net>
+#
+# I wrote this script for me, so there isn't really much documentation.
+# I'll explain the few things that come to mind:
+#
+# Summary: This script facilitates the updating and/or installation of horde
+# and its applications.
+# * Create a temporary directory to hold a new install
+# * Make a patch file of the various *.dist files and their non-dist versions
+# * Copy the existing install or download fresh from CVS
+# * Apply the patch made earlier
+# * Make a backup of the existing install
+# * Make the new download the current install
+#
+# Options/Variables:
+# NUM_SLASHES - Since I'm too lazy to code a better way, this is the number
+# of slashes to remove from the path to make the patch work
+# relative to the temporary directory.
+# NUM_BACKUPS - How many backups do we want to keep?
+# WEBDIR - The actual install directory (this is the live version)
+# BACKUPDIR - Where do we want to keep the backups
+# TMPDIR - Where do we build the new version to install
+# RELEASES - A list of the various "releases" we've defined
+# <rel>_dir - The name of the "horde" dir (usually horde) for release <rel>
+# <rel>_ver - A list of the various CVS distributions for realease <ver>
+# and the CVS branches to download. See examples.
+#
+# WARNING: I do not currently have it set up to check if a patch fails
+# completely. This is not usually a problem, but if a *.dist file
+# is drastically updated it has been known to cause problems.
+# If you use this script, please keep an eye out for this. That
+# said, I updated both my installs (release and head) with it
+# over 50 times before I finally had a problem.
+
+trim () {
+ echo $@
+}
+
+######## CONFIGURATION ########
+
+### MISC. OPTIONS ###
+NUM_SLASHES=4
+NUM_BACKUPS=5
+
+### DIRECTORIES ###
+WEBDIR=/usr/local/www
+BACKUPDIR=/usr/local/src
+TMPDIR=/usr/local/src
+
+### RELEASES ###
+RELEASES="release head"
+
+# For each release, we need _dir and _ver settings
+
+#This is the "array" of applications and versions to get
+release_dir=horde
+release_ver="
+ horde-RELENG_2
+ imp-RELENG_3
+ turba-RELENG_1
+ kronolith-RELENG_1
+ nag-RELENG_1
+ mnemo-RELENG_1
+"
+release_ver=`trim ${release_ver}`
+
+head_dir=horde.head
+head_ver="
+ horde-HEAD
+ framework-HEAD
+ imp-HEAD
+ turba-HEAD
+ gollem-HEAD
+ kronolith-HEAD
+ jonah-HEAD
+ troll-HEAD
+ nag-HEAD
+ nic-HEAD
+ mnemo-HEAD
+ passwd-HEAD
+ sam-HEAD
+"
+head_ver=`trim ${head_ver}`
+
+######## MAIN CODE ########
+
+APPVER=$head_ver
+HORDEDIR=$head_dir
+
+# check to see if any command line args are specified
+for arg in $*
+do
+ name=${arg%%=*}
+ name=${name##--}
+ value=${arg##*=}
+ if [ "$name" = "release" ]; then
+ APPVER=`eval echo '$'$value'_ver'`
+ HORDEDIR=`eval echo '$'$value'_dir'`
+ if [ "$APPVER" = "" -o "$HORDEDIR" = "" ]; then
+ echo "ERROR: No settings for release $value"
+ fi
+ continue
+ fi
+ echo "Unknown option $arg ('$name' = '$value')"
+ exit 1
+done
+
+echo "Verifying distribution list"
+if [ ! "${APPVER%%[- ]*}" = "horde" ]; then
+ echo " horde MUST be the first item in the APPVER list!"
+ exit 1
+fi
+
+echo "Determining temporary directory..."
+EXISTS=`ls -d ${TMPDIR}/${HORDEDIR}.TMP.[0-9]* | head -1`
+TMPDIR="${TMPDIR}/${HORDEDIR}.TMP.$$"
+
+if [ ! -z ${EXISTS} ]; then
+ echo " Found an existing (aborted?) update of horde (${EXISTS})."
+ read -p " Should I use it? [Yes]" USE_EXISTING
+ case ${USE_EXISTING} in
+ [Nn]|[Nn][Oo])
+ read -p " Should I delete ${EXISTS}? [Yes]" DELETE_EXISTING
+ case ${DELETE_EXISTING} in
+ [Nn]|[Nn][Oo])
+ echo " Not deleting ${EXISTS}"
+ ;;
+ *)
+ echo " Deleting ${EXISTS}"
+ rm -rf ${EXISTS}
+ ;;
+ esac
+ ;;
+ *)
+ TMPDIR=${EXISTS}
+ ;;
+ esac
+ unset USE_EXISTING
+fi
+if [ -e ${TMPDIR} ]; then
+ echo " Using ${TMPDIR}"
+else
+ echo " Creating new directory ${TMPDIR}"
+ mkdir ${TMPDIR}
+ if [ ! -e ${TMPDIR} ]; then
+ echo "ERROR: Couldn't create ${TMPDIR}"
+ exit 1
+ fi
+fi
+
+echo "Creating config patch file from existing horde"
+if [ -e ${TMPDIR}/update.patch ]; then
+ read -p " This directory includes a patch. Use it? [Yes]" USE_EXISTING
+ case ${USE_EXISTING} in
+ [Nn]|[Nn][Oo])
+ echo " Clearing existing update.patch"
+ rm -f ${TMPDIR}/update.patch || exit 1
+ ;;
+ esac
+ unset USE_EXISTING
+fi
+if [ ! -e ${TMPDIR}/update.patch ]; then
+ if [ ! -e ${WEBDIR}/${HORDEDIR} ]; then
+ echo " No existing horde distribution found. Can't create patch."
+ else
+ read -p " Do you want to create a patch from the existing install? [Yes]" MAKE_PATCH
+ case ${MAKE_PATCH} in
+ [Nn]|[Nn][Oo])
+ echo " Not creating a patch"
+ ;;
+ *)
+ echo " Creating patch...this could take a bit..."
+ find ${WEBDIR}/${HORDEDIR} -type f -name \*.dist -print \
+ | perl -ne 's/\.dist[\r\n]*//; print "$_.dist\n$_\n";' \
+ | xargs -n 2 diff -u > ${TMPDIR}/update.patch
+ ;;
+ esac
+ unset MAKE_PATCH
+ fi
+fi
+
+if [ -e "${WEBDIR}/${HORDEDIR}" ]; then
+ read -p "Do you want to fetch new (N) or update (U)? [U] " FETCH_NEW
+else
+ FETCH_NEW=new
+fi
+
+case ${FETCH_NEW} in
+ [Nn]|[Nn][Ee][Ww])
+ for APP in ${APPVER}
+ {
+ app=${APP%%-*}
+ rel=${APP##*-}
+ if [ ${app} = ${APP} ]; then
+ echo " No release specified...assuming HEAD"
+ rel=HEAD
+ fi
+
+ case ${app} in
+ horde)
+ APPDIR=${TMPDIR}
+ EXISTDIR="${TMPDIR}/${HORDEDIR}"
+ ;;
+ *)
+ APPDIR=${TMPDIR}/${HORDEDIR}
+ EXISTDIR="${TMPDIR}/${HORDEDIR}/${app}"
+ ;;
+ esac
+
+ if [ -e $EXISTDIR ]; then
+ case ${REGET} in
+ [Aa]|[Aa][Ll][Ll])
+ echo " Removing existing ${APPDIR}/${app}...";
+ rm -rf ${APPDIR}/${app}
+ echo " Retrieving ${app} $rel..."
+ cd ${APPDIR}
+ cvs -Q -z3 -d :pserver:cvsread@anoncvs.horde.org:/repository co \
+ -r $rel ${app}
+ ;;
+ [Nn][Oo][Nn][Ee])
+ REGET="NONE"
+ echo " Using existing ${APPDIR}/${app}"
+ ;;
+ *)
+ echo " ${app} exists. Should I get ${app} anyway?"
+ if [ "${app}" = "horde" ]; then
+ echo " NOTE: regetting horde does not clear out any existing files"
+ fi
+ read -p " [Y]es/[N]o/[A]ll/None (default None): " REGET
+ case ${REGET} in
+ [Yy]|[Yy][Ee][Ss]|[Aa]|[Aa][Ll][Ll])
+ echo " Removing existing ${APPDIR}/${app}...";
+ rm -rf ${APPDIR}/${app}
+ echo " Retrieving ${app} $rel..."
+ cd ${APPDIR}
+ cvs -Q -z3 -d :pserver:cvsread@anoncvs.horde.org:/repository co \
+ -r $rel ${app}
+ ;;
+ [Nn]|[Nn][Oo])
+ echo " Using existing ${APPDIR}/${app}"
+ ;;
+ *)
+ echo " Using existing ${APPDIR}/${app}"
+ REGET=NONE
+ ;;
+ esac
+ ;;
+ esac
+ else
+ echo -n " Retrieving ${app} $rel..."
+ cd ${APPDIR}
+ cvs -Q -z3 -d :pserver:cvsread@anoncvs.horde.org:/repository co \
+ -r $rel ${app}
+ echo "done"
+ fi
+ if [ "$app" = "horde" -a "$HORDEDIR" != "horde" ]; then
+ echo " Moving ${TMPDIR}/horde to ${TMPDIR}/${HORDEDIR}"
+ mv ${TMPDIR}/horde ${TMPDIR}/${HORDEDIR}
+ fi
+ }
+ ;;
+ *)
+ mkdir ${TMPDIR}/${HORDEDIR}
+ cp -Rpf ${WEBDIR}/${HORDEDIR}/* ${TMPDIR}/${HORDEDIR}
+ cd ${TMPDIR}/${HORDEDIR}
+ cvs update -PdC
+ ;;
+esac
+
+echo "Putting default config files in place..."
+if [ -e ${TMPDIR}/${HORDEDIR}/config/conf.php ]; then
+ echo " I have found some configuration files already in place."
+ echo " If you are updating an existing installation this is normal."
+ echo " NOTE: If some have been copied and others not, horde will be broken."
+ read -p " Should I copy .dist files anyway? [Yes] " USE_EXISTING
+ #The phrasing of the question means USE_EXISTING from the read is backwards
+ # but it seems better to confuse the programmer than the user...
+ case ${USE_EXISTING} in
+ [Nn]|[Nn][Oo])
+ USE_EXISTING=YES
+ ;;
+ *)
+ USE_EXISTING=NO
+ ;;
+ esac
+fi
+if [ "${USE_EXISTING:=NO}" = "NO" ]; then
+ echo " Copying *.dist files..."
+ find ${TMPDIR}/${HORDEDIR} -type f -name \*.dist -print \
+ | perl -ne 'print "$_"; s/\.dist//; print "$_"' \
+ | xargs -n 2 cp
+fi
+
+echo "Applying patch..."
+echo " Clearing out any old reject files..."
+find ${TMPDIR} -name \*.rej -type f -exec rm {} \; -print
+
+if [ ! -e ${TMPDIR}/update.patch ]; then
+ echo " I can't seem to find the patch file ${TMPDIR}/update.patch!"
+ read -p " Do you want me to load all config files in $EDITOR? [No]" EDIT
+ case ${EDIT} in
+ [Yy]|[Yy][Ee][Ss])
+ find ${TMPDIR}/${HORDEDIR} -type f -name \*.dist \
+ | perl -ne 's/\.dist[\r\n]*//; print "$_\n";' \
+ | xargs -n 2 echo $EDITOR > ${TMPDIR}/edit.sh
+ sh ${TMPDIR}/edit.sh
+ rm ${TMPDIR}/edit.sh
+ ;;
+ *)
+ echo " WARNING: You need to change the config files later!"
+ ;;
+ esac
+else
+ if [ "${USE_EXISTING}" = "YES" ]; then
+ echo " We kept the modified configuration files."
+ read -p " Should we still apply the patch? [No] " PATCH
+ case ${PATCH} in
+ [Yy]|[Yy][Ee][Ss])
+ PATCH=YES
+ ;;
+ *)
+ PATCH=NO
+ ;;
+ esac
+ fi
+
+ if [ "${PATCH:=YES}" = "YES" ]; then
+ echo " running patch"
+ cd ${TMPDIR}
+ if [ `patch -f -p${NUM_SLASHES} -s < ${TMPDIR}/update.patch` ]; then
+ echo " Patch applied successfully"
+ else
+ find ${TMPDIR}/${HORDEDIR} -type f -name \*.rej \
+ | perl -ne 's/\.rej[\r\n]*//; print "$_.rej\n$_\n"; ' \
+ | xargs -n 2 echo $EDITOR > ${TMPDIR}/edit.sh
+ sh ${TMPDIR}/edit.sh
+ rm ${TMPDIR}/edit.sh
+ fi
+ fi
+fi
+
+read -p "Are you ready to put the new CVS into production? [Yes]" PROD
+case ${PROD} in
+[Nn]|[Nn][Oo])
+ echo "${TMPDIR} has not been put in production."
+ ;;
+*)
+ if [ -e ${WEBDIR}/${HORDEDIR} ]; then
+ i=1
+ while [ ${i} != ${NUM_BACKUPS} ]
+ do
+ if [ ! -e ${BACKUPDIR}/${HORDEDIR}.${i} ]; then
+ break;
+ fi
+ i=$((${i}+1))
+ done
+
+ if [ ${i} = ${NUM_BACKUPS} ] && [ -e ${BACKUPDIR}/${HORDEDIR}.${i} ]; then
+ echo " Removing oldest backup directory (${BACKUPDIR}/${HORDEDIR}.${i})"
+ rm -rf ${BACKUPDIR}/${HORDEDIR}.${i} || exit 1
+ fi
+
+ while [ ${i} != 1 ]
+ do
+ echo " Moving ${BACKUPDIR}/${HORDEDIR}.$((${i}-1)) to ${BACKUPDIR}/${HORDEDIR}.${i}"
+ mv ${BACKUPDIR}/${HORDEDIR}.$((${i}-1)) ${BACKUPDIR}/${HORDEDIR}.${i} || exit 1
+ i=$((${i}-1))
+ done
+
+ echo " Moving ${WEBDIR}/${HORDEDIR} to ${BACKUPDIR}/${HORDEDIR}.1"
+ mv ${WEBDIR}/${HORDEDIR} ${BACKUPDIR}/${HORDEDIR}.1 || exit 1
+
+ echo " Moving ${TMPDIR}/${HORDEDIR} ${WEBDIR}/${HORDEDIR}"
+ mv ${TMPDIR}/${HORDEDIR} ${WEBDIR}/${HORDEDIR} || exit 1
+
+ echo " Removing ${TMPDIR}"
+ rm -rf ${TMPDIR}
+
+ echo "New CVS horde is now in production!"
+ else
+ echo "${WEBDIR}/${HORDEDIR} does not exist. Copying ${TMPDIR}/${HORDEDIR} to ${WEBDIR}/${HORDEDIR}"
+ cp ${TMPDIR}/${HORDEDIR} ${WEBDIR}/${HORDEDIR}
+ fi
+ ;;
+esac
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.4.9" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>admintools</name>
+ <channel>pear.horde.org</channel>
+ <summary>Horde Administrator Tools</summary>
+ <description>This package contains scripts useful to people administering Horde installations.
+ </description>
+ <lead>
+ <name>Chuck Hagenbuch</name>
+ <user>chuck</user>
+ <email>chuck@horde.org</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Jan Schneider</name>
+ <user>jan</user>
+ <email>jan@horde.org</email>
+ <active>yes</active>
+ </lead>
+ <date>2009-12-22</date>
+ <version>
+ <release>0.3.0</release>
+ <api>0.3.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>* Initial Horde 4 package.
+ <contents>
+ <dir name="/">
+ <file name="horde-base.php" role="script" />
+ <file name="horde-create-sequence.php" role="script">
+ <tasks:replace from="@php_bin@" to="php_bin" type="pear-config"/>
+ </file>
+ <file name="horde-db-dumpdata.php" role="script">
+ <tasks:replace from="@php_bin@" to="php_bin" type="pear-config"/>
+ </file>
+ <file name="horde-db-dumpschema.php" role="script">
+ <tasks:replace from="@php_bin@" to="php_bin" type="pear-config"/>
+ </file>
+ <file name="horde-db-updatedata.php" role="script">
+ <tasks:replace from="@php_bin@" to="php_bin" type="pear-config"/>
+ </file>
+ <file name="horde-db-updateschema.php" role="script">
+ <tasks:replace from="@php_bin@" to="php_bin" type="pear-config"/>
+ </file>
+ <file name="horde-remove-pref.php" role="script">
+ <tasks:replace from="@php_bin@" to="php_bin" type="pear-config"/>
+ </file>
+ <file name="horde-sql-shell.php" role="script">
+ <tasks:replace from="@php_bin@" to="php_bin" type="pear-config"/>
+ </file>
+ <file name="horde-update.sh" role="script" />
+ </dir> <!-- / -->
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.2.0</min>
+ </php>
+ <pearinstaller>
+ <min>1.7.0</min>
+ </pearinstaller>
+ </required>
+ </dependencies>
+ <phprelease>
+ <filelist>
+ <install name="horde-base.php" as="horde-base.php" />
+ <install name="horde-create-sequence.php" as="horde-create-sequence.php" />
+ <install name="horde-db-dumpdata.php" as="horde-db-dumpdata.php" />
+ <install name="horde-db-dumpschema.php" as="horde-db-dumpschema.php" />
+ <install name="horde-db-updatedata.php" as="horde-db-updatedata.php" />
+ <install name="horde-db-updateschema.php" as="horde-db-updateschema.php" />
+ <install name="horde-remove-pref.php" as="horde-remove-pref.php" />
+ <install name="horde-sql-shell.php" as="horde-sql-shell.php" />
+ <install name="horde-update.sh" as="horde-update.sh" />
+ </filelist>
+ </phprelease>
+ <changelog>
+ <release>
+ <date>2008-06-24</date>
+ <version>
+ <release>0.2.0</release>
+ <api>0.2.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>- Add a script for creating PEAR::DB sequences
+ - Add scripts for dumping and updating the Horde database from MDB2_Schema XML files
+ - Add a script for running a series of SQL statements from STDIN on the Horde database
+ - Add scripts for dumping and restoring data from the Horde database
+ </notes>
+ </release>
+ </changelog>
+</package>
--- /dev/null
+=====================
+Horde Developer Tools
+=====================
+
+Introduction
+~~~~~~~~~~~~
+This directory contains various developer scripts for the Horde
+distribution.
+
+
+Script Index
+~~~~~~~~~~~~
+horde-check-themes.php
+ Makes sure that themes that provide their own images aren't missing any.
+
+horde-fw-symlinks.php
+ Creates symbolic links necessary for developers to work directly on the
+ files in the framework module without needing to install the changed
+ packages.
+
+horde-highlight.php
+ Highlights source files on the console.
+
+horde-merge.php
+ Merges commits from a commit message into the CVS tree of the current
+ directory.
+
+horde-rev-cmp.sh
+ Compares different CVS revisions of the same file.
--- /dev/null
+#!@php_bin@
+<?php
+/**
+ * This script does some checking to make sure images are synchronised
+ * across themes.
+ *
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @category Horde
+ * @package devtools
+ * @author Marko Djukic <marko@oblo.com>
+ */
+
+/* CLI checks and environment setup first. */
+require_once 'Horde/Cli.php';
+
+/* Make sure no one runs this from the web. */
+if (!Horde_Cli::runningFromCLI()) {
+ exit("Must be run from the command line\n");
+}
+
+/* Get any options. */
+$simple = false;
+$horde_base = null;
+$ignore = array();
+if (isset($argv)) {
+ /* Get rid of the first arg which is the script name. */
+ array_shift($argv);
+ while ($arg = array_shift($argv)) {
+ if ($arg == '--help') {
+ print_usage();
+ } elseif ($arg == '-s') {
+ $simple = true;
+ } elseif (strpos($arg, '-i') === 0) {
+ list(,$ignore[]) = explode('=', $arg);
+ } elseif (file_exists($arg . '/config/registry.php')) {
+ $horde_base = $arg;
+ } else {
+ print_usage("Unrecognised option $arg");
+ }
+ }
+}
+
+if ($horde_base === null) {
+ print_usage("You must specify the base path to Horde.");
+}
+
+/* Set up CLI. */
+$cli = Horde_Cli::singleton();
+$cli->init();
+
+$horde_authentication = 'none';
+require_once $horde_base . '/lib/base.php';
+
+/* Get the apps and start doing checks. */
+$apps = $registry->listApps(array('hidden', 'notoolbar', 'active', 'admin'));
+
+/* Get a list of themes. */
+$themes = array();
+$themes_dir = $registry->get('themesfs', 'horde');
+if ($handle = opendir($themes_dir)) {
+ while ($file = readdir($handle)) {
+ if ($file == '.' || $file == '..' || $file == 'CVS' ||
+ $file == '.svn' ||
+ !file_exists("$themes_dir/$file/themed_graphics") ||
+ !file_exists("$themes_dir/$file/graphics")) {
+ continue;
+ }
+
+ /* Store the apps and their theme directories. */
+ foreach ($apps as $app) {
+ $dir = $registry->get('themesfs', $app) . '/' . $file . '/graphics';
+ if (is_dir($dir)) {
+ $themes[$app][$file] = $dir;
+ }
+ }
+ }
+}
+
+foreach ($apps as $app) {
+ /* Skip applications without icon themes. */
+ if (!isset($themes[$app])) {
+ continue;
+ }
+
+ /* Set up some dirs. */
+ $themes_dir = $registry->get('themesfs', $app);
+ $horde_icon_dir = $themes_dir . '/graphics';
+
+ /* Sanity check for the directories. */
+ if (!file_exists($horde_icon_dir)) {
+ continue;
+ }
+
+ /* Get a list of all horde images recursively. */
+ $horde_icon_list = array();
+ readDirRecursively($horde_icon_dir, $horde_icon_dir, $horde_icon_list);
+
+ /* Loop through themes that replace icons and check for differences. */
+ foreach ($themes[$app] as $theme => $theme_icon_dir) {
+ $theme_icon_list = array();
+ readDirRecursively($theme_icon_dir, $theme_icon_dir, $theme_icon_list);
+
+ /* Check for icons that are in the Horde base theme and not in the
+ * custom theme. */
+ $diff = array_diff($horde_icon_list, $theme_icon_list);
+ /* Don't bother reporting anything for themes that have all the horde
+ * base icons. */
+ if (empty($diff)) {
+ continue;
+ }
+
+ $cli->writeln($cli->red(sprintf('[%s] "%s" theme missing these icons:',
+ strtoupper($app),
+ $theme)));
+ sort($diff);
+ foreach ($diff as $icon) {
+ $cli->writeln($icon);
+ }
+
+ /* Check if only doing a Horde base theme to custom theme check. Skip
+ * the reverse checking if true. */
+ if ($simple) {
+ continue;
+ }
+
+ /* Check for icons that are in the Horde base theme and not in the
+ * custom theme. */
+ $diff = array_diff($theme_icon_list, $horde_icon_list);
+ /* Don't bother reporting anything for themes that don't have any icons
+ * more than the base theme. */
+ if (empty($diff)) {
+ continue;
+ }
+
+ $cli->writeln($cli->blue(sprintf('[%s] "%s" theme has these extra icons:',
+ strtoupper($app),
+ $theme)));
+ sort($diff);
+ foreach ($diff as $icon) {
+ $cli->writeln($icon);
+ }
+ }
+}
+
+$cli->writeln($cli->green('Done.'));
+exit;
+
+/**
+ * Loops through the directory recursively and stores the found
+ * graphics into an array.
+ */
+function readDirRecursively($path, $basepath, &$list)
+{
+ global $ignore;
+
+ if ($handle = opendir($path)) {
+ while ($file = readdir($handle)) {
+ if ($file == '.' || $file == '..' ||
+ $file == 'CVS' || $file == '.svn') {
+ continue;
+ }
+ if (is_dir("$path/$file")) {
+ readDirRecursively("$path/$file", $basepath, $list);
+ } else {
+ foreach ($ignore as $pattern) {
+ if (preg_match($pattern, $file)) {
+ continue 2;
+ }
+ }
+ $list[] = substr($path, strlen($basepath)) . "/$file";
+ }
+ }
+ closedir($handle);
+ }
+
+}
+
+function print_usage($message = '')
+{
+
+ if (!empty($message)) {
+ print "themes_check.php: $message\n\n";
+ }
+
+ print <<<USAGE
+Usage: themes_check.php [OPTION] /path/to/horde
+
+Possible options:
+ -s Do only a simple check for any Horde base theme graphics that
+ are missing from the other themes, and no check of the
+ opposite.
+ -i=PATTERN Insert any valid regex pattern to ignore files from being
+ checked. You can enter multiple -i options to include multiple
+ patterns. For example: -i="/xcf$/ to ignore any original
+ GIMP files.
+
+USAGE;
+ exit;
+}
--- /dev/null
+#!@php_bin@
+<?php
+/**
+ * This script creates softlinks to the library files you retrieved from
+ * the CVS "framework" module. This script also works on a framework
+ * installation retrieved from git.
+ *
+ * It creates the same directory structure the packages would have if they
+ * were installed with "pear install package.xml".
+ * For creating this structure it uses the information given in the
+ * package.xml files inside each package directory.
+ *
+ * Copyright 2002 Wolfram Kriesing <wolfram@kriesing.de>
+ * Copyright 2003-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @category Horde
+ * @package devtools
+ * @author Wolfram Kriesing <wolfram@kriesing.de>
+ * @author Jan Schneider <jan@horde.org>
+ */
+
+// Default values for srcDir and destDir are empty.
+$srcDir = null;
+$destDir = null;
+
+// Default to copying if this is run on Windows.
+$copy = strncasecmp(PHP_OS, 'WIN', 3) ? false : true;
+
+// All packages by default.
+$pkg = null;
+
+for ($i = 1; $i < count($argv); $i++) {
+ switch ($argv[$i]) {
+ case '--copy':
+ $copy = true;
+ break;
+
+ case '--help':
+ print_usage();
+
+ case '--src':
+ if (isset($argv[$i + 1])) {
+ if (is_dir($argv[$i + 1])) {
+ $srcDir = $argv[$i + 1];
+ $i++;
+ } else {
+ exit($argv[$i + 1] . " is not a directory");
+ }
+ }
+ break;
+
+ case '--dest':
+ if (isset($argv[$i + 1])) {
+ if (is_dir($argv[$i + 1])) {
+ $destDir = $argv[$i + 1];
+ $i++;
+ } else {
+ exit($argv[$i + 1] . " is not a directory");
+ }
+ }
+ break;
+
+ case '--pkg':
+ $pkg = $argv[$i + 1];
+ if (!is_dir($pkg) || !file_exists($pkg . '/package.xml')) {
+ exit("$pkg is not a valid package directory.\n");
+ }
+ $pkg = preg_replace('|/+$|', '', $pkg);
+ $i++;
+ break;
+
+ default:
+ print_usage("Unrecognised option $argv[$i]");
+ }
+}
+
+// Try to auto-detect the source and dest dirs.
+$cwd = getcwd();
+if ($srcDir === null && is_dir($cwd . DIRECTORY_SEPARATOR . 'framework')) {
+ $srcDir = $cwd . DIRECTORY_SEPARATOR . 'framework';
+}
+if ($destDir === null && is_dir($cwd . DIRECTORY_SEPARATOR . 'libs')) {
+ $destDir = $cwd . DIRECTORY_SEPARATOR . 'libs';
+}
+
+if ($srcDir === null || $destDir === null) {
+ print_usage('Failed to auto-detect source and destination directories,');
+}
+
+// Make $srcDir an absolute path.
+if (($srcDir[0] != '/' && !preg_match('/[A-Za-z]:/', $srcDir)) &&
+ $cwd = getcwd()) {
+ $srcDir = $cwd . '/' . $srcDir;
+}
+$srcDir = rtrim($srcDir, '/');
+
+// Make $destDir an absolute path.
+if (($destDir[0] != '/' && !preg_match('/[A-Za-z]:/', $destDir)) &&
+ $cwd = getcwd()) {
+ $destDir = $cwd . '/' . $destDir;
+}
+$destDir = rtrim($destDir, '/');
+
+// Put $destDir into include_path.
+if (strpos(ini_get('include_path'), $destDir) === false) {
+ ini_set('include_path', $destDir . PATH_SEPARATOR . ini_get('include_path'));
+}
+
+// Do CLI checks and environment setup first.
+if (!@include_once 'Horde/Cli.php') {
+ if (!@include_once $srcDir . '/Cli/lib/Horde/Cli.php') {
+ if (!@include_once $cwd . DIRECTORY_SEPARATOR . 'framework/Cli/lib/Horde/Cli.php') {
+ print_usage('Horde_Cli library is not in the include_path or in the src directory.');
+ }
+ }
+}
+
+// Make sure no one runs this from the web.
+if (!Horde_Cli::runningFromCLI()) {
+ exit;
+}
+
+// Load the CLI environment - make sure there's no time limit, init
+// some variables, etc.
+Horde_Cli::init();
+
+if (!class_exists('SimpleXMLElement', false)) {
+ include_once 'Tree/Tree.php';
+ if (!class_exists('Tree')) {
+ print_usage('You need the PEAR "Tree" package installed');
+ }
+}
+
+// Tree throws some irrelevant reference; silence them.
+error_reporting(E_ALL & ~E_NOTICE);
+
+$linker = new Linker($copy);
+if ($pkg) {
+ $linker->process(getcwd() . DIRECTORY_SEPARATOR . $pkg, $destDir);
+} elseif ($handle = opendir($srcDir)) {
+ while ($file = readdir($handle)) {
+ if ($file != '.' &&
+ $file != '..' &&
+ $file != 'CVS' &&
+ is_dir($srcDir . '/' . $file)) {
+ $linker->process($srcDir . '/' . $file, $destDir);
+ }
+ }
+ closedir($handle);
+ }
+
+echo "\n";
+
+/**
+ */
+class Linker {
+
+ var $_srcDir;
+
+ /**
+ * The base directory for the complete package.
+ *
+ * @string
+ */
+ var $_baseDir;
+
+ /**
+ * The base installation directories of the current directory or file
+ * relative to $_baseDir. The current base directory is always at array
+ * position 0.
+ *
+ * @array
+ */
+ var $_baseInstallDir = array('');
+
+ var $_fileroles = array('php');
+
+ var $_role;
+
+ var $_copy;
+
+ var $_tree;
+
+ var $_contents;
+
+ function Linker($copy = false)
+ {
+ $this->_copy = $copy;
+ }
+
+ function process($srcDir, $destDir)
+ {
+ $this->_srcDir = $srcDir;
+ $packageFile = $this->_srcDir . '/package.xml';
+ $cli = &Horde_Cli::singleton();
+
+ if (!is_file($packageFile)) {
+ $cli->message('No package.xml in ' . $this->_srcDir, 'cli.warning');
+ return false;
+ }
+
+ $this->_tree = $this->getXmlTree($packageFile);
+
+ // Read package name.
+ $packageName = trim($this->_tree->getElementContent('/package/name', 'cdata'));
+ $cli->writeln("Processing package $packageName.");
+
+ // First, look for '/package/phprelease/filelist', which
+ // overrides '/package/contents'.
+ if (($filelist = $this->_tree->getElementByPath('/package/phprelease/filelist'))) {
+ // Do this better, make the tree class work case insensitive.
+ $this->_baseDir = preg_replace('|/+|', '/', $destDir);
+ if (!is_dir($this->_baseDir)) {
+ require_once 'System.php';
+ System::mkdir('-p ' . $this->_baseDir);
+ }
+
+ $this->_handleFilelistTag($filelist);
+
+ // Look for contents in '/package/contents'.
+ } elseif (($this->_contents = $this->_tree->getElementByPath('/package/contents'))) {
+ // Do this better, make the tree class work case insensitive.
+ $this->_baseDir = preg_replace('|/+|', '/', $destDir);
+ if (!is_dir($this->_baseDir)) {
+ require_once 'System.php';
+ System::mkdir('-p ' . $this->_baseDir);
+ }
+
+ $this->_handleContentsTag($this->_contents);
+
+ // Didn't find either.
+ } else {
+ $cli->message('No filelist or contents tags found inside: ' . $packageFile, 'cli.warning');
+ }
+
+ unset($this->_tree);
+ unset($this->_contents);
+ }
+
+ function _handleFilelistTag($element, $curDir = '')
+ {
+ if (isset($element['children'])) {
+ foreach ($element['children'] as $child) {
+ switch ($child['name']) {
+ case 'install':
+ // <install name="lib/Horde/Log/Exception.php" as="Horde/Log.php" />
+ $this->_handleInstallTag($child, $curDir);
+ break;
+
+ default:
+ $cli = &Horde_Cli::singleton();
+ $cli->message('No handler for tag: ' . $child['name'], 'cli-warning');
+ break;
+ }
+ }
+ }
+ }
+
+ function _handleContentsTag($element, $curDir = '')
+ {
+ if (isset($element['children'])) {
+ foreach ($element['children'] as $child) {
+ switch ($child['name']) {
+ case 'file':
+ $this->_handleFileTag($child, $curDir);
+ break;
+
+ case 'dir':
+ $this->_handleDirTag($child, $curDir);
+ break;
+
+ default:
+ $cli = &Horde_Cli::singleton();
+ $cli->message('No handler for tag: ' . $child['name'], 'cli-warning');
+ break;
+ }
+ }
+ }
+ }
+
+ function _handleDirTag($element, $curDir)
+ {
+ if ($element['attributes']['name'] != '/') {
+ if (substr($curDir, -1) != DIRECTORY_SEPARATOR) {
+ $curDir .= DIRECTORY_SEPARATOR;
+ }
+ $curDir .= $element['attributes']['name'];
+ }
+
+ if (!empty($element['attributes']['baseinstalldir'])) {
+ array_unshift($this->_baseInstallDir, $element['attributes']['baseinstalldir']);
+ }
+ $this->_handleContentsTag($element, $curDir);
+ if (!empty($element['attributes']['baseinstalldir'])) {
+ array_shift($this->_baseInstallDir);
+ }
+ }
+
+ function _handleFileTag($element, $curDir)
+ {
+ if (!empty($element['attributes']['role'])) {
+ $this->_role = $element['attributes']['role'];
+ }
+
+ if (!in_array($this->_role, $this->_fileroles)) {
+ return;
+ }
+
+ if (!empty($element['attributes']['name'])) {
+ $filename = $element['attributes']['name'];
+ } else {
+ $filename = $element['cdata'];
+ }
+ $filename = trim($filename);
+
+ if (!empty($element['attributes']['baseinstalldir'])) {
+ $dir = $element['attributes']['baseinstalldir'];
+ } else {
+ $dir = $this->_baseInstallDir[0];
+ }
+ if (substr($dir, -1) == '/') {
+ $dir = substr($dir, 0, -1);
+ }
+ $dir .= $curDir;
+ if (substr($dir, -1) == '/') {
+ $dir = substr($dir, 0, -1);
+ }
+
+ if (!is_dir($this->_baseDir . $dir)) {
+ require_once 'System.php';
+ System::mkdir('-p ' . $this->_baseDir . $dir);
+ }
+
+ if ($this->_copy) {
+ $cmd = "cp {$this->_srcDir}$curDir/$filename {$this->_baseDir}$dir/$filename";
+ } else {
+ $parent = $this->_findCommonParent($this->_srcDir . $curDir,
+ $this->_baseDir . $dir);
+ $dirs = substr_count(substr($this->_baseDir . $dir,
+ strlen($parent)),
+ '/');
+ $src = str_repeat('../', $dirs) .
+ substr($this->_srcDir . $curDir, strlen($parent) + 1);
+ $cmd = "ln -sf $src/$filename {$this->_baseDir}$dir/$filename";
+ }
+
+ exec($cmd);
+ }
+
+ function _handleInstallTag($element, $curDir)
+ {
+ if (empty($element['attributes']['name'])) {
+ // Warning?
+ return;
+ }
+ $src = trim($element['attributes']['name']);
+ $srcDir = dirname($src);
+
+ if (empty($element['attributes']['as'])) {
+ // Warning?
+ return;
+ }
+ $as = trim($element['attributes']['as']);
+ $asDir = dirname($as);
+
+ $role = $this->_findRole($src);
+ if (!in_array($role, $this->_fileroles)) {
+ return;
+ }
+
+ if (!is_dir($this->_baseDir . '/' . $asDir)) {
+ require_once 'System.php';
+ System::mkdir('-p ' . $this->_baseDir . '/' . $asDir);
+ }
+
+ if ($this->_copy) {
+ $cmd = "cp {$this->_srcDir}$curDir/$src {$this->_baseDir}/$as";
+ } else {
+ $parent = $this->_findCommonParent($this->_srcDir . $curDir,
+ $this->_baseDir . $asDir);
+ $dirs = substr_count(substr($this->_baseDir . $srcDir, strlen($parent)),
+ '/');
+ $src = str_repeat('../', $dirs) . substr($this->_srcDir . $curDir, strlen($parent) + 1) . '/' . $src;
+ $cmd = "ln -sf $src {$this->_baseDir}/$as";
+ }
+
+ exec($cmd);
+ }
+
+ function _findRole($filename)
+ {
+ if (!$this->_contents) {
+ $this->_contents = $this->_tree->getElementByPath('/package/contents');
+ if (!$this->_contents) {
+ return false;
+ }
+ }
+
+ if (!isset($this->_contents['children'])) {
+ return false;
+ }
+
+ $pieces = explode('/', $filename);
+ if (!count($pieces)) {
+ return false;
+ }
+
+ $element = $this->_contents;
+ while (true) {
+ $continue = false;
+ foreach ($element['children'] as $child) {
+ if (!in_array($child['name'], array('file', 'dir'))) {
+ continue;
+ }
+
+ if ($child['attributes']['name'] == '/') {
+ $continue = true;
+ break;
+ }
+
+ if ($child['attributes']['name'] == $pieces[0]) {
+ if (count($pieces) == 1) {
+ if (isset($child['attributes']['role'])) {
+ return $child['attributes']['role'];
+ } else {
+ return false;
+ }
+ }
+
+ array_shift($pieces);
+ if (!count($pieces)) {
+ return false;
+ }
+
+ $continue = true;
+ break;
+ }
+ }
+
+ if (!$continue) {
+ return false;
+ }
+
+ if (!isset($child['children'])) {
+ return false;
+ }
+ $element = $child;
+ }
+
+ return false;
+ }
+
+ function _findCommonParent($a, $b)
+ {
+ for ($common = '', $lastpos = 0, $pos = strpos($a, '/', 1);
+ $pos !== false && strpos($b, substr($a, 0, $pos)) === 0;
+ $pos = strpos($a, '/', $pos + 1)) {
+ $common .= substr($a, $lastpos, $pos - $lastpos);
+ $lastpos = $pos;
+ }
+ return $common;
+ }
+
+ function getXmlTree($packageFile)
+ {
+ if (class_exists('SimpleXMLElement', false)) {
+ return new Linker_Xml_Tree($packageFile);
+ } else {
+ $tree = Tree::setupMemory('XML', $packageFile);
+ $tree->setup();
+ return $tree;
+ }
+ }
+
+}
+
+class Linker_Xml_Tree
+{
+ var $_sxml;
+
+ function __construct($packageFile)
+ {
+ $this->_sxml = simplexml_load_file($packageFile);
+ }
+
+ function getElementContent($path, $field)
+ {
+ $elt = $this->getElementByPath($path);
+ return $elt[$field];
+ }
+
+ function getElementByPath($path)
+ {
+ $path = str_replace('/package', '', $path);
+
+ $node = $this->_sxml;
+ $path = preg_split('|/|', $path, -1, PREG_SPLIT_NO_EMPTY);
+ while ($path) {
+ $ptr = array_shift($path);
+ if (!$node->$ptr) return null;
+ $node = $node->$ptr;
+ }
+
+ return $this->_asArray($node);
+ }
+
+ function _asArray($sxml)
+ {
+ $element = array();
+ $element['name'] = $sxml->getName();
+ $element['cdata'] = (string)$sxml;
+ $element['attributes'] = array();
+ foreach ($sxml->attributes() as $k => $v) {
+ $element['attributes'][$k] = (string)$v;
+ }
+ $element['children'] = array();
+ foreach ($sxml->children() as $node) {
+ $element['children'][] = $this->_asArray($node);
+ }
+
+ return $element;
+ }
+
+}
+
+function print_usage($message = '')
+{
+
+ if (!empty($message)) {
+ echo "horde-fw-symlinks.php: $message\n\n";
+ }
+
+ echo <<<USAGE
+Usage: horde-fw-symlinks.php [OPTION]
+
+Possible options:
+ --copy Do not create symbolic links, but actually copy the libraries
+ (this is done automatically on Windows).
+ --src DIR The source directory for the framework libraries.
+ --dest DIR The destination directory for the framework libraries.
+ --pkg DIR Path to a single package to install.
+
+USAGE;
+ exit;
+}
--- /dev/null
+#!@php_bin@
+<?php
+/**
+ * This script highlights various source files on the console.
+ *
+ * Copyright 2004-2009 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ *
+ * @category Horde
+ * @package devtools
+ * @author Jan Schneider <jan@horde.org>
+ */
+
+if (!isset($argv[1])) {
+ echo "Usage: highlight.php SOURCE_FILE [HIGHLIGHTER]\n";
+ exit;
+}
+
+require_once 'Text/Highlighter.php';
+require_once 'Text/Highlighter/Renderer/Console.php';
+
+/* File to highlight. */
+$file = $argv[1];
+
+/* Optional highlighter. */
+if (isset($argv[2])) {
+ $type = $argv[2];
+} else {
+ /* Try autodetecting. */
+ $map = array('cpp' => 'CPP',
+ 'css' => 'CSS',
+ 'diff' => 'DIFF', 'patch' => 'DIFF',
+ 'dtd' => 'DTD',
+ 'js' => 'JAVASCRIPT',
+ 'pl' => 'PERL',
+ 'php' => 'PHP',
+ 'py' => 'PYTHON',
+ 'sql' => 'SQL',
+ 'xml' => 'XML');
+ $ext = strtolower(substr($file, strrpos($file, '.') + 1));
+ if (isset($map[$ext])) {
+ $type = $map[$ext];
+ } else {
+ $type = 'PHP';
+ }
+}
+
+$hl = Text_Highlighter::factory($type);
+$hl->setRenderer(new Text_Highlighter_Renderer_Console());
+
+echo $hl->highlight(file_get_contents($file));
--- /dev/null
+#!@php_bin@
+<?php
+/**
+ * A small script that takes lines of a commit message like:
+ * <pre>
+ * 2.485 +26 -5 imp/compose.php
+ * 1.503 +2 -0 imp/docs/CHANGES
+ * 2.159 +25 -12 imp/templates/compose/compose.inc
+ * 2.55 +28 -3 imp/templates/compose/javascript.inc
+ * </pre>
+ * from the standard input and merges these commits into the appropriate files
+ * of the current directory. Mainly for merging changes in HEAD to the RELENG
+ * tree. This script should be run from Horde's root.
+ *
+ * @category Horde
+ * @package devtools
+ */
+
+// Location of the cvs binary
+$CVS = 'cvs';
+
+@set_time_limit(0);
+ob_implicit_flush(true);
+ini_set('track_errors', true);
+ini_set('implicit_flush', true);
+ini_set('html_errors', false);
+ini_set('magic_quotes_runtime', false);
+
+$reverse = $join = $commit = $compress = false;
+$target = '.';
+while ($arg = array_shift($argv)) {
+ switch ($arg) {
+ case '-R':
+ $reverse = true;
+ break;
+ case '-j':
+ $join = true;
+ break;
+ case '-c':
+ $commit = true;
+ break;
+ case '-z':
+ $compress = true;
+ break;
+ case '-t':
+ $target = array_shift($argv);
+ break;
+ }
+}
+$target .= '/';
+
+$lines = array();
+while (!feof(STDIN)) {
+ $lines[] = fgets(STDIN);
+}
+foreach ($lines as $line) {
+ $line = trim($line);
+ if (empty($line)) {
+ continue;
+ }
+ $tok = preg_split('/\s+/', $line, -1, PREG_SPLIT_NO_EMPTY);
+ $file = str_replace(array('horde/', 'Attic/'), '', $tok[3]);
+ if (isset($tok[4]) && $tok[4] == '(dead)') {
+ $cmd = $CVS . ' remove -f ' . $file;
+ $new_version = $tok[0];
+ } elseif (isset($tok[4]) && $tok[4] == '(new)') {
+ $cmd = '';
+ $dir = dirname($file);
+ if (!is_dir($dir)) {
+ $cmd = "$CVS -f co $dir; ";
+ }
+ $cmd .= $CVS . ' up -j ' . $tok[0] . ' ' . $file;
+ $new_version = $tok[0];
+ } else {
+ if (count($tok) != 4) {
+ print "Unknown line format:\n" . $line . "\n";
+ continue;
+ }
+ $new_version = explode('.', $tok[0]);
+ $old_version = $new_version;
+ $old_version[count($old_version) - 1]--;
+ if ($old_version[count($old_version) - 1] == 0) {
+ unset($old_version[count($old_version) - 1]);
+ unset($old_version[count($old_version) - 1]);
+ }
+ $new_version = implode('.', $new_version);
+ $old_version = implode('.', $old_version);
+ if ($reverse) {
+ $tmp = $new_version;
+ $new_version = $old_version;
+ $old_version = $tmp;
+ }
+ if ($join) {
+ $cmd = sprintf($CVS . ' up -j %s -j %s -kk %s',
+ $old_version,
+ $new_version,
+ $file);
+ } else {
+ $cmd = sprintf($CVS . ' diff -N -r %s -r %s -kk %s | patch %s',
+ $old_version,
+ $new_version,
+ $file,
+ $target . $file);
+ }
+ }
+ print $cmd . "\n";
+ system($cmd . ' 2>&1', $exit);
+ print "\n";
+
+ if ($exit !== 0) {
+ continue;
+ }
+
+ // Compress JS files if necessary
+ if ($compress && $old_version &&
+ preg_match('/^([^\/]+)\/(.+)\/(.+)$/', $file, $matches) &&
+ $matches[2] == 'js/src') {
+ $currdir = getcwd();
+ chdir(implode('/', array($matches[1], $matches[2])));
+ passthru('php ' . $currdir . '/framework/devtools/horde-js-compress.php --file=' . $matches[3]);
+ chdir($currdir);
+ if ($commit) {
+ print "Commit doesn't work for compressed JS files - you need to commit manually.\n";
+ }
+ }
+
+ if ($commit) {
+ $cmd = sprintf($CVS . ' ci -m "%s: %s" %s',
+ $reverse ? 'Revert' : (substr_count($new_version, '.') > 1 ? 'MFB' : 'MFH'),
+ $reverse ? $old_version : $new_version,
+ $file);
+ print $cmd . "\n";
+ system($cmd . ' 2>&1');
+ }
+}
--- /dev/null
+#!/bin/sh
+#
+# Script to compare revisions and ignore files that should be different, and
+# differences in revision numbers.
+# Syntax: ./compare_revisions.sh FIRST_FOLDER SECOND_FOLDER ['ADDITIONAL PARAMETERS']
+
+FIRST=$1
+SECOND=$2
+shift 2
+diff -r -I "\$Horde" -I "\$Revision" -I "\$Date" -I "\$Id" --exclude version.php --exclude CHANGES --exclude CREDITS --exclude '*.po' --exclude '*.pot' --exclude locale --exclude CVS --exclude '.#*' --exclude '*~' --exclude '*.bak' --exclude '*.orig' --exclude '*.rej' "$@" $FIRST $SECOND | grep -v "config/.*\.php "
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<package packagerversion="1.4.9" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+http://pear.php.net/dtd/tasks-1.0.xsd
+http://pear.php.net/dtd/package-2.0
+http://pear.php.net/dtd/package-2.0.xsd">
+ <name>devtools</name>
+ <channel>pear.horde.org</channel>
+ <summary>Horde Developer Tools</summary>
+ <description>This package contains scripts useful to people doing Horde development.
+ </description>
+ <lead>
+ <name>Chuck Hagenbuch</name>
+ <user>chuck</user>
+ <email>chuck@horde.org</email>
+ <active>yes</active>
+ </lead>
+ <lead>
+ <name>Jan Schneider</name>
+ <user>jan</user>
+ <email>jan@horde.org</email>
+ <active>yes</active>
+ </lead>
+ <date>2009-12-23</date>
+ <version>
+ <release>0.2.0</release>
+ <api>0.2.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>* Initial Horde 4 release.
+ </notes>
+ <contents>
+ <dir name="/">
+ <file name="horde-fw-symlinks.php" role="script">
+ <tasks:replace from="@php_bin@" to="php_bin" type="pear-config"/>
+ </file>
+ <file name="horde-highlight.php" role="script">
+ <tasks:replace from="@php_bin@" to="php_bin" type="pear-config"/>
+ </file>
+ <file name="horde-merge.php" role="script">
+ <tasks:replace from="@php_bin@" to="php_bin" type="pear-config"/>
+ </file>
+ <file name="horde-rev-cmp.sh" role="script" />
+ </dir> <!-- / -->
+ </contents>
+ <dependencies>
+ <required>
+ <php>
+ <min>5.2.0</min>
+ </php>
+ <pearinstaller>
+ <min>1.7.0</min>
+ </pearinstaller>
+ </required>
+ </dependencies>
+ <phprelease>
+ <filelist>
+ <install name="horde-fw-symlinks.php" as="horde-fw-symlinks.php" />
+ <install name="horde-highlight.php" as="horde-highlight.php" />
+ <install name="horde-merge.php" as="horde-merge.php" />
+ <install name="horde-rev-cmp.sh" as="horde-rev-cmp.sh" />
+ </filelist>
+ </phprelease>
+ <changelog>
+ <release>
+ <date>2006-09-11</date>
+ <version>
+ <release>0.2.0</release>
+ <api>0.2.0</api>
+ </version>
+ <stability>
+ <release>beta</release>
+ <api>beta</api>
+ </stability>
+ <license uri="http://www.gnu.org/copyleft/lesser.html">LGPL</license>
+ <notes>* Initial Horde 4 release.
+ </notes>
+ </release>
+ </changelog>
+</package>