aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'gentoolkit-dev/src')
-rw-r--r--gentoolkit-dev/src/ebump/AUTHORS5
-rw-r--r--gentoolkit-dev/src/ebump/ChangeLog8
-rw-r--r--gentoolkit-dev/src/ebump/Makefile20
-rw-r--r--gentoolkit-dev/src/ebump/README18
-rw-r--r--gentoolkit-dev/src/ebump/TODO0
-rwxr-xr-xgentoolkit-dev/src/ebump/ebump390
-rw-r--r--gentoolkit-dev/src/ebump/ebump.1110
-rw-r--r--gentoolkit-dev/src/echangelog/AUTHORS1
-rw-r--r--gentoolkit-dev/src/echangelog/ChangeLog84
-rw-r--r--gentoolkit-dev/src/echangelog/Makefile26
-rw-r--r--gentoolkit-dev/src/echangelog/README11
-rw-r--r--gentoolkit-dev/src/echangelog/TODO0
-rwxr-xr-xgentoolkit-dev/src/echangelog/echangelog805
-rw-r--r--gentoolkit-dev/src/echangelog/echangelog.1270
-rw-r--r--gentoolkit-dev/src/echangelog/test/TEST.pm26
-rw-r--r--gentoolkit-dev/src/echangelog/test/templates/test.patch6
-rw-r--r--gentoolkit-dev/src/echangelog/test/templates/vcstest-0.0.1.ebuild16
-rwxr-xr-xgentoolkit-dev/src/echangelog/test/test.sh176
-rw-r--r--gentoolkit-dev/src/ego/AUTHOR1
-rw-r--r--gentoolkit-dev/src/ego/AUTHORS1
-rw-r--r--gentoolkit-dev/src/ego/ChangeLog2
-rw-r--r--gentoolkit-dev/src/ego/Makefile18
-rw-r--r--gentoolkit-dev/src/ego/README2
-rw-r--r--gentoolkit-dev/src/ego/TODO0
-rw-r--r--gentoolkit-dev/src/ego/ego86
-rw-r--r--gentoolkit-dev/src/ekeyword/AUTHORS1
-rw-r--r--gentoolkit-dev/src/ekeyword/ChangeLog46
-rw-r--r--gentoolkit-dev/src/ekeyword/Makefile26
-rw-r--r--gentoolkit-dev/src/ekeyword/README20
-rw-r--r--gentoolkit-dev/src/ekeyword/TODO0
-rwxr-xr-xgentoolkit-dev/src/ekeyword/ekeyword147
-rw-r--r--gentoolkit-dev/src/ekeyword/ekeyword.pod68
-rwxr-xr-xgentoolkit-dev/src/ekeyword2/ekeyword296
-rw-r--r--gentoolkit-dev/src/eshowkw/Makefile18
-rw-r--r--gentoolkit-dev/src/eshowkw/eshowkw357
-rw-r--r--gentoolkit-dev/src/eshowkw/eshowkw.114
-rw-r--r--gentoolkit-dev/src/eviewcvs/AUTHORS1
-rw-r--r--gentoolkit-dev/src/eviewcvs/Makefile25
-rw-r--r--gentoolkit-dev/src/eviewcvs/README11
-rwxr-xr-xgentoolkit-dev/src/eviewcvs/eviewcvs95
-rw-r--r--gentoolkit-dev/src/eviewcvs/eviewcvs.pod48
-rw-r--r--gentoolkit-dev/src/imlate/Makefile18
-rwxr-xr-xgentoolkit-dev/src/imlate/imlate484
-rw-r--r--gentoolkit-dev/src/imlate/imlate.148
44 files changed, 3605 insertions, 0 deletions
diff --git a/gentoolkit-dev/src/ebump/AUTHORS b/gentoolkit-dev/src/ebump/AUTHORS
new file mode 100644
index 0000000..2432e06
--- /dev/null
+++ b/gentoolkit-dev/src/ebump/AUTHORS
@@ -0,0 +1,5 @@
+Maintainer:
+Karl Trygve Kalleberg <karltk@gentoo.org>
+
+Original author:
+Karl Trygve Kalleberg <karltk@gentoo.org>
diff --git a/gentoolkit-dev/src/ebump/ChangeLog b/gentoolkit-dev/src/ebump/ChangeLog
new file mode 100644
index 0000000..4434b94
--- /dev/null
+++ b/gentoolkit-dev/src/ebump/ChangeLog
@@ -0,0 +1,8 @@
+2004-06-21 Karl Trygve Kalleberg <karltk@gentoo.org>
+ * Fixed handling of deletion.
+
+2004-03-11 Karl Trygve Kalleberg <karltk@gentoo.org>
+ * Fixed incorrect cut'ing of wc -l output when updating ChangeLog
+
+2004-02-08 Karl Trygve Kalleberg <karltk@gentoo.org>
+ * Initial import
diff --git a/gentoolkit-dev/src/ebump/Makefile b/gentoolkit-dev/src/ebump/Makefile
new file mode 100644
index 0000000..aa1d347
--- /dev/null
+++ b/gentoolkit-dev/src/ebump/Makefile
@@ -0,0 +1,20 @@
+# Copyright 2004 Karl Trygve Kalleberg <karltk@gentoo.org>
+# Copyright 2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+#
+# $Header$
+
+include ../../makedefs.mak
+
+.PHONY: all
+all:
+
+dist:
+ mkdir -p ../../$(distdir)/src/ebump/
+ cp Makefile AUTHORS README TODO ChangeLog ebump ebump.1 ../../$(distdir)/src/ebump/
+
+install: all
+ install -m 0755 ebump $(bindir)/
+ install -d $(docdir)/ebump
+ install -m 0644 AUTHORS README TODO ChangeLog $(docdir)/ebump/
+ install -m 0644 ebump.1 $(mandir)/
diff --git a/gentoolkit-dev/src/ebump/README b/gentoolkit-dev/src/ebump/README
new file mode 100644
index 0000000..c81835c
--- /dev/null
+++ b/gentoolkit-dev/src/ebump/README
@@ -0,0 +1,18 @@
+
+Package : ebump
+Version : 0.1.0
+Author : See AUTHORS
+
+MOTIVATION
+
+The ebump utility is a Gentoo-specific tool for bumping the revision of
+a given ebuild and auxiliary files in the Portage tree. It is only
+useful for Gentoo developers with CVS commit access.
+
+MECHANICS
+
+N/A
+
+IMPROVEMENTS
+
+N/A
diff --git a/gentoolkit-dev/src/ebump/TODO b/gentoolkit-dev/src/ebump/TODO
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gentoolkit-dev/src/ebump/TODO
diff --git a/gentoolkit-dev/src/ebump/ebump b/gentoolkit-dev/src/ebump/ebump
new file mode 100755
index 0000000..b877318
--- /dev/null
+++ b/gentoolkit-dev/src/ebump/ebump
@@ -0,0 +1,390 @@
+#! /bin/sh
+#
+# Copyright (c) 2004 Karl Trygve Kalleberg <karltk@gentoo.org>
+# Copyright (c) Gentoo Technologies, Inc.
+# Licensed under the GNU General Public License, version 2
+#
+# Maintainer: Karl Trygve Kalleberg <karltk@gentoo.org>
+
+__version__="0.1.0"
+__author__="Karl Trygve Kalleberg"
+__email__="<karltk@gentoo.org>"
+__description__="Ebuild version bumping tool"
+
+
+
+die() {
+ echo $1 > /dev/stderr
+ exit -1
+}
+
+einfo() {
+ if [ ${opt_verbosity} -gt 1 ] ; then
+ echo $*
+ fi
+}
+
+print_version() {
+ echo "${__description__}, v${__version__}"
+ echo "Copyright (c) 2004 ${__author__} ${__email__}"
+ echo "Copyright (c) 2004 Gentoo Technologies, Inc."
+ echo "Licensed under the GNU General Public License, version 2"
+}
+
+print_usage() {
+ echo "Usage: ebump <options> foo<.ebuild>"
+ echo "Ebuild version bumping tool, v${__version__}"
+ echo " -V|--version show version info"
+ echo " -v|--verbose increase verbosity"
+ echo " -q|--quiet turn off output"
+ echo " -C|--no-vcs do not add to VCS"
+ echo " -m|--message append message to ChangeLog"
+ echo " -d|--delete-old delete previous revision from VCS (DANGEROUS!)"
+}
+
+#
+# Load options from /etc/gentoolkit/ebump.conf and ${HOME}/.gentoo/ebump.conf
+# Home directory file takes precedence.
+#
+load_options() {
+
+ # FIXME: Sourcing config files like this is really a bad idea; users may
+ # easily override any function in this program inside his config files.
+
+ if [ -f /etc/gentoolkit/ebump.conf ] ; then
+ . /etc/gentoolkit/ebump.conf
+ fi
+ if [ -f ${HOME}/.gentoo/gentool-env ] ; then
+ . ${HOME}/.gentoo/gentool-env
+ fi
+ if [ -f ${HOME}/.gentoo/ebump.conf ] ; then
+ . ${HOME}/.gentoo/ebump.conf
+ fi
+
+ # FIXME: remove this warning in 2-3 releases.
+ if [[ -n ${opt_add_cvs} ]];
+ then
+ echo "Warning: opt_add_cvs is deprecated, please use opt_add_vcs from now on!" >/dev/stderr
+ fi
+}
+
+#
+# Find closes ebuild to ${1}, if any
+#
+find_ebuild() {
+ f=${1}
+
+ if [ -f ${1} ] ; then
+ echo ${1}
+ fi
+
+ if [ -f ${1}.ebuild ] ; then
+ echo ${1}
+ fi
+}
+
+#
+# splitname (version|name|revision) package-name-version-revision
+#
+splitname() {
+ case $1 in
+ version)
+ echo ${2} | sed -r "s/.*-([0-9].*)/\1/"
+ ;;
+ name)
+ name=$(echo ${2} | sed -r "s/(.*)-[0-9].*/\1/")
+ if [ ${name} == ${2} ] ; then
+ if [ $(echo ${2} | grep "^[0-9].*") ] ; then
+ # The filename starts with a version number, thus it has no
+ # name
+ name=""
+ else
+ # The filename doesn't have a recognizeable version number;
+ # everything is a name
+ name=${2}
+ fi
+ fi
+ echo ${name}
+ ;;
+ revision)
+ rev=$(echo ${2} | sed -r "s/.*-r([0-9][0-9]*)/\1/")
+ if [ ${rev} == ${2} ] ; then
+ rev=0
+ fi
+ echo ${rev}
+ ;;
+ vernorev)
+ ver=$(echo ${2} | sed -r "s/.*-([0-9].*)-r[0-9]+/\1/")
+ if [ ${ver} == ${2} ] ; then
+ ver=$(echo ${2} | sed -r "s/.*-([0-9].*)/\1/")
+ fi
+ echo ${ver}
+ ;;
+ *)
+ echo
+ esac
+}
+
+process_ebuild() {
+ vcs=$1
+ ebuild_arg=$2
+ shift $#
+
+ # Files to add to VCS
+ addfiles=""
+ # Files to remove from VCS
+ delfiles=""
+
+ if [ -z ${ebuild_arg} ] ; then
+ print_usage
+ exit
+ fi
+
+ #
+ # Try to find a matching ebuild
+ #
+
+ ebuild_name=$(find_ebuild ${ebuild_arg})
+ if [ -z ${ebuild_name} ] ; then
+ die "Could not find ${ebuild_arg}"
+ fi
+ einfo "Processing ebuild ${ebuild_name}"
+
+ #
+ # Bump revision suffix (or add one)
+ #
+
+ PF=$(basename ${ebuild_name} .ebuild)
+ PN=$(splitname name ${PF})
+ PV=$(splitname version ${PF})
+ rev=$(splitname revision ${PF})
+ PV_norev=$(splitname vernorev ${PF})
+ newPF=${PN}-${PV_norev}-r$[rev+1]
+
+# echo $PF / $PN / $PV / $rev / $PV_norev / $newPF
+
+ einfo "Bumped ${PF}.ebuild to ${newPF}.ebuild"
+
+ if [[ "${vcs}" == "svn" ]];
+ then
+ svn cp ${PF}.ebuild ${newPF}.ebuild
+ else
+ cp ${PF}.ebuild ${newPF}.ebuild
+ fi
+
+ einfo "Reset keywords to ~arch"
+
+ ekeyword '~all' "${newPF}.ebuild"
+
+ addfiles="${addfiles} ${newPF}.ebuild"
+ delfiles="${delfiles} ${PF}.ebuild"
+
+ #
+ # (Optional) Bump relevant files in files/
+ #
+
+ if [ "${opt_bump_auxfiles}" == "y" ] ; then
+
+ # Gather list of auxiliary files in files/ that has a versioned
+ # filename, where the version matches our current version.
+
+ bumplist=""
+ for x in $(echo files/*) ; do
+ if [ ! -z $(echo $x | grep "${PV}$") ] ; then
+ bumplist="${bumplist} ${x}"
+ fi
+ done
+
+ # Bump version of all matches
+
+ for x in ${bumplist} ; do
+
+ bn=$(basename ${x})
+ dn=$(dirname ${x})
+
+ PN=$(splitname name ${bn})
+ PV=$(splitname version ${bn})
+ rev=$(splitname revision ${bn})
+ PV_norev=$(splitname vernorev ${bn})
+
+# echo $PN / ${PV_norev} / ${rev}
+
+ # Special case for when we have no name part; filename
+ # is just a version number
+ if [ -z "${PN}" ] ; then
+ newbn=${PV_norev}-r$[rev+1]
+ else
+ newbn=${PN}-${PV_norev}-r$[rev+1]
+ fi
+
+ if [ -d ${dn}/${bn} ] ; then
+ if [ -e ${dn}/${newbn} ] ; then
+ echo "Directory ${dn}/${newbn} exists, not copying" > /dev/stderr
+ else
+ cp -a ${dn}/${bn} ${dn}/${newbn}
+ # uhm, is that necessary?
+# find ${dn}/${newbn} -name CVS | xargs rm -rf
+ fi
+ else
+ cp ${dn}/${bn} ${dn}/${newbn}
+ fi
+
+ addfiles="${addfiles} ${dn}/${newbn}"
+ delfiles="${delfiles} ${dn}/${bn}"
+
+ einfo "Bumped ${dn}/${bn} to ${dn}/${newbn}"
+ done
+ fi
+
+# echo "addfiles ${addfiles}"
+# echo "delfiles ${delfiles}"
+
+ filelist="${addfiles}"
+
+ #
+ # (Optional) Add VCS entry for all new files
+ #
+ if [ "${opt_add_vcs}" == "y" ] ; then
+ for x in ${addfiles} ; do
+ if [ -d ${x} ] ; then
+ find ${x} -exec ${vcs} add {} ';'
+ else
+ ${vcs} add ${x}
+ fi
+ done
+ einfo "Added ${addfiles} to VCS"
+ fi
+
+
+ #
+ # (Optional) Delete previous entry
+ #
+ # Could we use 'rm' instead of remove for all vcs?
+ if [ "${opt_delete_old}" == "y" ] ; then
+ for x in ${delfiles} ; do
+ if [[ "${vcs}" == "cvs" ]];
+ then
+ ${vcs} remove -f ${x}
+ elif [[ "${vcs}" == "git" ]];
+ then
+ ${vcs} rm ${x}
+ else
+ ${vcs} remove ${x}
+ fi
+ done
+ einfo "Removed ${delfiles} from VCS"
+ fi
+
+ #
+ # (Optional) Add ChangeLog entry
+ #
+ if [[ "${opt_add_changelog}" == "y" ]] && [[ "${opt_add_vcs}" == "y" ]];
+ then
+ # FIXME: remove this warning in 2-3 releases
+ if [[ -n ${AUTHORNAME} ]] || [[ -n ${AUTHOREMAIL} ]];
+ then
+ echo "Warning: AUTHORNAME and AUTHOREMAIL is deprecated!" >/dev/stderr
+ echo "Please take a look at echangelog(1)." >/dev/stderr
+ echo "To avoid this warning unset AUTHORNAME and AUTHOREMAIL." >/dev/stderr
+ fi
+
+ echangelog "${opt_commitmessage}" || set $?
+
+ if [[ ${1:-0} -ne 0 ]];
+ then
+ einfo "Modifying ChangeLog failed!"
+ else
+ einfo "Added ChangeLog entry"
+ fi
+ fi
+}
+
+function get_vcs() {
+ if [[ -d "CVS" ]];
+ then
+ echo "cvs"
+ return 0
+ elif [[ -d ".svn" ]];
+ then
+ echo "svn"
+ return 0
+ else
+ if [[ -x "$(which git)" ]];
+ then
+ if [[ -n "$(git rev-parse --git-dir 2>/dev/null)" ]];
+ then
+ echo "git"
+ return 0
+ fi
+ fi
+ echo
+ return 1
+ fi
+}
+
+original_params=${#}
+
+#
+# Global options
+#
+opt_verbosity=1
+opt_warn_on_delete=y
+opt_add_changelog=y
+opt_add_vcs=y
+opt_bump_auxfiles=y
+opt_delete_old=n
+opt_commitmessage=""
+
+load_options
+
+skip=0
+while [ ${#} -gt 0 ] ; do
+ arg=${1}
+ shift
+ if [ ${skip} -gt 0 ] ; then
+ skip=$[skip-1]
+ else
+ case ${arg} in
+ -h|--help)
+ print_usage
+ exit 0
+ ;;
+ -m|--message)
+ opt_commitmessage="${1}"
+ skip=1
+ ;;
+ -C|--no-vcs)
+ opt_add_vcs=n
+ ;;
+ -V|--version)
+ print_version
+ exit
+ ;;
+ -v|--verbose)
+ opt_verbosity=$[opt_verbosity + 1]
+ ;;
+ -q|--quiet)
+ opt_verbosity=0
+ ;;
+ -d|--delete-old)
+ opt_delete_old=y
+ ;;
+ *)
+ ebuild_arg=${arg}
+ ;;
+ esac
+ fi
+done
+
+_vcs=$(get_vcs)
+if [[ -z "${_vcs}" ]];
+then
+ echo "Warning: no cvs, git or svn repository found!" >/dev/stderr
+ echo "Changes can't be added to the VCS" >/dev/stderr
+ opt_add_vcs=n
+ opt_delete_old=n
+fi
+process_ebuild "${_vcs}" ${ebuild_arg}
+
+# TODO:
+# - put cli parser into separate functions
diff --git a/gentoolkit-dev/src/ebump/ebump.1 b/gentoolkit-dev/src/ebump/ebump.1
new file mode 100644
index 0000000..38cd795
--- /dev/null
+++ b/gentoolkit-dev/src/ebump/ebump.1
@@ -0,0 +1,110 @@
+.TH "ebump" "1" "0.1.0" "Gentoolkit" "Gentoo Administration"
+.SH "NAME"
+.LP
+ebump \- Gentoo: Ebuild revision bumper
+.SH "SYNTAX"
+.LP
+ebump [\fIoption\fP] <\fIpackage-name[-version]\fP>
+
+.SH "DESCRIPTION"
+
+.LP
+\fIebump\fR bumps the revision of a particular ebuild, and all auxiliary
+files in the files/ directory that have a matching version suffix.
+
+.LP
+By default, the all new revision files will be added to the VCS.
+
+.LP
+You must stand in the directory of the ebuild to be bumped.
+
+.SH "OPTIONS"
+.LP
+\fB\-C\fR
+.br
+\fB--no-vcs\fB
+.IP
+Do not add new files to VCS.
+
+.LP
+\fB\-V\fR
+.br
+\fB--version\fB
+.IP
+Display version information and exit.
+
+.LP
+\fB\-v\fR
+.br
+\fB--verbose\fB
+.IP
+Increase verbosity level. May be used more than once.
+
+.LP
+\fB\-q\fR
+.br
+\fB--quiet\fB
+.IP
+Do not output any non-essential information.
+
+.LP
+\fB\-m\fR <\fIChangeLog text\fR>
+.br
+\fB\--message\fR <\fIChangeLog text\fR>
+.IP
+Specifies the message to add to the ChangeLog, instead of the standard
+placeholder.
+
+.LP
+\fB\-d\fR
+.br
+\fB\--delete-old\fR
+.IP
+Delete old revision and old auxiliary files from VCS. This is
+\fIdangerous\fR and should only be used if you know exactly what you are
+doing, because
+.br
+1) the old revision may be stable on a different architecture than the one you
+are working on.
+.br
+2) the auxiliary files may be required by other versions of the ebuild.
+.br
+3) the new revision should usually undergo a period of testing before being marked stable.
+
+.SH "CONFIGURATION"
+
+.LP
+\fB/etc/gentoolkit/ebump.conf\fR
+.br
+\fB~/.gentoo/ebump.conf\fR
+.IP
+From these files, \fIebump\fR will load the settings
+.br
+\fBopt_verbosity\fR (default \fI1\fR) - verbosity level 0-10
+.br
+\fBopt_add_changelog\fR (default \fIy\fR) - add entry in ChangeLog
+.br
+\fBopt_add_vcs\fR (default \fIy\fR) - add new files to VCS
+.br
+\fBopt_bump_auxfiles\fR (default \fIy\fR) - bump auxiliary files in files/
+.br
+\fBopt_delete_old\fR (default \fIn\fR) - delete old revision (DANGEROUS!)
+.br
+\fBopt_commitmessage\fR (default \fI""\fR) - default ChangeLog message
+
+.LP
+\fB(DEPRECATED)\fR
+.br
+\fB~/.gentoo/gentool-env\fR
+.IR
+From this file, \fIebump\fR will load the env vars \fBAUTHORNAME\fR and
+\fBAUTHOREMAIL\fR, which are used to generate proper ChangeLog entries.
+
+.SH "SEE ALSO"
+.LP
+The rest of the utilities in \fIapp-portage/gentoolkit-dev\fR, such as
+\fIechangelog(1)\fR and \fIekeyword(1)\fR.
+
+.SH "AUTHORS"
+.LP
+Karl Trygve Kalleberg <karltk@gentoo.org>
diff --git a/gentoolkit-dev/src/echangelog/AUTHORS b/gentoolkit-dev/src/echangelog/AUTHORS
new file mode 100644
index 0000000..36d5bfd
--- /dev/null
+++ b/gentoolkit-dev/src/echangelog/AUTHORS
@@ -0,0 +1 @@
+Aron Griffis <agriffis@gentoo.org>
diff --git a/gentoolkit-dev/src/echangelog/ChangeLog b/gentoolkit-dev/src/echangelog/ChangeLog
new file mode 100644
index 0000000..c1c5885
--- /dev/null
+++ b/gentoolkit-dev/src/echangelog/ChangeLog
@@ -0,0 +1,84 @@
+26 Mar 2006 Aron Griffis <agriffis@gentoo.org>
+ * echangelog: Don't warn about missing ebuilds when updating
+ copyrights #120061
+
+27 Apr 2005 Aron Griffis <agriffis@gentoo.org>
+ * more changes for #90326; report all trivial files if no significant
+ changes can be found
+
+26 Apr 2005 Aron Griffis <agriffis@gentoo.org>
+ * detect conflicts explicitly
+ * report ChangeLog in the list of files if it's the only file that is
+ changing #90326
+
+23 Mar 2005 Aron Griffis <agriffis@gentoo.org>
+ * handle package moves without adding new version lines
+
+08 Mar 2005 Aron Griffis <agriffis@gentoo.org>
+ * don't complain about cvs add of digests #84377
+ * use gmtime instead of localtime
+
+07 Mar 2005 Aron Griffis <agriffis@gentoo.org>
+ * report all changed versions #84332
+
+25 Feb 2005 Aron Griffis <agriffis@gentoo.org>
+ * strip GECOS #80011
+
+09 Nov 2004 Aron Griffis <agriffis@gentoo.org>
+ * change "cvs diff -fU 0" => "cvs -f diff U0" because -f is a
+ global option, not a diff option
+
+08 Nov 2004 Aron Griffis <agriffis@gentoo.org>
+ * call cvs with -f to refrain from using .cvsrc, which might
+ contain conflicting options
+ * fix auto-addition of ChangeLog; last attempt was broken
+
+03 Nov 2004 Aron Griffis <agriffis@gentoo.org>
+ * abort when there are unresolved files (files that aren't under
+ revision control) just like repoman
+ * auto-add to cvs when a new ChangeLog is created
+
+15 Sep 2004 Aron Griffis <agriffis@gentoo.org>
+ * fix the wrapping to fit in 80 columns properly. It was
+ previously possible to get lines with 81 chars. Thanks to
+ ciaranm for reporting.
+
+29 Mar 2004 Aron Griffis <agriffis@gentoo.org>
+ * fix bug 46111 by testing for /<root@/ instead of / root@/
+
+28 Mar 2004 Aron Griffis <agriffis@gentoo.org>
+ * apply patch from plasmaroo, with minor modifications, to enable EDITOR
+ and +- support
+
+27 Mar 2004 Michael Sterrett <mr_bones_@gentoo.org>
+ * don't fall out of the loop if update_copyright() didn't change
+ anything. Just go on to the next file.
+
+21 Mar 2004 Aron Griffis <agriffis@gentoo.org>
+ * Fix typo $0 -> 0
+
+19 Mar 2004 Aron Griffis <agriffis@gentoo.org>
+ * Remove debugging output
+ * Fix $v bug introduced in last commit
+
+16 Mar 2004 Aron Griffis <agriffis@gentoo.org>
+ * Make Feb 17 behavior work without Feb 20 bug :-)
+ * Release as version 0.2.0
+
+20 Feb 2004 Aron Griffis <agriffis@gentoo.org>
+ * Only update copyrights on modified ebuilds, otherwise if you run
+ echangelog again, it reports that all the ebuilds have been updated!
+ The copyright year issue would be better solved on Jan 1 of each year by
+ a separate script.
+
+17 Feb 2004 Aron Griffis <agriffis@gentoo.org>
+ * Update copyrights on all ebuilds, not just the modified ones
+
+07 Jan 2004 Aron Griffis <agriffis@gentoo.org>
+ * Updated Makefile to understand building man-page from pod
+ * Removed static man-page in favor of generated man-page from pod
+ * Added copyright year updating
+ * Allow echangelog to run even when no files have changed
+
+2004-01-07 Karl Trygve Kalleberg <karltk@gentoo.org>
+ * Added Makefile
diff --git a/gentoolkit-dev/src/echangelog/Makefile b/gentoolkit-dev/src/echangelog/Makefile
new file mode 100644
index 0000000..a3e5aac
--- /dev/null
+++ b/gentoolkit-dev/src/echangelog/Makefile
@@ -0,0 +1,26 @@
+# Copyright 2004 Karl Trygve Kalleberg <karltk@gentoo.org>
+# Copyright 2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+#
+# $Header$
+
+include ../../makedefs.mak
+
+.PHONY: all test
+
+all:
+
+test:
+ cd test; bash test.sh
+
+dist:
+ mkdir -p ../../$(distdir)/src/echangelog/test/templates
+ cp Makefile AUTHORS README TODO ChangeLog echangelog echangelog.1 ../../$(distdir)/src/echangelog/
+ cp test/TEST.pm test/test.sh ../../$(distdir)/src/echangelog/test/
+ cp test/templates/test.patch test/templates/vcstest-0.0.1.ebuild ../../$(distdir)/src/echangelog/test/templates
+
+install: all
+ install -m 0755 echangelog $(bindir)/
+ install -d $(docdir)/echangelog
+ install -m 0644 AUTHORS README $(docdir)/echangelog/
+ install -m 0644 echangelog.1 $(mandir)/
diff --git a/gentoolkit-dev/src/echangelog/README b/gentoolkit-dev/src/echangelog/README
new file mode 100644
index 0000000..77a7930
--- /dev/null
+++ b/gentoolkit-dev/src/echangelog/README
@@ -0,0 +1,11 @@
+Most of the documentation is contained in the man-page, which you can
+read directly (using GNU man) by doing
+
+ man ./echangelog.1
+
+To rebuild the man-page from pod source, do
+
+ pod2man --name=echangelog --center='Gentoolkit' \
+ echangelog.pod echangelog.1
+
+03 Nov 2004 agriffis
diff --git a/gentoolkit-dev/src/echangelog/TODO b/gentoolkit-dev/src/echangelog/TODO
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gentoolkit-dev/src/echangelog/TODO
diff --git a/gentoolkit-dev/src/echangelog/echangelog b/gentoolkit-dev/src/echangelog/echangelog
new file mode 100755
index 0000000..b414b1f
--- /dev/null
+++ b/gentoolkit-dev/src/echangelog/echangelog
@@ -0,0 +1,805 @@
+#!/usr/bin/perl -w
+#
+# echangelog: Update the ChangeLog for an ebuild. For example:
+#
+# $ echangelog 'Add ~alpha to KEYWORDS'
+# 4a5,7
+# > 10 Feb 2003; Aron Griffis <agriffis@gentoo.org> oaf-0.6.8-r1.ebuild :
+# > Add ~alpha to KEYWORDS
+# >
+
+use strict;
+use POSIX qw(strftime getcwd setlocale);
+use File::Basename;
+use Getopt::Long;
+
+# Fix bug 21022 by restricting to C locale
+setlocale(&POSIX::LC_ALL, "C");
+
+use Text::Wrap;
+$Text::Wrap::columns = 77;
+$Text::Wrap::unexpand = 0;
+
+# Global variables
+my (@files, @ebuilds, @conflicts, @trivial, @unknown, @new_versions, %actions);
+my ($input, $editor, $entry, $user, $date, $text, $vcs);
+my ($opt_help, $opt_nostrict, $opt_force_vcs, $opt_version);
+
+$opt_help = 0;
+$opt_nostrict = 0;
+$opt_version = 0;
+# DEPRECATED
+my $opt_strict = 0;
+
+my %vcs = (
+ bzr => {
+ directory => ".bzr",
+ diff => "bzr diff",
+ status => "bzr status -S .",
+ add => "bzr add",
+ skip => 3,
+ # The same as for hg.
+ regex => qr/^=== \S+ file '\S+\/\S+\/((\S+)\.ebuild)/
+ },
+ cvs => {
+ directory => "CVS",
+ diff => "cvs -f diff -U0",
+ status => "cvs -fn up",
+ add => "cvs -f add",
+ skip => 6,
+ regex => qr/^Index: (([^\/]*?)\.ebuild)\s*$/
+ },
+ git => {
+ directory => ".git",
+ diff => "git diff",
+ status => "git diff-index HEAD --name-status",
+ add => "git add",
+ # This value should usually be 3 but on new file mode we need skip+1.
+ # So 4 should be fine anyway.
+ skip => 4,
+ regex => qr/^diff \-\-git \S*\/((\S*)\.ebuild)/
+ },
+ hg => {
+ directory => ".hg",
+ diff => "hg diff",
+ status => "hg status .",
+ add => "hg add",
+ skip => 3,
+ # hg diff is relative to the root.
+ # TODO: Write a proper regex :)
+ regex => qr/diff \-r \S+ \S+\/\S+\/((\S+)\.ebuild)/
+ },
+ svn => {
+ directory => ".svn",
+ diff => "svn diff -N",
+ status => "svn status",
+ add => "svn add",
+ skip => 4,
+ regex => qr/^Index: (([^\/]*?)\.ebuild)\s*$/
+ },
+);
+
+sub usage {
+ (my $usage = <<" EOF") =~ s/^\t//gm;
+ Usage: echangelog [options] <changelog message>
+
+ Options:
+ --help err, this screen ...
+ --no-strict do not abort on trivial/no changes
+ --vcs <vcs> skip vcs autodetection and use the specified vcs instead
+ for a list of supported version control systems see below
+ --version show version info
+
+ Supported VCS: bzr, cvs, git, hg, svn
+ EOF
+ print $usage;
+ exit 0;
+}
+
+sub version {
+ my $Revision = "Last svn change rev";
+ my $Date = "Last svn change date";
+ my $foo = "";
+ print "echangelog\n$Revision$foo \n$Date$foo\n";
+ exit 0;
+}
+
+sub getenv($) {
+ my $key = shift;
+
+ # Ensure our variable exist
+ if ( defined($ENV{$key}) ) {
+ # Ensure we don't get empty variables
+ if ( length($ENV{$key}) > 0 ) {
+ return $ENV{$key};
+ }
+ }
+ return undef;
+}
+
+# Bug 264146.
+# Copied from Text::Wrap.
+# The only modified thing is:
+# We trim _just_ tab/space etc. but not \n/\r.
+# \s treats even \n/\r as whitespace.
+# BUGS:
+# ' test'
+# ' test'
+# Will end up in:
+# ' test'
+# ''
+# 'test'
+# See 'my $ps = ($ip eq $xp) ? "\n\n" : "\n";'
+sub text_fill {
+ my ($ip, $xp, @raw) = @_;
+ my @para;
+ my $pp;
+
+ for $pp ( split(/\n\s+/, join("\n", @raw)) ) {
+ $pp =~ s/[\x09\x0B\x0C\x20]+/ /g;
+ my $x = Text::Wrap::wrap($ip, $xp, $pp);
+ push(@para, $x);
+ }
+
+ # if paragraph_indent is the same as line_indent,
+ # separate paragraphs with blank lines
+ my $ps = ($ip eq $xp) ? "\n\n" : "\n";
+ return join ($ps, @para);
+}
+
+sub changelog_info(%) {
+ my %changed = @_;
+
+ open(INFO, '>', 'ChangeLog.new');
+
+ print(INFO "\n");
+ print(INFO "# Please enter the ChangeLog message for your changes. Lines starting\n");
+ print(INFO "# with '#' will be ignored, and an empty message aborts the ChangeLog.\n");
+ print(INFO "#\n# Changes:\n");
+
+ foreach my $key (keys(%changed)) {
+ if ($changed{$key} eq "+") {
+ printf(INFO "# new file:\t%s\n", $key);
+ }
+ elsif ($changed{$key} eq "-") {
+ printf(INFO "# deleted:\t%s\n", $key);
+ }
+ else {
+ printf(INFO "# modified:\t%s\n", $key);
+ }
+ }
+
+ close(INFO);
+}
+
+sub update_cat_pn {
+ my $t = shift;
+ my $cwd = getcwd();
+
+ my $category = basename(dirname($cwd));
+ my $package_name = basename($cwd);
+
+ $t =~ s/^(# ChangeLog for).*/$1 $category\/$package_name/;
+
+ return $t;
+}
+
+# Check partent dirs recursivevly/backward
+sub check_vcs_dir {
+ my $type = shift;
+
+ my $dir = getcwd();
+ while($dir !~ /^\/$/) {
+ return 1 if -d "${dir}/${type}";
+ $dir = dirname($dir);
+ }
+ # Check / as well
+ return 1 if -d "/${type}";
+
+ return 0;
+}
+
+# Just to ensure we don't get duplicate entries.
+sub mypush(\@@) {
+ my $aref = shift;
+
+ foreach my $value (@_) {
+ push(@{$aref}, $value) if !grep(/^\Q$value\E$/, @{$aref});
+ }
+}
+
+GetOptions(
+ 'help' => \$opt_help,
+ 'no-strict' => \$opt_nostrict,
+ 'vcs=s' => \$opt_force_vcs,
+ 'version|v' => \$opt_version,
+ 'strict' => \$opt_strict,
+);
+
+usage() if $opt_help;
+version() if $opt_version;
+
+if($opt_strict) {
+ print STDERR "Warning: The option '--strict' has been deprecated and will be removed soon!\n";
+ print STDERR "--strict behaviour is now default.\n";
+}
+
+# Figure out what kind of repo we are in.
+# Respect $PATH while looking for the VCS
+if(! defined($opt_force_vcs)) {
+ if (getenv("PATH")) {
+ foreach my $path ( split(":", getenv("PATH")) ) {
+ foreach my $_vcs (sort(keys(%vcs))) {
+ if ( -X "${path}/${_vcs}" ) {
+ $vcs = $_vcs if check_vcs_dir($vcs{$_vcs}{directory});
+ last if $vcs;
+ }
+ }
+ last if $vcs;
+ }
+ }
+}
+else {
+ $vcs = $opt_force_vcs if defined $vcs{$opt_force_vcs};
+}
+
+if ( ! $vcs ) {
+ print STDERR "Either no CVS, .git, .svn, ... directories found, the specific VCS has not been\n";
+ print STDERR "installed or you don't have execute rights!\n";
+ exit(1);
+}
+
+# Read the current ChangeLog
+if (-f 'ChangeLog') {
+ open(I, '<', 'ChangeLog') or die "Can't open ChangeLog for input: $!\n";
+ { local $/ = undef; $text = <I>; }
+ close(I);
+} else {
+ # No ChangeLog here, maybe we should make one...
+ if (<*.ebuild>) {
+ open(C, '-|', "portageq portdir") or die "portageq returned with an error: $!\n";
+ my $portdir = <C>;
+ $portdir =~ s/\s+$//;
+ close(C);
+
+ die "Can't find PORTDIR\n" if (length $portdir == 0);
+
+ open(I, '<', "$portdir/skel.ChangeLog")
+ or die "Can't open $portdir/skel.ChangeLog for input: $!\n";
+ { local $/ = undef; $text = <I>; }
+ close(I);
+
+ $text =~ s/^\*.*//ms; # don't need the fake entry
+
+ $text = update_cat_pn($text);
+ } else {
+ die "This should be run in a directory with ebuilds...\n";
+ }
+}
+
+# Figure out what has changed around here
+open C, $vcs{$vcs}{status}.' 2>&1 |' or die "Can't run ".$vcs{$vcs}{status}.": $!\n";
+while (<C>) {
+ # I don't want mess our existing stuff with the horrible bazaar stuff.
+ # TODO: add stuff for untracked/conflicting files.
+ if ($vcs eq "bzr") {
+ # NEW, DELETED, MODIFIED
+ if (/^[\s\+\-]([NDM])\s+(.*)/) {
+ my ($status, $filename) = ($1, $2);
+ # strip category/package/ since everything is relative to the repo root.
+ $filename =~ s/^([^\/]+\/){2}//;
+
+ # skip empty $filename, e.g. if you add a new package, the first
+ # line would be the package directory app-foo/bar/ but thats stripped above.
+ next if !$filename;
+ # skip directories
+ next if -d $filename;
+
+ ($actions{$filename} = $status) =~ tr/NDM/+-/d;
+ push(@files, $filename);
+ next;
+ }
+ # RENAMED/MOVED
+ elsif (/^R\s+(\S+) => (\S+)/) {
+ my ($old, $new) = ($1, $2);
+ $old =~ s/^([^\/]+\/){2}//;
+ $new =~ s/^([^\/]+\/){2}//;
+
+ next if !$old or !$new;
+ next if -d $old or -d $new;
+
+ $actions{$old} = '-';
+ $actions{$new} = '+';
+
+ push(@files, $old, $new);
+ next;
+ }
+ }
+ if (/^C\s+(\S+)/) {
+ # NOTE: The git part here might be unused
+ if($vcs eq "git") {
+ my $filename = $1;
+ $filename =~ /\S*\/(\S*)/;
+
+ next if -d $filename;
+
+ push @conflicts, $filename;
+ next;
+ }
+
+ push @conflicts, $1;
+ next;
+ }
+ elsif (/^\?\s+(\S+)/) {
+ push @unknown, $1;
+ $actions{$1} = '?';
+ next;
+ }
+ elsif (/^([ARMD])\s+\+?\s*(\S+)/) {
+ my ($status, $filename) = ($1,$2);
+
+ if($vcs eq "git") {
+ open(P, '-|', "git rev-parse --sq --show-prefix");
+ my $prefix = <P>;
+ close(P);
+
+ if (defined($prefix)) {
+ chomp($prefix);
+
+ if ($filename =~ /\Q$prefix\E(\S*)/) {
+ $filename = $1 ;
+ }
+ else {
+ next;
+ }
+ }
+ }
+
+ next if -d $filename;
+
+ push(@files, $filename);
+ ($actions{$filename} = $status) =~ tr/DARM/-+-/d;
+ }
+}
+
+sub git_unknown_objects {
+ open(GIT, "-|", "${vcs} ls-files --exclude-standard --others");
+ while(defined( my $line = <GIT> )) {
+ chomp($line);
+
+ # IMHO we can skip those files, even if they're untracked
+ #next if $line =~ m/^\.gitignore$/;
+
+ push(@unknown, $line);
+ }
+ close(GIT);
+}
+
+# git only shows files already added so we need to check for unknown files
+# separately here.
+if($vcs eq "git") {
+ git_unknown_objects();
+}
+
+# Separate out the trivial files for now
+@files = grep {
+ !/^(Manifest|ChangeLog)$/ or do { push @trivial, $_; 0; }
+} @files;
+
+@unknown = grep {
+ !/^(Manifest|ChangeLog)$/ or do { push @trivial, $_; 0; }
+} @unknown;
+
+# Don't allow any conflicts
+if (@conflicts) {
+ print STDERR <<EOT;
+$vcs reports the following conflicts. Please resolve them before
+running echangelog.
+EOT
+ print STDERR map "C $_\n", @conflicts;
+ exit 1;
+}
+
+# Don't allow unknown files (other than the trivial files that were separated
+# out above)
+if (@unknown) {
+ print STDERR <<EOT;
+$vcs reports the following unknown files. Please use "$vcs add" before
+running echangelog, or remove the files in question.
+EOT
+ print STDERR map "? $_\n", @unknown;
+ exit 1;
+}
+
+# Sort the list of files as portage does. None of the operations through
+# the rest of the script should break this sort.
+sub sortfunc($$) {
+ my ($a, $b) = @_;
+ (my $va = $a) =~ s/.*?-(\d.*?)(?:\.ebuild)?$/$1/;
+ (my $vb = $b) =~ s/.*?-(\d.*?)(?:\.ebuild)?$/$1/;
+ my ($na, $sa, $sna, $ra) = ($va =~ /^(.*?)(?:_(alpha|beta||pre|rc|p)(\d*))?(?:-r(\d+))?$/);
+ my ($nb, $sb, $snb, $rb) = ($vb =~ /^(.*?)(?:_(alpha|beta||pre|rc|p)(\d*))?(?:-r(\d+))?$/);
+ my (@na) = split /\.|(?<=\d)(?=[^\d\.])/, $na;
+ my (@nb) = split /\.|(?<=\d)(?=[^\d\.])/, $nb;
+ my $retval;
+
+ #
+ # compare version numbers first
+ #
+ for (my $i = 0; defined $na[$i] or defined $nb[$i]; $i++) {
+ # def vs. undef
+ return +1 if defined $na[$i] and !defined $nb[$i];
+ return -1 if defined $nb[$i] and !defined $na[$i];
+
+ # num vs. num
+ if ($na[$i] =~ /^\d/ and $nb[$i] =~ /^\d/) {
+ $retval = ($na[$i] <=> $nb[$i]);
+ return $retval if $retval;
+ next;
+ }
+
+ # char vs. char
+ if ($na[$i] =~ /^\D/ and $nb[$i] =~ /^\D/) {
+ $retval = ($na[$i] cmp $nb[$i]);
+ return $retval if $retval;
+ next;
+ }
+
+ # num vs. char
+ $retval = ($na[$i] =~ /\d/ and -1 or +1);
+ return $retval;
+ }
+
+ #
+ # compare suffix second
+ #
+ if (defined $sa and !defined $sb) {
+ return +2 if $sa eq "p";
+ return -2;
+ }
+ if (defined $sb and !defined $sa) {
+ return -3 if $sb eq "p";
+ return +3;
+ }
+
+ if (defined $sa) { # and defined $sb
+ $retval = ($sa cmp $sb);
+ if ($retval) {
+ return +4 if $sa eq "p";
+ return -4 if $sb eq "p";
+ return $retval; # suffixes happen to be alphabetical order, mostly
+ }
+
+ # compare suffix number
+ return +5 if defined $sna and !defined $snb;
+ return -5 if defined $snb and !defined $sna;
+
+ if (defined $sna) { # and defined $snb
+ $retval = ($sna <=> $snb);
+ return $retval if $retval;
+ }
+ }
+
+ #
+ # compare rev third
+ #
+ return +6 if defined $ra and !defined $rb;
+ return -6 if defined $rb and !defined $ra;
+
+ if (defined $ra) { # and defined $rb
+ return ($ra <=> $rb);
+ }
+
+ #
+ # nothing left to compare
+ #
+ return 0;
+}
+
+# Forget ebuilds that only have changed copyrights, unless that's all
+# the changed files we have
+@ebuilds = grep /\.ebuild$/, @files;
+@files = grep !/\.ebuild$/, @files;
+
+if (@ebuilds) {
+ if ($vcs eq "git") {
+ open C, $vcs{$vcs}{diff}." HEAD -- @ebuilds 2>&1 |" or die "Can't run: ".$vcs{$vcs}{diff}."$!\n";
+ } else {
+ open C, $vcs{$vcs}{diff}." @ebuilds 2>&1 |" or die "Can't run: ".$vcs{$vcs}{diff}."$!\n";
+ }
+
+ $_ = <C>;
+
+ while (defined $_) {
+ # only possible with cvs
+ if (/^$vcs diff: (([^\/]*?)\.ebuild) was removed/) {
+ mypush(@files, $1);
+ }
+ # We assume GNU diff output format here.
+ # git format: diff --git a/app-doc/repodoc/metadata.xml b/app-doc/repodoc/metadata.xml
+ elsif (/$vcs{$vcs}{regex}/) {
+ my ($file, $version) = ($1, $2);
+
+ if ($vcs eq "git") {
+ while (<C>) {
+ last if /^deleted file mode|^index/;
+ if (/^new file mode/) {
+ mypush(@files, $file);
+ mypush(@new_versions, $version);
+ last;
+ }
+ }
+ }
+
+ if ($vcs eq "bzr") {
+ if (/^=== added file/) {
+ mypush(@files, $file);
+ mypush(@new_versions, $version);
+ last;
+ }
+ elsif(/^=== renamed file '.+\/([^\/]+\.ebuild)' => '.+\/(([^\/]+)\.ebuild)'/) {
+ mypush(@files, $1, $2);
+ mypush(@new_versions, $3);
+ last;
+ }
+ }
+
+ # check if more than just copyright date changed.
+ # skip some lines (vcs dependent)
+ foreach(1..$vcs{$vcs}{skip}) {
+ $_ = <C>;
+ }
+
+ while (<C>) {
+ last if /^[A-Za-z]/;
+ if (/^[-+](?!# Copyright)/) {
+ mypush(@files, $file);
+ last;
+ }
+ }
+
+ # at this point we've either added $f to @files or not,
+ # and we have the next line in $_ for processing
+ next;
+ }
+ elsif (/^$vcs.*?: (([^\/]*?)\.ebuild) is a new entry/) {
+ mypush(@files, $1);
+ mypush(@new_versions, $2);
+ }
+
+ # other cvs output is ignored
+ $_ = <C>;
+ }
+}
+close C;
+
+# Subversion diff doesn't identify new versions. So use the status command
+if (($vcs eq "svn") and (@ebuilds)) {
+ open C, $vcs{$vcs}{status}." @ebuilds 2>&1 |" or die "Can't run: ".$vcs{$vcs}{status}."$!\n";
+ $_ = <C>;
+
+ while (defined $_) {
+ if (/^A\s+\+?\s*(([^\s]*)\.ebuild)/) {
+ mypush(@files, $1);
+ mypush(@new_versions, $2);
+ }
+
+ $_ = <C>;
+ }
+}
+
+# When a package move occurs, the versions appear to be new even though they are
+# not. Trim them from @new_versions in that case.
+@new_versions = grep { $text !~ /^\*\Q$_\E\s/m } @new_versions;
+
+# Check if we have any files left, otherwise re-insert ebuild list
+# (of course, both might be empty anyway)
+@files = @ebuilds unless (@files);
+
+# Allow ChangeLog entries with no changed files, but give a fat warning
+unless (@files) {
+ print STDERR "**\n";
+ print STDERR "** NOTE: No non-trivial changed files found. Normally echangelog\n";
+ print STDERR "** should be run after all affected files have been added and/or\n";
+ print STDERR "** modified. Did you forget to $vcs add?\n";
+ print STDERR "**\n";
+
+ if (!$opt_nostrict) {
+ print STDERR "** In strict mode, exiting\n";
+ print STDERR "** If you know what you're doing there pass '--no-strict' to echangelog\n";
+ exit(1);
+ }
+
+ @files = sort sortfunc @trivial;
+
+ # last resort to put something in the list
+ unless (@files) {
+ @files = qw/ChangeLog/;
+ $actions{'ChangeLog'} = "";
+ }
+}
+
+# sort
+@files = sort sortfunc @files;
+@new_versions = sort sortfunc @new_versions;
+
+# Get the input from the cmdline, editor or stdin
+if ($ARGV[0]) {
+ $input = "@ARGV";
+} else {
+ $editor = getenv('ECHANGELOG_EDITOR') ? getenv('ECHANGELOG_EDITOR') : getenv('EDITOR') || undef;
+
+ if ($editor) {
+ # Append some informations.
+ changelog_info(%actions);
+
+ system("$editor ChangeLog.new");
+
+ if ($? != 0) {
+ # This usually happens when the editor got forcefully killed; and
+ # the terminal is probably messed up: so we reset things.
+ system('stty sane');
+ print STDERR "Editor died! Reverting to stdin method.\n";
+ undef $editor;
+ } else {
+ if (open I, "<ChangeLog.new") {
+ local $/ = undef;
+ $input = <I>;
+ close(I);
+
+ # Remove comments from changelog_info().
+ local $/ = "\n";
+ $input =~ s/^#.*//mg;
+ local $/ = undef;
+ } else {
+ print STDERR "Error opening ChangeLog.new: $!\n";
+ print STDERR "Reverting to stdin method.\n";
+ undef $editor;
+ }
+ }
+ unlink('ChangeLog.new') if -f 'ChangeLog.new';
+ }
+
+ unless ($editor) {
+ print "Please type the log entry: use Ctrl-d to finish, Ctrl-c to abort...\n";
+ local $/ = undef;
+ $input = <>;
+ }
+}
+die "Empty entry; aborting\n" unless $input =~ /\S/;
+
+# If there are any long lines, then wrap the input at $columns chars
+# (leaving 2 chars on left, one char on right, after adding indentation below).
+$input = text_fill(' ', ' ', $input);
+
+# Prepend the user info to the input
+# Changes related to bug 213374;
+# This sequence should be right:
+# 1. GENTOO_COMMITTER_NAME && GENTOO_COMMITTER_EMAIL
+# 2. GENTOO_AUTHOR_NAME && GENTOO_AUTHOR_EMAIL
+# 3. ECHANGELOG_USER (fallback/obsolete?)
+# 4. getpwuid()..
+if ( getenv("GENTOO_COMMITTER_NAME") && getenv("GENTOO_COMMITTER_EMAIL") ) {
+ $user = sprintf("%s <%s>", getenv("GENTOO_COMMITTER_NAME"), getenv("GENTOO_COMMITTER_EMAIL"));
+}
+elsif ( getenv("GENTOO_AUTHOR_NAME") && getenv("GENTOO_AUTHOR_EMAIL") ) {
+ $user = sprintf("%s <%s>", getenv("GENTOO_AUTHOR_NAME"), getenv("GENTOO_AUTHOR_EMAIL"));
+}
+elsif ( getenv("ECHANGELOG_USER") ) {
+ $user = getenv("ECHANGELOG_USER");
+}
+else {
+ my ($fullname, $username) = (getpwuid($<))[6,0];
+ $fullname =~ s/,.*//; # remove GECOS, bug 80011
+ $user = sprintf('%s <%s@gentoo.org>', $fullname, $username);
+}
+
+# Make sure that we didn't get "root"
+die "Please set ECHANGELOG_USER or run as non-root\n" if $user =~ /<root@/;
+
+$date = strftime("%d %b %Y", gmtime);
+$entry = "$date; $user ";
+$entry .= join ', ', map "$actions{$_}$_", @files;
+$entry .= ':';
+$entry = Text::Wrap::fill(' ', ' ', $entry); # does not append a \n
+$entry .= "\n$input"; # append user input
+
+# Each one of these regular expressions will eat the whitespace
+# leading up to the next entry (except the two-space leader on the
+# front of a dated entry), so it needs to be replaced with a
+# double carriage-return. This helps to normalize the spacing in
+# the ChangeLogs.
+if (@new_versions) {
+ # Insert at the top with a new version marker
+ $text =~ s/^( .*? ) # grab header
+ \s*\n(?=\ \ \d|\*|\z) # suck up trailing whitespace
+ /"$1\n\n" .
+ join("\n", map "*$_ ($date)", reverse @new_versions) .
+ "\n\n$entry\n\n"/sxe
+ or die "Failed to insert new entry (4)\n";
+} else {
+ # Changing an existing patch or ebuild, no new version marker
+ # required
+ $text =~ s/^( .*? ) # grab header
+ \s*\n(?=\ \ \d|\*|\z) # suck up trailing whitespace
+ /$1\n\n$entry\n\n/sx
+ or die "Failed to insert new entry (3)\n";
+}
+
+# New packages and/or ones that have moved around often have stale data here.
+# But only do that in places where ebuilds are around (as echangelog can be
+# used in profiles/ and such places).
+if (grep(/\.ebuild$/, @files)) {
+ $text = update_cat_pn($text);
+}
+
+sub update_copyright {
+ my ($t) = @_;
+ (my $year = $date) =~ s/.* //;
+
+ $t =~ s/^# Copyright \d+(?= )/$&-$year/m or
+ $t =~ s/^(# Copyright) \d+-(\d+)/$1 1999-$year/m;
+
+ return $t;
+}
+
+# Update the copyright year in the ChangeLog
+$text = update_copyright($text);
+
+# Write the new ChangeLog
+open O, '>ChangeLog.new' or die "Can't open ChangeLog.new for output: $!\n";
+print O $text or die "Can't write ChangeLog.new: $!\n";
+close O or die "Can't close ChangeLog.new: $!\n";
+
+# Update affected ebuild copyright dates. There is no reason to update the
+# copyright lines on ebuilds that haven't changed. I verified this with an IP
+# lawyer.
+for my $e (grep /\.ebuild$/, @files) {
+ if (-s $e) {
+ my ($etext, $netext);
+
+ open E, "<$e" or warn("Can't read $e to update copyright year\n"), next;
+ { local $/ = undef; $etext = <E>; }
+ close E;
+
+ # Attempt the substitution and compare
+ $netext = update_copyright($etext);
+ next if $netext eq $etext; # skip this file if no change.
+
+ # Write the new ebuild
+ open E, ">$e.new" or warn("Can't open $e.new\n"), next;
+ print E $netext and
+ close E or warn("Can't write $e.new\n"), next;
+
+ # Move things around and show the diff
+ system "diff -U 0 $e $e.new";
+ rename "$e.new", $e or warn("Can't rename $e.new: $!\n");
+
+ # git requires to re-add this file else it wouln't be included in the commit.
+ if ($vcs eq "git")
+ {
+ system("$vcs{$vcs}{add} ${e}");
+ }
+ }
+}
+
+# Move things around and show the ChangeLog diff
+system 'diff -Nu ChangeLog ChangeLog.new';
+rename 'ChangeLog.new', 'ChangeLog' or die "Can't rename ChangeLog.new: $!\n";
+
+# Okay, now we have a starter ChangeLog to work with.
+# The text will be added just like with any other ChangeLog below.
+# Add the new ChangeLog to vcs before continuing.
+if ($vcs eq "cvs") {
+ if (open F, "CVS/Entries") {
+ system("cvs -f add ChangeLog") unless (scalar grep /^\/ChangeLog\//, <F>);
+ }
+} elsif ($vcs eq "svn") {
+ if (open F, ".svn/entries") {
+ system("svn add ChangeLog") unless (scalar grep /ChangeLog/, <F>);
+ }
+} else {
+ system("$vcs{$vcs}{add} ChangeLog 2>&1 >> /dev/null");
+}
+
+# vim: set ts=4 sw=4 tw=0:
diff --git a/gentoolkit-dev/src/echangelog/echangelog.1 b/gentoolkit-dev/src/echangelog/echangelog.1
new file mode 100644
index 0000000..1575644
--- /dev/null
+++ b/gentoolkit-dev/src/echangelog/echangelog.1
@@ -0,0 +1,270 @@
+.\" Automatically generated by Pod::Man 2.16 (Pod::Simple 3.07)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sh \" Subsection heading
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings. \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote. \*(C+ will
+.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+. ds -- \(*W-
+. ds PI pi
+. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
+. ds L" ""
+. ds R" ""
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds -- \|\(em\|
+. ds PI \(*p
+. ds L" ``
+. ds R" ''
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.ie \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. nr % 0
+. rr F
+.\}
+.el \{\
+. de IX
+..
+.\}
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear. Run. Save yourself. No user-serviceable parts.
+. \" fudge factors for nroff and troff
+.if n \{\
+. ds #H 0
+. ds #V .8m
+. ds #F .3m
+. ds #[ \f1
+. ds #] \fP
+.\}
+.if t \{\
+. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+. ds #V .6m
+. ds #F 0
+. ds #[ \&
+. ds #] \&
+.\}
+. \" simple accents for nroff and troff
+.if n \{\
+. ds ' \&
+. ds ` \&
+. ds ^ \&
+. ds , \&
+. ds ~ ~
+. ds /
+.\}
+.if t \{\
+. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+. \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+. \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+. \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+. ds : e
+. ds 8 ss
+. ds o a
+. ds d- d\h'-1'\(ga
+. ds D- D\h'-1'\(hy
+. ds th \o'bp'
+. ds Th \o'LP'
+. ds ae ae
+. ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "echangelog 1"
+.TH echangelog 1 "2009-04-28" "perl v5.10.0" "Gentoolkit"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH "NAME"
+echangelog \- Gentoo: update portage ChangeLogs
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+echangelog [ \fItext\fR ]
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+This tool provides an easy way to create or update portage ChangeLogs
+in Gentoo. The tool scans the current directory, which is assumed to
+be a package directory such as /usr/portage/app\-editors/vim, finds
+what files have been changed or added, and inserts the appropriate
+entry to ChangeLog. If \fItext\fR is not provided on the command-line,
+echangelog prompts for it.
+.PP
+All modifications should occur before running echangelog so that it
+can include the appropriate file information in the ChangeLog entry.
+For example, you should run \*(L"cvs add\*(R" on your files, otherwise
+echangelog won't know those files are part of the update.
+.PP
+If your text would cause the ChangeLog entry to exceed 80 columns, it
+will be rewrapped to keep the ChangeLog neat. If you need special
+formatting in the ChangeLog, then you can either (1) run echangelog
+with no text on the command-line, and make sure that your text won't
+be too wide, (2) edit the ChangeLog manually. If you prefer (2), I'd
+recommend something like \*(L"echangelog blah\*(R" so that the header lines
+are computed correctly, then edit and change \*(L"blah\*(R" to your preferred
+text.
+.PP
+In addition to updating the ChangeLog, echangelog will automatically
+update the copyright year of all out-of-date ebuilds, as well as the
+ChangeLog itself. These updates are included in the diff displayed by
+echangelog when it finishes its work.
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+Presently echangelog is simple enough that it supplies no options.
+Probably I'll add \fB\-\-help\fR and \fB\-\-version\fR in the future, but for
+now it's enough to track the gentoolkit version.
+.SH "EXAMPLES"
+.IX Header "EXAMPLES"
+To create a ChangeLog for a completely new package. The header is
+parsed from skel.ebuild.
+.PP
+.Vb 2
+\& $ cvs add metalog\-0.1.ebuild
+\& cvs server: use \*(Aqcvs commit\*(Aq to add this file permanently
+\&
+\& $ echangelog \*(AqNew ebuild, thanks to Harvey McGillicuddy\*(Aq
+\& \-\-\- ChangeLog 1969\-12\-31 19:00:00.000000000 \-0500
+\& +++ ChangeLog.new 2003\-02\-23 14:04:06.000000000 \-0500
+\& @@ \-0,0 +1,9 @@
+\& +# ChangeLog for app\-admin/metalog
+\& +# Copyright 2000\-2003 Gentoo Technologies, Inc.; Distributed under the GPL v2
+\& +# $Header$
+\& +
+\& +*metalog\-0.1 (23 Feb 2003)
+\& +
+\& + 23 Feb 2003; Aron Griffis <agriffis@gentoo.org> metalog\-0.1.ebuild :
+\& + New ebuild, thanks to Harvey McGillicuddy
+\& +
+.Ve
+.PP
+To bump a revision. Note you need to \*(L"cvs add\*(R" so that echangelog
+will notice the new file.
+.PP
+.Vb 2
+\& $ cvs add metalog\-0.1\-r1.ebuild
+\& cvs server: use \*(Aqcvs commit\*(Aq to add this file permanently
+\&
+\& $ echangelog \*(AqBump revision to fix bug #999\*(Aq
+\& \-\-\- ChangeLog 2003\-02\-23 14:04:06.000000000 \-0500
+\& +++ ChangeLog.new 2003\-02\-23 14:07:48.000000000 \-0500
+\& @@ \-2,6 +2,11 @@
+\& # Copyright 2000\-2003 Gentoo Technologies, Inc.; Distributed under the GPL v2
+\& # $Header$
+\&
+\& +*metalog\-0.1\-r1 (23 Feb 2003)
+\& +
+\& + 23 Feb 2003; Aron Griffis <agriffis@gentoo.org> metalog\-0.1\-r1.ebuild :
+\& + Bump revision to fix bug #999
+\& +
+\& *metalog\-0.1 (23 Feb 2003)
+\&
+\& 23 Feb 2003; Aron Griffis <agriffis@gentoo.org> metalog\-0.1.ebuild :
+.Ve
+.PP
+For a multi-line entry, omit the command-line arg.
+.PP
+.Vb 10
+\& $ echangelog
+\& Please type the log entry, finish with ctrl\-d
+\& Bump revision to fix bug #999. Necessary to bump the revision because
+\& the problem appears at run\-time, not compile\-time. This should also
+\& give users the updated default configuration file.
+\& \-\-\- ChangeLog 2003\-02\-23 14:09:12.000000000 \-0500
+\& +++ ChangeLog.new 2003\-02\-23 14:12:43.000000000 \-0500
+\& @@ \-2,6 +2,13 @@
+\& # Copyright 2000\-2003 Gentoo Technologies, Inc.; Distributed under the GPL v2
+\& # $Header$
+\&
+\& +*metalog\-0.1\-r1 (23 Feb 2003)
+\& +
+\& + 23 Feb 2003; Aron Griffis <agriffis@gentoo.org> metalog\-0.1\-r1.ebuild :
+\& + Bump revision to fix bug #999. Necessary to bump the revision because
+\& + the problem appears at run\-time, not compile\-time. This should also
+\& + give users the updated default configuration file.
+\& +
+\& *metalog\-0.1 (23 Feb 2003)
+\&
+\& 23 Feb 2003; Aron Griffis <agriffis@gentoo.org> metalog\-0.1.ebuild :
+.Ve
+.SH "ENVIRONMENT VARIABLES"
+.IX Header "ENVIRONMENT VARIABLES"
+.IP "\s-1ECHANGELOG_USER\s0" 4
+.IX Item "ECHANGELOG_USER"
+If echangelog can't figure out your username for the entry, you should
+set \s-1ECHANGELOG_USER\s0. For example, export ECHANGELOG_USER=\*(L"Aron
+Griffis <agriffis@gentoo.org>\*(R"
+.SH "NOTES"
+.IX Header "NOTES"
+As of the most recent version of echangelog (when this man-page
+appeared), echangelog puts all new entries at the top of the file
+instead of finding the appropriate *version line within the file.
+This is because that \*(L"new\*(R" ChangeLog format was never agreed upon by
+the Gentoo developers. Unfortunately the existence of both formats
+will undoubtedly cause much confusion.
+.PP
+This also means that the examples above are wrong, since I just copied
+them from some old email. However they're not much wrong. ;\-)
+.PP
+This tool was written by Aron Griffis <agriffis@gentoo.org>. Bugs
+found should be filed against me at http://bugs.gentoo.org/
diff --git a/gentoolkit-dev/src/echangelog/test/TEST.pm b/gentoolkit-dev/src/echangelog/test/TEST.pm
new file mode 100644
index 0000000..6632148
--- /dev/null
+++ b/gentoolkit-dev/src/echangelog/test/TEST.pm
@@ -0,0 +1,26 @@
+# We just return a static/predefined date because we're working with
+# static md5 checksums.
+
+package TEST;
+
+use strict;
+use warnings;
+
+BEGIN {
+ use Exporter();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+
+ $VERSION = 1.00;
+
+ @ISA = qw(Exporter);
+ @EXPORT = qw(&strftime);
+ %EXPORT_TAGS = ( );
+ @EXPORT_OK = qw();
+}
+our @EXPORT_OK;
+
+sub strftime {
+ return "01 Jan 2009";
+}
+
+1;
diff --git a/gentoolkit-dev/src/echangelog/test/templates/test.patch b/gentoolkit-dev/src/echangelog/test/templates/test.patch
new file mode 100644
index 0000000..72d46fa
--- /dev/null
+++ b/gentoolkit-dev/src/echangelog/test/templates/test.patch
@@ -0,0 +1,6 @@
+--- test.patch 2009-04-28 14:13:26.171225175 +0200
++++ test.patch 2009-04-28 14:12:26.246497830 +0200
+@@ -0,0 +1,3 @@
++This is just an example.
++Its used for several echangelog tests.
++
diff --git a/gentoolkit-dev/src/echangelog/test/templates/vcstest-0.0.1.ebuild b/gentoolkit-dev/src/echangelog/test/templates/vcstest-0.0.1.ebuild
new file mode 100644
index 0000000..2824b83
--- /dev/null
+++ b/gentoolkit-dev/src/echangelog/test/templates/vcstest-0.0.1.ebuild
@@ -0,0 +1,16 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+DESCRIPTION="echangelog test ebuild"
+HOMEPAGE=""
+SRC_URI=""
+
+LICENSE=""
+SLOT="0"
+KEYWORDS=""
+IUSE=""
+
+DEPEND=""
+RDEPEND=""
+
diff --git a/gentoolkit-dev/src/echangelog/test/test.sh b/gentoolkit-dev/src/echangelog/test/test.sh
new file mode 100755
index 0000000..14703d4
--- /dev/null
+++ b/gentoolkit-dev/src/echangelog/test/test.sh
@@ -0,0 +1,176 @@
+#!/bin/bash
+
+source /etc/init.d/functions.sh
+
+SUPPORTED_VCS=( "cvs" "svn" "git" )
+VCSTEST="echangelog-test/vcstest"
+_ROOT=$(pwd)
+
+export ECHANGELOG_USER="Just a test <echangelogtest@gentoo.org>"
+
+MD5_INIT="34d54bc2ab1a2154b0c7bd5cdd7f6119"
+MD5_PATCH="db1ab89bb7374824d0f198078f79a83f"
+MD5_REVBUMP="31ddfa60d2ae4dd1fccd7e3d2bd2c06c"
+MD5_COPYRIGHT="6f39fa409ea14bb6506347c53f6dee50"
+MD5_OBSOLETE="0aedadf159c6f3add97a3f79fb867221"
+MD5_FINAL="17eb0df69f501cc6fdaffebd118b7764"
+
+function md5() {
+ local fname=$1
+ echo $(md5sum ${fname} | awk '{ print $1 }')
+}
+
+function ech() {
+ local bin=$1
+ local msg=$2
+
+ perl -I$(dirname $(dirname ${bin})) ${bin} "${msg}"
+}
+
+function make_test() {
+ local root=$1
+ local vcs=$2
+
+ local echangelog="${root}/tmp/echangelog"
+ local tmp="${root}/tmp/${vcs}"
+ local template="${root}/templates"
+
+ cd $root
+ mkdir -p ${tmp}
+ cd ${tmp}
+
+ [[ "${vcs}" == "cvs" ]] && mkdir -p ${tmp}/cvsroot
+ [[ "${vcs}" == "svn" ]] && mkdir -p ${tmp}/svnroot
+
+ if [[ "${vcs}" == "git" ]];
+ then
+ git init
+ touch .gitignore
+ git add .gitignore
+ git commit -a -m 'Initial Commit'
+ elif [[ "${vcs}" == "svn" ]];
+ then
+ svnadmin create svnroot
+ svn co file://${tmp}/svnroot svn
+ cd svn
+ elif [[ "${vcs}" == "cvs" ]];
+ then
+ CVSROOT="${tmp}/cvsroot" cvs init
+ mkdir cvsroot/cvs
+ cvs -d:local:${tmp}/cvsroot co cvs
+ cd cvs
+ fi
+
+ mkdir -p ${VCSTEST}
+
+ cp ${template}/vcstest-0.0.1.ebuild ${VCSTEST}
+ ${vcs} add $(dirname ${VCSTEST})
+ if [[ "${vcs}" == "cvs" ]];
+ then
+ ${vcs} add ${VCSTEST}
+ ${vcs} add "${VCSTEST}/vcstest-0.0.1.ebuild"
+ fi
+
+ cd ${VCSTEST}
+ ech ${echangelog} 'New ebuild for bug <id>.'
+
+ if [[ "${MD5_INIT}" != "$(md5 ChangeLog)" ]];
+ then
+ eerror "WRONG MD5_INIT!"
+ fi
+
+ mkdir files
+ cp ${template}/test.patch files
+ if [[ "${vcs}" == "cvs" ]];
+ then
+ ${vcs} add files/
+ ${vcs} add files/test.patch
+ else
+ ${vcs} add files
+ fi
+
+ ech ${echangelog} "Added adittional patch to fix foo."
+
+ if [[ "${MD5_PATCH}" != "$(md5 ChangeLog)" ]];
+ then
+ eerror "WRONG MD5_PATCH!"
+ fi
+
+ if [[ "${vcs}" == "svn" ]];
+ then
+ ${vcs} commit -m 'New ebuild for bug <id>.' ../
+ else
+ ${vcs} commit -m 'New ebuild for bug <id>.'
+ fi
+
+ [[ "${vcs}" == "cvs" ]] && sed -i -e 's:# $Header\: .*$:# $Header\: $:' ChangeLog
+
+ cp vcstest-0.0.1.ebuild vcstest-0.0.1-r1.ebuild
+ ${vcs} add vcstest-0.0.1-r1.ebuild
+
+ ech ${echangelog} "Revbump..."
+
+ if [[ "${MD5_REVBUMP}" != "$(md5 ChangeLog)" ]];
+ then
+ eerror "WRONG MD5_REVBUMP!"
+ fi
+
+ sed -i -e 's:# Copyright 1999-2009 Gentoo Foundation:# Copyright 1999-2010 Gentoo Foundation:' vcstest-0.0.1.ebuild
+ ech ${echangelog} "Revbump...; Just copyright changed."
+
+ if [[ "${MD5_COPYRIGHT}" != "$(md5 ChangeLog)" ]];
+ then
+ eerror "WRONG MD5_COPYRIGHT!"
+ fi
+
+ if [[ "${vcs}" == "cvs" ]];
+ then
+ rm -f files/test.patch
+ ${vcs} remove files/test.patch
+ else
+ ${vcs} rm files/test.patch
+ fi
+
+ ech ${echangelog} "Revbump...; Just copyright changed; Removed obsolete patch."
+
+ if [[ "${MD5_OBSOLETE}" != "$(md5 ChangeLog)" ]];
+ then
+ eerror "WRONG MD5_OBSOLETE!"
+ fi
+
+ echo>>vcstest-0.0.1.ebuild
+ ech ${echangelog} "Revbump...; Just copyright changed; Removed obsolete patch; Modified more then just the copyright."
+
+ if [[ "${MD5_FINAL}" != "$(md5 ChangeLog)" ]];
+ then
+ eerror "WRONG MD5_FINAL!"
+ fi
+}
+
+[[ -d "${_ROOT}/tmp" ]] && rm -rf ${_ROOT}/tmp
+mkdir -p ${_ROOT}/tmp
+
+ebegin "Preparing echangelog"
+
+if [[ -e ../echangelog ]];
+then
+ cp ../echangelog "${_ROOT}/tmp" || set $?
+ sed -i -e 's:use POSIX qw.*:use POSIX qw(setlocale getcwd);\nuse TEST qw(strftime);:' "${_ROOT}/tmp/echangelog" || set $?
+ eend ${1:-0} || exit ${1}
+else
+ eerror "error"
+ eend ${1:-1}
+ exit 1
+fi
+
+for vcs in ${SUPPORTED_VCS[*]};
+do
+ if [[ -x "$(which ${vcs} 2>/dev/null)" ]];
+ then
+ ebegin "Starting test with ${vcs}"
+ make_test $_ROOT "${vcs}" || set $?
+ eend ${1:-0}
+ else
+ ewarn "No ${vcs} executable found, skipping test..."
+ fi
+done
diff --git a/gentoolkit-dev/src/ego/AUTHOR b/gentoolkit-dev/src/ego/AUTHOR
new file mode 100644
index 0000000..36d5bfd
--- /dev/null
+++ b/gentoolkit-dev/src/ego/AUTHOR
@@ -0,0 +1 @@
+Aron Griffis <agriffis@gentoo.org>
diff --git a/gentoolkit-dev/src/ego/AUTHORS b/gentoolkit-dev/src/ego/AUTHORS
new file mode 100644
index 0000000..36d5bfd
--- /dev/null
+++ b/gentoolkit-dev/src/ego/AUTHORS
@@ -0,0 +1 @@
+Aron Griffis <agriffis@gentoo.org>
diff --git a/gentoolkit-dev/src/ego/ChangeLog b/gentoolkit-dev/src/ego/ChangeLog
new file mode 100644
index 0000000..503d0da
--- /dev/null
+++ b/gentoolkit-dev/src/ego/ChangeLog
@@ -0,0 +1,2 @@
+2004-15-01 Karl Trygve Kalleberg <karltk@gentoo.org>
+ * Added Makefile
diff --git a/gentoolkit-dev/src/ego/Makefile b/gentoolkit-dev/src/ego/Makefile
new file mode 100644
index 0000000..b27a2cb
--- /dev/null
+++ b/gentoolkit-dev/src/ego/Makefile
@@ -0,0 +1,18 @@
+# Copyright 2004 Karl Trygve Kalleberg <karltk@gentoo.org>
+# Copyright 2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+#
+# $Header$
+
+include ../../makedefs.mak
+
+all:
+
+dist:
+ mkdir -p ../../$(distdir)/src/ego/
+ cp Makefile AUTHORS README TODO ChangeLog ego ../../$(distdir)/src/ego/
+
+install: all
+ install -d $(docdir)/ego
+ install -m 0644 AUTHORS README ego $(docdir)/ego/
+
diff --git a/gentoolkit-dev/src/ego/README b/gentoolkit-dev/src/ego/README
new file mode 100644
index 0000000..6c44b4c
--- /dev/null
+++ b/gentoolkit-dev/src/ego/README
@@ -0,0 +1,2 @@
+[ -f ${HOME}/scripts/ego.bash ] &&
+alias ego="unalias ego ; source ${HOME}/scripts/ego.bash ; ego "
diff --git a/gentoolkit-dev/src/ego/TODO b/gentoolkit-dev/src/ego/TODO
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gentoolkit-dev/src/ego/TODO
diff --git a/gentoolkit-dev/src/ego/ego b/gentoolkit-dev/src/ego/ego
new file mode 100644
index 0000000..f1691f2
--- /dev/null
+++ b/gentoolkit-dev/src/ego/ego
@@ -0,0 +1,86 @@
+echo1() {
+ echo "$1"
+}
+
+ego() {
+ local portdir tmpdir category pkg target
+
+ # This is WAY faster than portageq:
+ # portdir=$(portageq portdir)
+ # tmpdir=$(portageq envvar PORTAGE_TMPDIR)/portage
+ eval $(
+ . /etc/make.globals
+ . /etc/make.conf
+ export PORTDIR PORTAGE_TMPDIR
+ export | sed -n '
+ s/^declare -x PORTDIR=/portdir=/p
+ s/^declare -x PORTAGE_TMPDIR=\(.*\)/tmpdir=\1\/portage/p'
+ )
+
+ case $1 in
+ *-*/*)
+ pkg=${1##*/}
+ category=${1%/*}
+ ;;
+
+ ?*)
+ pkg=$1
+ # require an ebuild so that we can block deprecated packages
+ # such as dev-libs/rep-gtk
+ category=$(echo1 $portdir/*-*/$pkg/*.ebuild)
+ [[ -f $category ]] || category=$(echo1 $portdir/*-*/$pkg*/*.ebuild)
+ [[ -f $category ]] || category=$(echo1 $portdir/*-*/*$pkg/*.ebuild)
+ [[ -f $category ]] || category=$(echo1 $portdir/*-*/*$pkg*/*.ebuild)
+ if [[ ! -f $category ]]; then
+ echo "Can't find $pkg in $portdir" >&2
+ return 1
+ fi
+ pkg=${category%/*}
+ pkg=${pkg##*/}
+ category=${category#$portdir/}
+ category=${category%%/*}
+ ;;
+
+ *)
+ # Check if we're under $portdir first
+ pkg=${PWD##*/}
+ category=${PWD%/*}
+ category=${category##*/}
+ if [[ ! -d $portdir/$category/$pkg ]]; then
+ # Next check if we're in PORTAGE_TMPDIR
+ if [[ $PWD = $tmpdir/* ]]; then
+ pkg=${PWD#$tmpdir/}
+ pkg=${pkg%%/*}
+ pkg=${pkg%%-[0-9]*} # not really a valid assumption
+ category=$(echo1 $portdir/*-*/$pkg/*.ebuild)
+ if [[ ! -f $category ]]; then
+ echo "Can't find $pkg in $portdir" >&2
+ return 1
+ fi
+ category=${category#$portdir/}
+ category=${category%%/*}
+ else
+ echo "syntax: ego [pkgname]" >&2
+ echo "or simply ego from a dir under $portdir or $tmpdir" >&2
+ return 1
+ fi
+ fi
+ ;;
+ esac
+
+ # go to tmpdir or portdir?
+ if [[ $PWD/ = */$category/$pkg/* ]]; then
+ [[ -n $tmpdir ]] || tmpdir=$(portageq envvar PORTAGE_TMPDIR)/portage
+ target=$(command ls -1td $tmpdir/$pkg-* 2>/dev/null | head -n 1)
+ if [[ -z $target ]]; then
+ echo "No matches found for $tmpdir/$pkg-*" >&2
+ return 1
+ fi
+ cd $target/work/$pkg* 2>/dev/null ||
+ cd $target/work 2>/dev/null ||
+ cd $target
+ else
+ cd $portdir/$category/$pkg
+ fi
+}
+
diff --git a/gentoolkit-dev/src/ekeyword/AUTHORS b/gentoolkit-dev/src/ekeyword/AUTHORS
new file mode 100644
index 0000000..36d5bfd
--- /dev/null
+++ b/gentoolkit-dev/src/ekeyword/AUTHORS
@@ -0,0 +1 @@
+Aron Griffis <agriffis@gentoo.org>
diff --git a/gentoolkit-dev/src/ekeyword/ChangeLog b/gentoolkit-dev/src/ekeyword/ChangeLog
new file mode 100644
index 0000000..68d99e5
--- /dev/null
+++ b/gentoolkit-dev/src/ekeyword/ChangeLog
@@ -0,0 +1,46 @@
+24 Apr 2009 Paul Varner <fuzzyray@gentoo.org>
+ * Handle multiline KEYWORDS
+
+07 Jan 2009 Mike Frysinger <vapier@gentoo.org>
+ * Support intended KEYWORDS
+ * Convert every instance of KEYWORDS in the file
+ * Error out on invalid arguments #156827
+ * Tighten up diff output to show KEYWORDS changes
+
+27 Oct 2005 Aron Griffis <agriffis@gentoo.org>
+ * Fix handling of comments
+ * Add support for bare ~ as a synonym for ~all
+
+23 Mar 2005 Aron Griffis <agriffis@gentoo.org>
+ * Only modify non-masked keywords with "all"
+
+17 Mar 2005 Aron Griffis <agriffis@gentoo.org>
+ * Sort keywords alphabetically
+
+09 Nov 2004 Aron Griffis <agriffis@gentoo.org>
+ * Fix mismatching of ppc vs. ppc-macos #69683
+
+15 Sep 2004 Aron Griffis <agriffis@gentoo.org>
+ * Update for GLEP 22 keywords
+ * Change copyright line for Gentoo Foundation
+
+12 Apr 2004 Aron Griffis <agriffis@gentoo.org>
+ * Add ability to remove keywords with ^, for example:
+ ekeyword ^alpha blah.ebuild
+ * Add support for -*, for example: ekeyword -* would add it;
+ ekeyword ^* would remove it.
+ * Add a man-page for ekeyword
+
+09 Apr 2004 Aron Griffis <agriffis@gentoo.org>
+ * Add ability to modify all keywords via all, ~all, or -all, for
+ example: ekeyword -all ~alpha ia64 blah.ebuild
+
+31 Mar 2004 Aron Griffis <agriffis@gentoo.org>
+ * Fix bug 28426 with patch from Mr_Bones_ to keep ekeyword from confusing
+ ppc and ppc64
+
+2004-01-12 Aron Griffis <agriffis@gentoo.org>
+ * Allow multiple keywords
+
+2004-01-07 Karl Trygve Kalleberg <karltk@gentoo.org>
+ * Added Makefile
diff --git a/gentoolkit-dev/src/ekeyword/Makefile b/gentoolkit-dev/src/ekeyword/Makefile
new file mode 100644
index 0000000..a1a5802
--- /dev/null
+++ b/gentoolkit-dev/src/ekeyword/Makefile
@@ -0,0 +1,26 @@
+# Copyright 2004 Karl Trygve Kalleberg <karltk@gentoo.org>
+# Copyright 2004 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+#
+# $Header$
+
+include ../../makedefs.mak
+
+%.1 : %.pod
+ pod2man $< > $@
+
+.PHONY: all
+all: ekeyword.1
+
+dist: ekeyword.1
+ mkdir -p ../../$(distdir)/src/ekeyword
+ cp Makefile AUTHORS README TODO ChangeLog ekeyword ekeyword.1 ../../$(distdir)/src/ekeyword/
+
+install: all
+ install -m 0755 ekeyword $(bindir)/
+ install -d $(docdir)/ekeyword
+ install -m 0644 AUTHORS README TODO ChangeLog $(docdir)/ekeyword/
+ install -m 0644 ekeyword.1 $(mandir)/
+
+clean:
+ $(RM) ekeyword.1
diff --git a/gentoolkit-dev/src/ekeyword/README b/gentoolkit-dev/src/ekeyword/README
new file mode 100644
index 0000000..ec7ff5e
--- /dev/null
+++ b/gentoolkit-dev/src/ekeyword/README
@@ -0,0 +1,20 @@
+Package : ekeyword
+Version : 0.1.0
+Author : See AUTHORS
+
+MOTIVATION
+
+Update the KEYWORDS in an ebuild.
+
+MECHANICS
+
+N/A
+
+IMPROVEMENTS
+
+- Should rewrite to Python, and use Portage directly to select candidate
+ ebuilds.
+- Should add entry to ChangeLog.
+
+For improvements, send a mail to agriffis@gentoo.org or make out a bug at
+bugs.gentoo.org.
diff --git a/gentoolkit-dev/src/ekeyword/TODO b/gentoolkit-dev/src/ekeyword/TODO
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gentoolkit-dev/src/ekeyword/TODO
diff --git a/gentoolkit-dev/src/ekeyword/ekeyword b/gentoolkit-dev/src/ekeyword/ekeyword
new file mode 100755
index 0000000..e38801d
--- /dev/null
+++ b/gentoolkit-dev/src/ekeyword/ekeyword
@@ -0,0 +1,147 @@
+#!/usr/bin/perl -w
+#
+# Copyright 2003-2009, Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# Written by Aron Griffis <agriffis@gentoo.org>
+#
+# ekeyword: Update the KEYWORDS in an ebuild. For example:
+#
+# $ ekeyword ~alpha oaf-0.6.8-r1.ebuild
+# - ppc sparc x86
+# + ~alpha ppc sparc x86
+
+my ($kw_re) = '^(?:([-~^]?)(\w[\w-]*)|([-^]\*))$';
+my (@kw);
+
+# make sure the cmdline consists of keywords and ebuilds
+unless (@ARGV > 0) {
+ # NOTE: ~all will ignore all -arch keywords
+ print STDERR "syntax: ekeyword { arch | ~[arch] | -[arch] } ebuild...\n";
+ print STDERR "instead of 'arch' you can also use 'all' which covers all existing keywords...\n";
+ exit(1);
+}
+for my $a (@ARGV) {
+ $a = '~all' if $a eq '~' or $a eq $ENV{'HOME'}; # for vapier
+ next if $a =~ /$kw_re/o; # keyword
+ next if $a =~ /^\S+\.ebuild$/; # ebuild
+ die "I don't understand $a\n";
+}
+
+my $files = 0;
+for my $f (@ARGV) {
+ if ($f =~ /$kw_re/o) {
+ push @kw, $f;
+ next;
+ }
+
+ print "$f\n";
+
+ open I, "<$f" or die "Can't read $f: $!\n";
+ open O, ">$f.new" or die "Can't create $f.new: $!\n";
+ select O;
+
+ my $keys_before;
+ my $keys_after;
+ while (<I>) {
+ if (/^\s*KEYWORDS=/) {
+
+ # extract the quoted section from KEYWORDS
+ while (not /^\s*KEYWORDS=["'].*?["']/) {
+ chomp;
+ my $next = <I>;
+ $_ = join " ", $_, $next;
+ }
+ (my $quoted = $_) =~ s/^.*?["'](.*?)["'].*/$1/s;
+ $keys_before = $quoted;
+
+ # replace -* with -STAR for our convenience below
+ $quoted =~ s/-\*/-STAR/;
+
+ for my $k (@kw) {
+ my ($leader, $arch, $star) = ($k =~ /$kw_re/o);
+
+ # handle -* and ^*
+ if (defined $star) {
+ $leader = substr $star,0,1;
+ $arch = 'STAR';
+ }
+
+ # remove keywords
+ if ($leader eq '^') {
+ if ($arch eq 'all') {
+ $quoted = '';
+ } else {
+ $quoted =~ s/[-~]?\Q$arch\E\b//;
+ }
+
+ # add or modify keywords
+ } else {
+ if ($arch eq 'all') {
+ # modify all non-masked keywords in the list
+ $quoted =~ s/(^|\s)~?(?=\w)/$1$leader/g;
+ } else {
+ # modify or add keyword
+ unless ($quoted =~ s/[-~]?\Q$arch\E(\s|$)/$leader$arch$1/) {
+ # modification failed, need to add
+ if ($arch eq 'STAR') {
+ $quoted = "$leader$arch $quoted";
+ } else {
+ $quoted .= " $leader$arch";
+ }
+ }
+ }
+ }
+ }
+
+ # replace -STAR with -*
+ $quoted =~ s/-STAR\b/-*/;
+
+ # sort keywords and fix spacing
+ $quoted = join " ", sort {
+ (my $sa = $a) =~ s/^\W//;
+ (my $sb = $b) =~ s/^\W//;
+ return -1 if $sa eq '*';
+ return +1 if $sb eq '*';
+ $sa .= "-";
+ $sb .= "-";
+ $sa =~ s/([a-z0-9]+)-([a-z0-9]*)/$2-$1/g;
+ $sb =~ s/([a-z0-9]+)-([a-z0-9]*)/$2-$1/g;
+ $sa cmp $sb;
+ } split " ", $quoted;
+
+ $keys_after = $quoted;
+
+ # re-insert quoted to KEYWORDS
+ s/(["']).*?["']/$1$quoted$1/;
+
+ print $_ or die "Can't write $f.new: $!\n";
+ } else {
+ print, next;
+ }
+ }
+
+ close I;
+ close O;
+ select STDOUT;
+
+ if ($keys_before ne $keys_after) {
+ # This gives uniform output, but actually seems to make
+ # it harder to pick out differences, and doesn't work so
+ # well when adding/removing keywords
+ #$keys_before =~ s/(^| )/ /g;
+ #$keys_before =~ s/ ([-~])/$1/g;
+ #$keys_after =~ s/(^| )/ /g;
+ #$keys_after =~ s/ ([-~])/$1/g;
+ print " - $keys_before\n + $keys_after\n";
+ #system "diff -U 0 $f $f.new | sed -n -r 's:^(.)[[:space:]]*KEYWORDS=\"(.*)\": \\1 \\2:p'";
+ #system "diff -U 0 $f $f.new | sed -n '/KEYWORDS=/s:^: :p'";
+ }
+ rename "$f.new", "$f" or die "Can't rename: $!\n";
+ $files++;
+}
+
+if ($files == 0) {
+ die "No ebuilds processed!";
+}
+
+# vim:ts=4 sw=4
diff --git a/gentoolkit-dev/src/ekeyword/ekeyword.pod b/gentoolkit-dev/src/ekeyword/ekeyword.pod
new file mode 100644
index 0000000..ff837b9
--- /dev/null
+++ b/gentoolkit-dev/src/ekeyword/ekeyword.pod
@@ -0,0 +1,68 @@
+=head1 NAME
+
+ekeyword - Gentoo: modify package KEYWORDS
+
+=head1 SYNOPSIS
+
+ekeyword { arch|~arch|-arch|^arch } ebuild...
+
+=head1 DESCRIPTION
+
+This tool provides a simple way to add or update KEYWORDS in a set of
+ebuilds. Each command-line argument is processed in order, so that
+keywords are added to the current list as they appear, and ebuilds are
+processed as they appear.
+
+Instead of specifying a specific arch, it's possible to use the word
+"all". This causes the change to apply to all keywords presently
+specified in the ebuild.
+
+The ^ leader instructs ekeyword to remove the specified arch.
+
+=head1 OPTIONS
+
+Presently ekeyword is simple enough that it supplies no options.
+Probably I'll add B<--help> and B<--version> in the future, but for
+now it's enough to track the gentoolkit version.
+
+=head1 EXAMPLES
+
+To mark a single arch stable:
+
+ $ ekeyword alpha metalog-0.7-r1.ebuild
+ metalog-0.7-r1.ebuild
+ -KEYWORDS="~alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86"
+ +KEYWORDS="alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86"
+
+When bumping a package, to mark all arches for testing:
+
+ $ ekeyword ~all metalog-0.7-r2.ebuild
+ metalog-0.7-r2.ebuild
+ -KEYWORDS="alpha amd64 hppa ia64 mips ppc sparc x86"
+ +KEYWORDS="~alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86"
+
+To signify that a package is broken for all arches except one:
+
+ $ ekeyword ^all -* ~x86 metalog-0.7-r3.ebuild
+ metalog-0.7-r3.ebuild
+ -KEYWORDS="~alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86"
+ +KEYWORDS="-* ~x86"
+
+To do lots of things at once:
+
+ $ ekeyword alpha metalog-0.7-r1.ebuild \
+ ~all metalog-0.7-r2.ebuild ^all -* ~x86 metalog-0.7-r3.ebuild
+ metalog-0.7-r1.ebuild
+ -KEYWORDS="~alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86"
+ +KEYWORDS="alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86"
+ metalog-0.7-r2.ebuild
+ -KEYWORDS="alpha amd64 hppa ia64 mips ppc sparc x86"
+ +KEYWORDS="~alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86"
+ metalog-0.7-r3.ebuild
+ -KEYWORDS="~alpha ~amd64 ~hppa ~ia64 ~mips ~ppc ~sparc ~x86"
+ +KEYWORDS="-* ~x86"
+
+=head1 NOTES
+
+This tool was written by Aron Griffis <agriffis@gentoo.org>. Bugs
+found should be filed against me at http://bugs.gentoo.org/
diff --git a/gentoolkit-dev/src/ekeyword2/ekeyword2 b/gentoolkit-dev/src/ekeyword2/ekeyword2
new file mode 100755
index 0000000..ce8842d
--- /dev/null
+++ b/gentoolkit-dev/src/ekeyword2/ekeyword2
@@ -0,0 +1,96 @@
+#!/usr/bin/python
+
+# Output like:
+# setuptools-0.6_rc9.ebuild
+# < KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sh ~sparc ~sparc-fbsd -x86 ~x86-fbsd"
+# ---
+# > KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sh ~sparc ~sparc-fbsd x86 ~x86-fbsd"
+
+from __future__ import with_statement
+from sys import argv
+from fnmatch import fnmatch
+from shutil import copyfile
+from os import environ as env
+
+import re
+import string
+
+from portage import settings
+
+STABLE_KEYWORDS = frozenset(settings["PORTAGE_ARCHLIST"].split())
+BROKEN_KEYWORDS = frozenset(['-*'] + ['-'+k for k in STABLE_KEYWORDS])
+TEST_KEYWORDS = frozenset(['~'+k for k in STABLE_KEYWORDS])
+KNOWN_KEYWORDS = STABLE_KEYWORDS | TEST_KEYWORDS | BROKEN_KEYWORDS
+
+argv = set(argv[1:])
+kw_re = re.compile(r'KEYWORDS="([^"]*)"')
+ebuilds = frozenset([x for x in argv if fnmatch(x, '*.ebuild')])
+pretend = bool(argv.intersection(('-p', '--pretend',)))
+keywords = argv.difference(('-p', '--pretend',)) - ebuilds
+
+if not ebuilds:
+ print 'usage: ekeyword [-p|--pretend] [^|~|-][all] [[^|~|-]arch [[^|~|-]arch]...] ebuild [ebuild...]'
+
+for e in ebuilds:
+ # TODO: error handling for file I/O
+ kw = set(keywords)
+ if not pretend:
+ try:
+ copyfile(e, e+'.orig')
+ except IOError:
+ print "Can't copy file %s. Check permissions." % e
+ exit(1)
+ try:
+ with open(e) as c:
+ ebuild = c.read()
+ except IOError:
+ print "Can't open file %s. Aborting." % e
+ exit(1)
+
+ orig = kw_re.search(ebuild)
+ curkw = set(orig.groups()[0].split())
+
+ # ^ or ^all by itself means remove all keywords
+ # (however, other keywords established in the same args still get set.)
+ if kw.intersection(('^', '^all',)):
+ kw -= set(('^', '^all',))
+ curkw = set()
+
+ # ~ or ~all by itself means set ~keyword for all keywords
+ # since ~ expands to "$HOME" in the shell, assume the user meant ~ if we see
+ # the expansion of "$HOME". (Hope there's no user named 'all'.)
+ if kw.intersection(('~', '~all', env['HOME'],)):
+ kw -= set(('~', '~all', env['HOME'],))
+ curkw = set(['~'+k if k in STABLE_KEYWORDS else k for k in curkw])
+
+ for k in kw:
+ # Remove keywords starting with ^
+ if k[0] == '^':
+ curkw -= set((k[1:], '-'+k[1:], '~'+k[1:], ))
+ # Set ~ and - keywords to TEST and BROKEN, respectively
+ elif k[0] == '~' or k[0] == '-':
+ curkw -= set((k[1:], '-'+k[1:], '~'+k[1:], ))
+ curkw |= set((k,))
+ # Set remaining keywords to STABLE
+ else:
+ curkw -= set(('~'+k,))
+ curkw |= set((k,))
+
+ # Sort by arch, then OS (Luckily, this makes -* show up first if it's there)
+ result = 'KEYWORDS="%s"' % ' '.join(sorted(curkw,
+ key=lambda x: x.strip(string.punctuation).lower()))
+
+ if not pretend:
+ try:
+ with open(e, 'w') as rebuild:
+ rebuild.write(kw_re.sub(result, ebuild))
+ except IOError:
+ print "Can't write file %s. Aborting." % e
+ exit(1)
+
+ unknown_keywords = curkw - KNOWN_KEYWORDS
+ if unknown_keywords:
+ print "\nWarning: Unknown keywords '%s'.\n" % ', '.join(sorted(unknown_keywords))
+
+ print '<<< %s' % orig.group()
+ print '>>> %s' % result
diff --git a/gentoolkit-dev/src/eshowkw/Makefile b/gentoolkit-dev/src/eshowkw/Makefile
new file mode 100644
index 0000000..77bf1d8
--- /dev/null
+++ b/gentoolkit-dev/src/eshowkw/Makefile
@@ -0,0 +1,18 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+include ../../makedefs.mak
+
+.PHONY: all
+
+all:
+
+dist:
+ mkdir -p ../../$(distdir)/src/eshowkw/
+ cp Makefile eshowkw eshowkw.1 ../../$(distdir)/src/eshowkw/
+
+install: all
+ install -m 0755 eshowkw $(bindir)/
+ install -m 0644 eshowkw.1 $(mandir)/
+
diff --git a/gentoolkit-dev/src/eshowkw/eshowkw b/gentoolkit-dev/src/eshowkw/eshowkw
new file mode 100644
index 0000000..d5d3584
--- /dev/null
+++ b/gentoolkit-dev/src/eshowkw/eshowkw
@@ -0,0 +1,357 @@
+#!/bin/bash
+# vim: set sw=4 sts=4 et tw=80 :
+
+# Author: Ciaran McCreesh <ciaranm@gentoo.org>
+# Purpose: Display ebuild keywords in a graphical form
+# Invocation: eshowkw [ packagename ] (defaults to current directory if no
+# packagename is provided)
+
+shopt -s extglob
+
+PID_TO_KILL=$$
+
+die() {
+ echo "$@" 1>&2
+ kill $PID_TO_KILL
+}
+
+trap 'exit 250' 15
+
+get_portage_dir() {
+ local dir
+ if [[ -z ${portage_dir_cache} ]] ; then
+ for dir in "${HOME}/cvs/gentoo-x86" "/usr/portage" ; do
+ [[ -d ${dir}/profiles ]] && portage_dir_cache=${dir} && break
+ done
+ fi
+ [[ -z ${portage_dir_cache} ]] && portage_dir_cache=$(portageq portdir )
+ export portage_dir_cache
+ echo ${portage_dir_cache}
+}
+
+version_sort() {
+ local items= left=0
+ items=( $@ )
+
+ while [[ ${left} -lt ${#items[@]} ]] ; do
+ local lowest_idx=${left}
+ local idx=$(( ${lowest_idx} + 1 ))
+ while [[ ${idx} -lt ${#items[@]} ]] ; do
+ version_compare "${items[${lowest_idx}]}" "${items[${idx}]}"
+ [[ $? -eq 3 ]] && lowest_idx=${idx}
+ idx=$(( ${idx} + 1 ))
+ done
+ local tmp=${items[${lowest_idx}]}
+ items[${lowest_idx}]=${items[${left}]}
+ items[${left}]=${tmp}
+ left=$(( ${left} + 1 ))
+ done
+ echo ${items[@]}
+}
+
+version_compare() {
+ local ver_a=${1} ver_b=${2} parts_a parts_b cur_idx_a=0 cur_idx_b=0
+ parts_a=( $(get_all_version_components "${ver_a}" ) )
+ parts_b=( $(get_all_version_components "${ver_b}" ) )
+
+ ### compare number parts.
+ local inf_loop=0
+ while true ; do
+ # grab the current number components
+ local cur_tok_a=${parts_a[${cur_idx_a}]}
+ local cur_tok_b=${parts_b[${cur_idx_b}]}
+
+ # number?
+ if [[ -n ${cur_tok_a} ]] && [[ -z ${cur_tok_a//[[:digit:]]} ]] ; then
+ cur_idx_a=$(( ${cur_idx_a} + 1 ))
+ [[ ${parts_a[${cur_idx_a}]} == "." ]] \
+ && cur_idx_a=$(( ${cur_idx_a} + 1 ))
+ else
+ cur_tok_a=""
+ fi
+
+ if [[ -n ${cur_tok_b} ]] && [[ -z ${cur_tok_b//[[:digit:]]} ]] ; then
+ cur_idx_b=$(( ${cur_idx_b} + 1 ))
+ [[ ${parts_b[${cur_idx_b}]} == "." ]] \
+ && cur_idx_b=$(( ${cur_idx_b} + 1 ))
+ else
+ cur_tok_b=""
+ fi
+
+ # done with number components?
+ [[ -z ${cur_tok_a} ]] && [[ -z ${cur_tok_b} ]] && break
+
+ # to avoid going into octal mode, strip any leading zeros. otherwise
+ # bash will throw a hissy fit on versions like 6.3.068.
+ cur_tok_a=${cur_tok_a##+(0)}
+ cur_tok_b=${cur_tok_b##+(0)}
+
+ # if a component is blank, make it zero.
+ [[ -z ${cur_tok_a} ]] && cur_tok_a=0
+ [[ -z ${cur_tok_b} ]] && cur_tok_b=0
+
+ # compare
+ [[ ${cur_tok_a} -lt ${cur_tok_b} ]] && return 1
+ [[ ${cur_tok_a} -gt ${cur_tok_b} ]] && return 3
+ done
+
+ ### number parts equal. compare letter parts.
+ local letter_a=
+ letter_a=${parts_a[${cur_idx_a}]}
+ if [[ ${#letter_a} -eq 1 ]] && [[ -z ${letter_a/[a-z]} ]] ; then
+ cur_idx_a=$(( ${cur_idx_a} + 1 ))
+ else
+ letter_a="@"
+ fi
+
+ local letter_b=
+ letter_b=${parts_b[${cur_idx_b}]}
+ if [[ ${#letter_b} -eq 1 ]] && [[ -z ${letter_b/[a-z]} ]] ; then
+ cur_idx_b=$(( ${cur_idx_b} + 1 ))
+ else
+ letter_b="@"
+ fi
+
+ # compare
+ [[ ${letter_a} < ${letter_b} ]] && return 1
+ [[ ${letter_a} > ${letter_b} ]] && return 3
+
+ ### letter parts equal. compare suffixes in order.
+ local suffix rule part r_lt r_gt
+ for rule in "alpha=1" "beta=1" "pre=1" "rc=1" "p=3" "r=3" ; do
+ suffix=${rule%%=*}
+ r_lt=${rule##*=}
+ [[ ${r_lt} -eq 1 ]] && r_gt=3 || r_gt=1
+
+ local suffix_a=
+ for part in ${parts_a[@]} ; do
+ [[ ${part#${suffix}} != ${part} ]] && \
+ [[ -z ${part##${suffix}*([[:digit:]])} ]] && \
+ suffix_a=${part#${suffix}}0
+ done
+
+ local suffix_b=
+ for part in ${parts_b[@]} ; do
+ [[ ${part#${suffix}} != ${part} ]] && \
+ [[ -z ${part##${suffix}*([[:digit:]])} ]] && \
+ suffix_b=${part#${suffix}}0
+ done
+
+ [[ -z ${suffix_a} ]] && [[ -z ${suffix_b} ]] && continue
+
+ [[ -z ${suffix_a} ]] && return ${r_gt}
+ [[ -z ${suffix_b} ]] && return ${r_lt}
+
+ # avoid octal problems
+ suffix_a=${suffix_a##+(0)} ; suffix_a=${suffix_a:-0}
+ suffix_b=${suffix_b##+(0)} ; suffix_b=${suffix_b:-0}
+
+ [[ ${suffix_a} -lt ${suffix_b} ]] && return 1
+ [[ ${suffix_a} -gt ${suffix_b} ]] && return 3
+ done
+
+ ### no differences.
+ return 2
+}
+
+get_all_version_components() {
+ local ver_str=${1} result result_idx=0
+ result=( )
+
+ while [[ -n "$ver_str" ]] ; do
+ case "${ver_str:0:1}" in
+ # number: parse whilst we have a number
+ [[:digit:]])
+ result[$result_idx]="${ver_str%%[^[:digit:]]*}"
+ ver_str="${ver_str##+([[:digit:]])}"
+ result_idx=$(($result_idx + 1))
+ ;;
+
+ # separator: single character
+ [-_.])
+ result[$result_idx]="${ver_str:0:1}"
+ ver_str="${ver_str:1}"
+ result_idx=$(($result_idx + 1))
+ ;;
+
+ # letter: grab the letters plus any following numbers
+ [[:alpha:]])
+ local not_match="${ver_str##+([[:alpha:]])*([[:digit:]])}"
+ result[$result_idx]=${ver_str:0:$((${#ver_str} - ${#not_match}))}
+ ver_str="${not_match}"
+ result_idx=$(($result_idx + 1))
+ ;;
+
+ # huh?
+ *)
+ result[$result_idx]="${ver_str:0:1}"
+ ver_str="${ver_str:1}"
+ result_idx=$(($result_idx + 1))
+ ;;
+ esac
+ done
+
+ echo ${result[@]}
+}
+
+get_package_dir() {
+ if [[ -z ${1} ]] ; then
+ pwd
+ return 0
+ fi
+
+ if [[ -d ${1} ]] ; then
+ readlink -f ${1}
+ return 0
+ fi
+
+ get_portage_dir 1>/dev/null
+ if [[ ${1/\/} != ${1} ]] ; then
+ local d=$(get_portage_dir )/${1}
+ if [[ -d ${d} ]] ; then
+ echo ${d}
+ return 0
+ fi
+ else
+ local d
+ d=( $(echo $(get_portage_dir )/*-*/${1} ) )
+ if [[ ${#d[@]} -gt 1 ]] ; then
+ die "${1} is ambiguous"
+ elif [[ -d ${d[0]} ]] ; then
+ echo ${d[0]}
+ return 0
+ fi
+ fi
+
+ return 1
+}
+
+repeat() {
+ local i
+ for (( i=0 ; i < ${1} ; i=$(( ${i} + 1 )) )) ; do
+ echo -n "${2}"
+ done
+}
+
+get_keywords() {
+ (
+ inherit() { :; }
+ source "$(pwd)/${1}" 2>/dev/null
+ echo ${KEYWORDS}
+ )
+}
+
+colorarch() {
+ case "${1}" in
+ amd64)
+ echo -n -e "\033[0;33m${2}\033[0;0m"
+ ;;
+ x86)
+ echo -n -e "\033[0;31m${2}\033[0;0m"
+ ;;
+ *)
+ echo -n "${2}"
+ ;;
+ esac
+}
+
+colourise() {
+ case "${1}" in
+ \*)
+ echo -n -e "\033[0;31m*\033[0;0m"
+ ;;
+ +)
+ echo -n -e "\033[0;32m+\033[0;0m"
+ ;;
+ -)
+ echo -n -e "\033[0;31m-\033[0;0m"
+ ;;
+ \~)
+ echo -n -e "\033[0;33m~\033[0;0m"
+ ;;
+ *)
+ echo -n "${1}"
+ ;;
+ esac
+}
+
+show_keyword_diagram() {
+ echo -n -e "Keywords for \033[1;34m"
+ local title=$(readlink -f $(pwd ) )
+ title=${title#$(readlink -f ../.. )/*( )}
+ echo -n "${title}"
+ echo -e "\033[0;0m:"
+ echo
+
+ local archs=() arch_length=0 arch=
+ while read arch
+ do
+ [[ -z "${arch}" ]] && continue
+ [[ "${arch:0:1}" == "#" ]] && continue
+ [[ ${#arch} -gt ${arch_length} ]] && arch_length=${#arch}
+
+ archs[${#archs[*]}]=$arch
+ done < "$(get_portage_dir)/profiles/arch.list"
+
+
+ local versions= pkgname= version_length=0 version=
+ pkgname=$(basename $(readlink -f ./ ) )
+ versions=( $(for e in $(echo *.ebuild ) ; do \
+ [[ -f ${e} ]] && echo ${e} | sed -e 's/\.ebuild$//g' \
+ -e "s/^${pkgname}-//g" ; \
+ done ) )
+ versions=( $(version_sort ${versions[@]} ) )
+ for version in "${versions[@]}" ; do
+ [[ ${#version} -gt ${version_length} ]] && version_length=${#version}
+ done
+
+ local i=0 archletter=
+ for (( i = 0 ; i < ${arch_length} ; i=$(( ${i} + 1 )) )) ; do
+ repeat ${version_length} " "
+ echo -n " | "
+ for arch in "${archs[@]}" ; do
+ archletter="${arch:${i}:1}"
+ echo -n "$(colorarch "${arch}" "${archletter:- }" ) "
+ done
+ echo
+ done
+
+ repeat ${version_length} "-"
+ echo -n "-+"
+ repeat ${#archs[@]} "--"
+ echo
+
+ for version in "${versions[@]}" ; do
+ echo -n "${version}"
+ repeat $(( ${version_length} - ${#version} )) " "
+ echo -n " | "
+
+ local keyword keywords
+ keywords=( $(get_keywords "${pkgname}-${version}.ebuild" ) )
+ for arch in "${archs[@]}" ; do
+ local display=" "
+ [[ ${keywords[@]/-\*} != ${keywords[@]} ]] && display="*"
+ for keyword in "${keywords[@]}" ; do
+ [[ ${arch} == "${keyword#[~-]}" ]] && \
+ display=${keyword:0:1} && \
+ break;
+ done
+ [[ -z ${display#[~ *-]} ]] || display="+"
+ echo -n "$(colourise "${display}" ) "
+ done
+
+ echo
+ done
+}
+
+main() {
+ local dir=$(get_package_dir "${1}" )
+ [[ -z ${dir} ]] && die "Couldn't find '${1}'"
+ cd ${dir}
+ [[ $(echo *.ebuild ) != "*.ebuild" ]] || die "No ebuilds in ${dir}"
+ show_keyword_diagram
+ true
+}
+
+main "$@"
+
diff --git a/gentoolkit-dev/src/eshowkw/eshowkw.1 b/gentoolkit-dev/src/eshowkw/eshowkw.1
new file mode 100644
index 0000000..8d08048
--- /dev/null
+++ b/gentoolkit-dev/src/eshowkw/eshowkw.1
@@ -0,0 +1,14 @@
+.TH "eshowkw" "1" "Ciaran McCreesh" "gentoolkit-dev"
+.SH "NAME"
+.LP
+eshowkw \- Displays ebuild keywords in a graphical form.
+.SH "SYNTAX"
+.LP
+eshowkw [ packagename ] (defaults to current directory if no packagename is provided)
+
+
+.SH "AUTHORS"
+.LP
+Ciaran McCreesh <ciaranm@gentoo.org>
+.SH "BUGS"
+Please report any bugs to http://bugs.gentoo.org
diff --git a/gentoolkit-dev/src/eviewcvs/AUTHORS b/gentoolkit-dev/src/eviewcvs/AUTHORS
new file mode 100644
index 0000000..36d5bfd
--- /dev/null
+++ b/gentoolkit-dev/src/eviewcvs/AUTHORS
@@ -0,0 +1 @@
+Aron Griffis <agriffis@gentoo.org>
diff --git a/gentoolkit-dev/src/eviewcvs/Makefile b/gentoolkit-dev/src/eviewcvs/Makefile
new file mode 100644
index 0000000..7ab81c6
--- /dev/null
+++ b/gentoolkit-dev/src/eviewcvs/Makefile
@@ -0,0 +1,25 @@
+# Copyright 2005 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+#
+# $Header$
+
+include ../../makedefs.mak
+
+%.1 : %.pod
+ pod2man $< > $@
+
+.PHONY: all
+all: eviewcvs.1
+
+dist: eviewcvs.1
+ mkdir -p ../../$(distdir)/src/eviewcvs/
+ cp Makefile AUTHORS README eviewcvs eviewcvs.pod eviewcvs.1 ../../$(distdir)/src/eviewcvs/
+
+install: all
+ install -m 0755 eviewcvs $(bindir)/
+ install -d $(docdir)/eviewcvs
+ install -m 0644 AUTHORS README $(docdir)/eviewcvs/
+ install -m 0644 eviewcvs.1 $(mandir)/
+
+clean:
+ $(RM) eviewcvs.1
diff --git a/gentoolkit-dev/src/eviewcvs/README b/gentoolkit-dev/src/eviewcvs/README
new file mode 100644
index 0000000..c7258d7
--- /dev/null
+++ b/gentoolkit-dev/src/eviewcvs/README
@@ -0,0 +1,11 @@
+Most of the documentation is contained in the man-page, which you can
+read directly (using GNU man) by doing
+
+ man ./eviewcvs.1
+
+To rebuild the man-page from pod source, do
+
+ pod2man --name=eviewcvs --center='Gentoolkit' \
+ eviewcvs.pod eviewcvs.1
+
+03 Nov 2004 agriffis
diff --git a/gentoolkit-dev/src/eviewcvs/eviewcvs b/gentoolkit-dev/src/eviewcvs/eviewcvs
new file mode 100755
index 0000000..280ec0b
--- /dev/null
+++ b/gentoolkit-dev/src/eviewcvs/eviewcvs
@@ -0,0 +1,95 @@
+#!/bin/bash
+# $Id$
+#
+# Copyright 2005, Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# Written by Aron Griffis <agriffis@gentoo.org>
+#
+# eviewcvs - generate viewcvs urls for some files
+#
+
+if [[ -t 1 ]]; then
+ blue=""
+ cyan=""
+ green=""
+ red=""
+ off=""
+else
+ unset blue cyan green red off
+fi
+
+startdir="$PWD"
+url="http://sources.gentoo.org/viewcvs.py"
+unset diffs
+declare -a hdr orev
+
+chdir() {
+ cd "$1" || return
+
+ # Figure out where we are, hopefully
+ unset cwd root
+ if [[ -f CVS/Repository ]]; then
+ cwd=$(<CVS/Repository)
+ elif [[ -f .svn/entries ]]; then
+ cwd=$(grep -om1 'url=.*' .svn/entries)
+ cwd=${cwd#*/var/svnroot/}
+ cwd=${cwd%\"*}
+ fi
+}
+
+# Default to all files in directory
+[[ -n $* ]] || set -- *
+
+for f in "$@"; do
+ [[ -f $f ]] || continue
+
+ # Determine the directory settings
+ if [[ $f == */* ]]; then
+ chdir ${f%/*}
+ f=${f##*/}
+ else
+ chdir ${startdir}
+ fi
+
+ # Default to the directory settings
+ fwd=$cwd
+
+ # Get the header for this file, from which we can extract the root,
+ # directory and revision
+ hdr=( $(egrep -m1 -o '\$(Header|Id):[^$]*\$' "$f") )
+ frev=${hdr[2]}
+ case ${hdr[*]} in
+ \$Header:\ /var/cvsroot/*/*\ \$*)
+ fwd=${hdr[1]} # /var/cvsroot/gentoo-src/keychain/keychain.sh,v
+ fwd=${fwd#/var/cvsroot/} # gentoo-src/keychain/keychain.sh,v
+ fwd=${fwd%/*} # gentoo-src/keychain
+ ;;
+ '')
+ if [[ -d CVS ]]; then
+ frev=$(cvs log "$f" 2>/dev/null | awk '/^head:/{print $2}')
+ elif [[ -d .svn ]]; then
+ frev=$(svn info "$f" 2>/dev/null | awk '/^Revision:/{print $2}')
+ fi
+ ;;
+ esac
+ [[ -n ${frev} ]] || continue
+
+ # Here is the simple URL to view it
+ echo "${url}/${fwd:+$fwd/}${green}${f}${off}?rev=${frev}&view=markup"
+
+ # Also supply a diff URL if possible
+ if [[ ${frev##*.} -gt 1 ]]; then
+ orev=( ${frev//./ } ) # convert to array
+ (( orev[${#orev[@]}-1]-- )) # decrement the last element
+ orev=${orev[*]} # convert to string
+ orev=${orev// /.} # revert spaces to dots
+ diffs="${diffs:+$diffs
+}${url}/${fwd:+$fwd/}${blue}${f}${off}?r1=${orev}&r2=${frev}"
+ fi
+done
+
+if [[ -n ${diffs} ]]; then
+ echo "${diffs}"
+fi
+
+# vim:set expandtab sw=4 smarttab:
diff --git a/gentoolkit-dev/src/eviewcvs/eviewcvs.pod b/gentoolkit-dev/src/eviewcvs/eviewcvs.pod
new file mode 100644
index 0000000..b4403c8
--- /dev/null
+++ b/gentoolkit-dev/src/eviewcvs/eviewcvs.pod
@@ -0,0 +1,48 @@
+=head1 NAME
+
+eviewcvs - Gentoo: generate viewcvs URLs
+
+=head1 SYNOPSIS
+
+eviewcvs [ I<files...> ]
+
+=head1 DESCRIPTION
+
+This tool generates a list of viewcvs URLs based on the files listed, or all the
+files in the current directory if the file list is omitted. The first part of
+the output, hilighted in green, is the simple URLs to view the files. The
+second part of the output, hilighted in blue, is the URLs to view the diffs
+against the previous revision.
+
+=head1 OPTIONS
+
+Presently eviewcvs is simple enough that it supplies no options.
+Probably I'll add B<--help> and B<--version> in the future, but for
+now it's enough to track the gentoolkit version.
+
+=head1 EXAMPLES
+
+To generate viewcvs URLs for a given file:
+
+ $ eviewcvs package.mask
+ http://www.gentoo.org/cgi-bin/viewcvs.cgi/profiles/package.mask?rev=1.3716&content-type=text/vnd.viewcvs-markup
+ http://www.gentoo.org/cgi-bin/viewcvs.cgi/profiles/package.mask?r1=1.3715&r2=1.3716
+
+To generate viewcvs URLs for all files in a directory:
+
+ $ cd portage/net-misc/keychain
+ $ eviewcvs
+ http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/keychain/ChangeLog?rev=1.54&view=markup
+ http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/keychain/Manifest?rev=1.86&view=markup
+ http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/keychain/keychain-2.6.1.ebuild?rev=1.3&view=markup
+ http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/keychain/keychain-2.6.2.ebuild?rev=1.1&view=markup
+ http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/keychain/metadata.xml?rev=1.3&view=markup
+ http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/keychain/ChangeLog?r1=1.53&r2=1.54
+ http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/keychain/Manifest?r1=1.85&r2=1.86
+ http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/keychain/keychain-2.6.1.ebuild?r1=1.2&r2=1.3
+ http://sources.gentoo.org/viewcvs.py/gentoo-x86/net-misc/keychain/metadata.xml?r1=1.2&r2=1.3
+
+=head1 AUTHOR
+
+This tool was written by Aron Griffis <agriffis@gentoo.org>. Bugs
+found should be filed against me at http://bugs.gentoo.org/
diff --git a/gentoolkit-dev/src/imlate/Makefile b/gentoolkit-dev/src/imlate/Makefile
new file mode 100644
index 0000000..dd88d2b
--- /dev/null
+++ b/gentoolkit-dev/src/imlate/Makefile
@@ -0,0 +1,18 @@
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+include ../../makedefs.mak
+
+.PHONY: all
+
+all:
+
+dist:
+ mkdir -p ../../$(distdir)/src/imlate/
+ cp Makefile imlate imlate.1 ../../$(distdir)/src/imlate/
+
+install: all
+ install -m 0755 imlate $(bindir)/
+ install -m 0644 imlate.1 $(mandir)/
+
diff --git a/gentoolkit-dev/src/imlate/imlate b/gentoolkit-dev/src/imlate/imlate
new file mode 100755
index 0000000..ed019cc
--- /dev/null
+++ b/gentoolkit-dev/src/imlate/imlate
@@ -0,0 +1,484 @@
+#!/usr/bin/python
+
+# Copyright 1999-2009 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+# author: Christian Ruppert <idl0r@gentoo.org>
+
+VERSION = "0.0.4"
+
+# works just with stable keywords!
+MAIN_ARCH = "auto" # can be overridden by -m ARCH
+TARGET_ARCH = "auto" # can be overridden by -t ARCH
+# auto means e.g.:
+# MAIN_ARCH = amd64
+# TARGET_ARCH = ~amd64
+# That will show you general stable candidates for amd64.
+# The arch will be taken from your portage settings (e.g. make.conf).
+
+################################
+# do not change anything below #
+################################
+
+from os.path import join, basename
+from sys import stderr, stdout
+from os import stat
+from time import time
+from xml.dom import minidom, NotFoundErr
+from xml.parsers.expat import ExpatError
+# TODO: just import needed stuff to safe memory and maybe use "as foo"
+import portage
+import portage.versions
+
+if __name__ == "__main__":
+ from optparse import OptionParser
+ from time import gmtime, strftime
+
+# portage < 2.1.6 needs portage_const instead of portage.const,
+# which is not the problem...
+# the problem is the keyword handling (ACCEPT_KEYWORDS)
+# portage < 2.1.6 does not support -*
+# but -* is needed to ensure that we just check for arch
+if portage.versions.vercmp(portage.VERSION, "2.1.6") < 0:
+ raise StandardError, "imlate requires portage >=2.1.6"
+
+# override/change portage module settings
+def _portage_settings( var, value, settings = None ):
+ if not settings:
+ settings = portage.settings
+
+ settings.unlock()
+ settings[var] = value
+ # backup_changes is very important since it can cause trouble,
+ # if we do not backup our changes!
+ settings.backup_changes( var )
+ settings.lock()
+
+# add stuff to our imlate dict
+def _add_ent( imlate, cat, pkg, ver, our_ver ):
+ if not cat in imlate.keys():
+ imlate[cat] = {}
+ if not pkg in imlate[cat].keys():
+ imlate[cat][pkg] = []
+
+ imlate[cat][pkg].append( ver )
+ imlate[cat][pkg].append( our_ver )
+
+ return imlate
+
+def _fill( width, line, fill = " " ):
+ while len( line ) < width:
+ line = "%s%s" % ( str( line ), str( fill ) )
+ return line
+
+# create a hopefully pretty result
+def show_result( conf, pkgs ):
+ # X - len(colX) = space to fill
+ col1 = 40
+ col2 = 20
+
+ _header = "%s candidates for 'gentoo' on '%s'"
+ _helper = "category/package[:SLOT] our version best version"
+ _cand = ""
+ header = ""
+
+ if conf["FILE"] == "stdout":
+ out = stdout
+ elif conf["FILE"] == "stderr":
+ out = stderr
+ else:
+ out = open( conf["FILE"], "w" )
+
+ if conf["STABLE"] and conf["KEYWORD"]:
+ _cand = "%i Stable and %i Keyword(~)" % ( conf["STABLE_SUM"],
+ conf["KEYWORD_SUM"] )
+ elif conf["STABLE"]:
+ _cand = "%i Stable" % conf["STABLE_SUM"]
+ elif conf["KEYWORD"]:
+ _cand = "%i Keyword(~)" % conf["KEYWORD_SUM"]
+
+ header = _header % ( _cand, conf["MAIN_ARCH"] )
+
+ print >> out, "Generated on: %s" % conf["TIME"]
+ print >> out, _fill( len( header ), "", "=" )
+ print >> out, header
+ print >> out, _fill( len( header ), "", "=" )
+ print >> out
+
+ print >> out, _helper
+ print >> out, _fill( len( _helper ), "", "-" )
+
+ for cat in sorted( pkgs.keys() ):
+ print >> out, "%s/" % cat
+ for pkg in sorted( pkgs[cat].keys() ):
+ print >> out, "%s%s%s" % ( _fill( col1, ( " %s" % pkg ) ),
+ _fill( col2, pkgs[cat][pkg][1] ),
+ pkgs[cat][pkg][0] )
+
+ if conf["FILE"] != "stdout":
+ out.close()
+
+def _get_metadata(metadata, element, tag):
+ values = []
+
+ try:
+ metadatadom = minidom.parse(metadata)
+ except ExpatError, e:
+ raise ExpatError("%s: %s" % (metadata, e,))
+
+ try:
+ elements = metadatadom.getElementsByTagName(element)
+ if not elements:
+ return values
+ except NotFoundErr:
+ return values
+
+ try:
+ for _element in elements:
+ node = _element.getElementsByTagName(tag)
+
+ if tag == "herd" and (not node or not node[0].childNodes):
+# print >> stderr, "'%s' is missing a <herd> tag or it is empty," % metadata
+# print >> stderr, "please file a bug at https://bugs.gentoo.org and refer to http://www.gentoo.org/proj/en/devrel/handbook/handbook.xml?part=2&chap=4"
+ values.append("no-herd")
+ continue
+
+ values.append(node[0].childNodes[0].data)
+ except NotFoundErr:
+ raise NotFoundErr("%s: Malformed input: missing 'flag' tag(s)" % (metadata))
+
+ metadatadom.unlink()
+ return values
+
+def is_maintainer(maintainer, metadata):
+ data = []
+
+ if maintainer == None:
+ return True
+
+ mtainer = maintainer.split(",")
+
+ data = _get_metadata(metadata, "maintainer", "email")
+
+ if not data and len(maintainer) == 0:
+ return True
+ elif not data and len(maintainer) > 0:
+ return False
+ else:
+ for addy in data:
+ for contact in mtainer:
+ if addy == contact:
+ return True
+ if addy.startswith(contact):
+ return True
+ return False
+
+def is_herd(herd, metadata):
+ data = []
+
+ if herd == None:
+ return True
+
+ hrd = herd.split(",")
+ data = _get_metadata(metadata, "pkgmetadata", "herd")
+
+ if not data and len(herd) == 0:
+ return True
+ elif not data and len(herd) > 0:
+ return False
+ else:
+ for hd in data:
+ for hd2 in hrd:
+ if hd == hd2:
+ return True
+ if hd.startswith(hd2):
+ return True
+
+ return False
+
+
+# fetch a list of arch (just stable) packages
+# -* is important to be sure that just arch is used
+def get_packages( conf ):
+ _pkgs = {}
+
+ _portage_settings( "ACCEPT_KEYWORDS", ( "-* %s" % str( conf["TARGET_ARCH"] ) ),
+ conf["portdb"].settings )
+
+ for cp in conf["portdb"].dbapi.cp_all():
+ cpvrs = []
+ slots = {}
+
+ if conf["USER_PKGS"]:
+ if not cp in conf["USER_PKGS"]:
+ continue
+
+ # None is important to match also on empty string
+ if conf["MAINTAINER"] != None:
+ if not is_maintainer(conf["MAINTAINER"], join(conf["PORTDIR"], cp, "metadata.xml")):
+ continue
+ if conf["HERD"] != None:
+ if not is_herd(conf["HERD"], join(conf["PORTDIR"], cp, "metadata.xml")):
+ continue
+
+ cpvrs = conf["portdb"].dbapi.match( cp )
+
+ for cpvr in cpvrs:
+ slot = conf["portdb"].dbapi.aux_get( cpvr, ["SLOT"] )[0]
+ if not slot in slots:
+ slots[slot] = []
+ slots[slot].append(cpvr)
+
+ for slot in sorted(slots):
+ cpvr = portage.versions.best( slots[slot] )
+
+ if cpvr:
+ ( cat, pkg, ver, rev ) = portage.versions.catpkgsplit( cpvr )
+
+ if not cat in _pkgs.keys():
+ _pkgs[cat] = {}
+ if not pkg in _pkgs[cat].keys():
+ _pkgs[cat][pkg] = []
+
+ if rev != "r0":
+ ver = "%s-%s" % ( ver, rev )
+
+ _pkgs[cat][pkg].append( ver )
+
+ return _pkgs
+
+# compare get_packages() against MAIN_ARCH
+def get_imlate( conf, pkgs ):
+ _portage_settings( "ACCEPT_KEYWORDS", ( "-* %s" % str( conf["MAIN_ARCH"] ) ),
+ conf["portdb"].settings )
+
+ stable = str( conf["MAIN_ARCH"].lstrip("~") )
+ testing = "~%s" % stable
+ exclude = "-%s" % stable
+ exclude_all = "-*"
+
+ imlate = {}
+
+ for cat in sorted( pkgs.keys() ):
+ for pkg in sorted( pkgs[cat].keys() ):
+ for vr in pkgs[cat][pkg]:
+ cpvr = ""
+ abs_pkg = ""
+ kwds = ""
+ our = ""
+ our_ver = ""
+ mtime = 0
+ slot = 0
+
+ # 0 = none(default), 1 = testing(~arch), 2 = stable(arch),
+ # 3 = exclude(-arch), 4 = exclude_all(-*)
+ # -* would be overridden by ~arch or arch
+ kwd_type = 0
+
+ cpvr = "%s/%s-%s" % ( cat, pkg, vr )
+
+ # absolute ebuild path for mtime check
+ abs_pkg = join( conf["PORTDIR"], cat, pkg, basename( cpvr ) )
+ abs_pkg = "%s.ebuild" % str( abs_pkg )
+
+ kwds = conf["portdb"].dbapi.aux_get( cpvr, ["KEYWORDS"] )[0]
+
+ # FIXME: %s is bad.. maybe even cast it, else there are issues because its unicode
+ slot = ":%s" % conf["portdb"].dbapi.aux_get( cpvr, ["SLOT"] )[0]
+ if slot == ":0":
+ slot = ""
+
+ # sorted() to keep the right order
+ # e.g. -* first, -arch second, arch third and ~arch fourth
+ # -* -foo ~arch
+ # example: -* would be overridden by ~arch
+ for kwd in sorted( kwds.split() ):
+ if kwd == stable:
+ kwd_type = 2
+ break
+ elif kwd == exclude:
+ kwd_type = 3
+ break
+ elif kwd == exclude_all:
+ kwd_type = 4
+ elif kwd == testing:
+ kwd_type = 1
+ break
+
+ # ignore -arch and already stabilized packages
+ if kwd_type == 3 or kwd_type == 2:
+ continue
+ # drop packages with -* and without ~arch or arch
+ # even if there is another version which includes arch or ~arch
+ if kwd_type == 4:
+ continue
+ # drop "stable candidates" with mtime < 30 days
+ # Shall we use gmtime/UTC here?
+ if kwd_type == 1:
+ mtime = int( ( time() - stat( abs_pkg ).st_mtime ) / 60 / 60 / 24 )
+ if mtime < conf["MTIME"]:
+ continue
+
+ # look for an existing stable version
+ our = portage.versions.best( conf["portdb"].dbapi.match( "%s/%s%s" % ( cat, pkg, slot ) ) )
+ if our:
+ _foo = portage.versions.pkgsplit( our )
+ our_ver = _foo[1]
+ if _foo[2] != "r0":
+ our_ver = "%s-%s" % ( our_ver, _foo[2] )
+ else:
+ our_ver = ""
+
+ # we just need the version if > our_ver
+ if our_ver:
+ if portage.versions.vercmp( our_ver, vr ) >= 0:
+ continue
+
+ if kwd_type == 1 and conf["STABLE"]:
+ imlate = _add_ent( imlate, cat, ("%s%s" % (pkg, slot)), vr, our_ver )
+ conf["STABLE_SUM"] += 1
+ elif kwd_type == 0 and conf["KEYWORD"]:
+ conf["KEYWORD_SUM"] += 1
+ imlate = _add_ent( imlate, cat, ( "~%s%s" % (pkg, slot) ),
+ vr, our_ver )
+
+ return imlate
+
+# fetch portage related settings
+def get_settings( conf = None ):
+ if not isinstance( conf, dict ) and conf:
+ raise TypeError, "conf must be dict() or None"
+ if not conf:
+ conf = {}
+
+ # TODO: maybe we should improve it a bit ;)
+ mysettings = portage.config( config_incrementals = portage.const.INCREMENTALS, local_config = False )
+
+ if conf["MAIN_ARCH"] == "auto":
+ conf["MAIN_ARCH"] = "%s" % mysettings["ACCEPT_KEYWORDS"].split(" ")[0].lstrip("~")
+ if conf["TARGET_ARCH"] == "auto":
+ conf["TARGET_ARCH"] = "~%s" % mysettings["ACCEPT_KEYWORDS"].split(" ")[0].lstrip("~")
+
+ # TODO: exclude overlay categories from check
+ if conf["CATEGORIES"]:
+ _mycats = []
+ for _cat in conf["CATEGORIES"].split(","):
+ _cat = _cat.strip()
+ _mycats.append(_cat )
+ if _cat not in mysettings.categories:
+ raise ValueError, "invalid category for -C switch '%s'" % _cat
+ mysettings.categories = _mycats
+
+ # maybe thats not necessary because we override porttrees below..
+ _portage_settings( "PORTDIR_OVERLAY", "", mysettings )
+ trees = portage.create_trees()
+ trees["/"]["porttree"].settings = mysettings
+ portdb = trees["/"]["porttree"]
+ portdb.dbapi.mysettings = mysettings
+ portdb.dbapi.porttrees = [portage.portdb.porttree_root]
+ # does it make sense to remove _all_ useless stuff or just leave it as it is?
+ #portdb.dbapi._aux_cache_keys.clear()
+ #portdb.dbapi._aux_cache_keys.update(["EAPI", "KEYWORDS", "SLOT"])
+
+ conf["PORTDIR"] = portage.settings["PORTDIR"]
+ conf["portdb"] = portdb
+
+ return conf
+
+
+# just for standalone
+def main():
+ conf = {}
+ pkgs = {}
+
+ parser = OptionParser( version = "%prog " + VERSION )
+ parser.usage = "%prog [options] [category/package] ..."
+ parser.disable_interspersed_args()
+
+ parser.add_option( "-f", "--file", dest = "filename", action = "store", type = "string",
+ help = "write result into FILE [default: %default]", metavar = "FILE", default = "stdout" )
+ parser.add_option( "-m", "--main", dest = "main_arch", action = "store", type = "string",
+ help = "set main ARCH (e.g. your arch) [default: %default]", metavar = "ARCH", default = MAIN_ARCH )
+ parser.add_option( "-t", "--target", dest = "target_arch", action = "store", type = "string",
+ help = "set target ARCH (e.g. x86) [default: %default]", metavar = "ARCH", default = TARGET_ARCH )
+ parser.add_option( "--mtime", dest = "mtime", action = "store", type = "int",
+ help = "set minimum MTIME in days [default: %default]", metavar = "MTIME", default = 30 )
+
+ # TODO: leave a good comment here (about True/False) :)
+ parser.add_option( "-s", "--stable", dest = "stable", action = "store_true", default = False,
+ help = "just show stable candidates (e.g. -s and -k is the default result) [default: True]" )
+ parser.add_option( "-k", "--keyword", dest = "keyword", action = "store_true", default = False,
+ help = "just show keyword candidates (e.g. -s and -k is the default result) [default: True]" )
+
+ parser.add_option( "-M", "--maintainer", dest = "maintainer", action = "store", type = "string",
+ help = "Show only packages from the specified maintainer", metavar = "MAINTAINER", default = None)
+
+ parser.add_option( "-H", "--herd", dest = "herd", action = "store", type = "string",
+ help = "Show only packages from the specified herd", metavar = "HERD", default = None)
+
+# # EXPERIMENTAL
+# parser.add_option( "-e", "--experimental", dest = "experimental", action = "store_true", default = False,
+# help = "enables experimental functions/features (have a look for # EXPERIMENTAL comments in the source) [default: %default]" )
+
+ parser.add_option( "-C", "--category", "--categories", dest = "categories", action = "store", default = None,
+ metavar = "CATEGORIES",
+ help = "just check in the specified category/categories (comma separated) [default: %default]")
+
+ ( options, args ) = parser.parse_args()
+
+ if len( args ) > 0:
+ conf["USER_PKGS"] = args
+ else:
+ conf["USER_PKGS"] = []
+
+ # cleanup optparse
+ try:
+ parser.destroy()
+ except AttributeError:
+ # to be at least python 2.4 compatible
+ del parser._short_opt
+ del parser._long_opt
+ del parser.defaults
+
+ # generated timestamp (UTC)
+ conf["TIME"] = strftime( "%a %b %d %H:%M:%S %Z %Y", gmtime() )
+
+ # package counter
+ conf["KEYWORD_SUM"] = 0
+ conf["STABLE_SUM"] = 0
+
+ if not options.main_arch in portage.archlist and options.main_arch != "auto":
+ raise ValueError, "invalid MAIN ARCH defined!"
+ if not options.target_arch in portage.archlist and options.target_arch != "auto":
+ raise ValueError, "invalid TARGET ARCH defined!"
+
+ conf["MAIN_ARCH"] = options.main_arch
+ conf["TARGET_ARCH"] = options.target_arch
+
+ conf["FILE"] = options.filename
+ conf["MTIME"] = options.mtime
+
+ if not options.stable and not options.keyword:
+ conf["STABLE"] = True
+ conf["KEYWORD"] = True
+ else:
+ conf["STABLE"] = options.stable
+ conf["KEYWORD"] = options.keyword
+
+# conf["EXPERIMENTAL"] = options.experimental
+ conf["CATEGORIES"] = options.categories
+
+ conf["MAINTAINER"] = options.maintainer
+ conf["HERD"] = options.herd
+
+ # append to our existing
+ conf = get_settings( conf )
+ pkgs = get_packages( conf )
+ pkgs = get_imlate( conf, pkgs )
+
+ show_result( conf, pkgs )
+
+if __name__ == "__main__":
+ main()
+
diff --git a/gentoolkit-dev/src/imlate/imlate.1 b/gentoolkit-dev/src/imlate/imlate.1
new file mode 100644
index 0000000..d4a1dc2
--- /dev/null
+++ b/gentoolkit-dev/src/imlate/imlate.1
@@ -0,0 +1,48 @@
+.TH "imlate" "1" "0.0.4" "Christian Ruppert" "gentoolkit-dev"
+.SH "NAME"
+.LP
+imlate \- Displays candidates for keywords for an architecture based upon a target architecture.
+.SH "SYNTAX"
+.LP
+imlate [options]
+
+
+.SH "OPTIONS"
+.TP
+.B \-\-version
+show program's version number and exit
+.TP
+.B \-h, \-\-help
+show this help message and exit
+.TP
+.B \-f FILE, \-\-file=FILE
+write result into FILE [default: stdout]
+.TP
+.B \-m ARCH, \-\-main=ARCH
+set main ARCH (e.g. your arch) [default: amd64]
+.TP
+.B \-t ARCH, \-\-target=ARCH
+set target ARCH (e.g. x86) [default: x86]
+.TP
+.B \-\-mtime=MTIME
+set minimum MTIME in days [default: 30]
+.TP
+.B \-s, \-\-stable
+just show stable candidates (e.g. \-s and \-k is the default result) [default: True]
+.TP
+.B \-k, \-\-keyword
+just show keyword candidates (e.g. \-s and \-k is the default result) [default: True]
+.TP
+.B \-M MAINTAINER, \-\-maintainer=MAINTAINER
+Show only packages from the specified maintainer
+.TP
+.B \-H HERD, \-\-herd=HERD
+Show only packages from the specified herd
+.TP
+.B \-C CATEGORIES, \-\-category=CATEGORIES, \-\-categories=CATEGORIES
+just check in the specified category/categories (comma separated) [default: none]
+.SH "AUTHORS"
+.LP
+Christian Ruppert <idl0r@gentoo.org>
+.SH "BUGS"
+Please report any bugs to http://bugs.gentoo.org