aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfuzzyray <fuzzyray@gentoo.org>2009-05-05 17:39:24 +0000
committerfuzzyray <fuzzyray@gentoo.org>2009-05-05 17:39:24 +0000
commitc819d146be6bce86d97019494173253e71b85d2f (patch)
tree200d00c2b9a420540ff9c4e0d8b3080b762fb562
parentAdd some useful informations when using $EDITOR. (diff)
downloadgentoolkit-c819d146be6bce86d97019494173253e71b85d2f.tar.gz
gentoolkit-c819d146be6bce86d97019494173253e71b85d2f.tar.bz2
gentoolkit-c819d146be6bce86d97019494173253e71b85d2f.zip
Rearrange trunk to support gentoolkit version 0.3. Split into gentoolkit, gentoolkit-dev, and deprecated. Import djanderson's work on the gentoolkit library and equery
svn path=/trunk/gentoolkit/; revision=589
-rw-r--r--AUTHORS28
-rw-r--r--COPYING (renamed from trunk/COPYING)0
-rw-r--r--ChangeLog (renamed from trunk/ChangeLog)0
-rw-r--r--NEWS (renamed from trunk/NEWS)0
-rw-r--r--README (renamed from trunk/README)0
-rw-r--r--THANKS8
-rw-r--r--TODO (renamed from trunk/TODO)0
-rw-r--r--bin/eclean802
-rwxr-xr-xbin/epkginfo207
-rw-r--r--bin/equery32
-rwxr-xr-xbin/eread (renamed from trunk/src/eread/eread)0
-rwxr-xr-xbin/euse547
-rw-r--r--bin/glsa-check366
-rwxr-xr-xbin/revdep-rebuild1094
-rw-r--r--data/99gentoolkit-env (renamed from trunk/src/99gentoolkit-env)0
-rw-r--r--data/eclean/distfiles.exclude (renamed from trunk/src/eclean/distfiles.exclude)0
-rw-r--r--data/eclean/packages.exclude (renamed from trunk/src/eclean/packages.exclude)0
-rw-r--r--data/revdep-rebuild/99revdep-rebuild (renamed from trunk/src/revdep-rebuild/99revdep-rebuild)0
-rw-r--r--man/eclean.1 (renamed from trunk/src/eclean/eclean.1)0
-rw-r--r--man/epkginfo.1 (renamed from trunk/src/epkginfo/epkginfo.1)0
-rw-r--r--man/equery.1 (renamed from trunk/src/equery/equery.1)0
-rw-r--r--man/eread.1 (renamed from trunk/src/eread/eread.1)0
-rw-r--r--man/euse.1 (renamed from trunk/src/euse/euse.1)0
-rw-r--r--man/genpkgindex.1 (renamed from trunk/src/genpkgindex/genpkgindex.1)0
-rw-r--r--man/glsa-check.157
-rw-r--r--man/revdep-rebuild.1101
-rw-r--r--pym/gentoolkit/__init__.py52
-rw-r--r--pym/gentoolkit/equery/__init__.py407
-rw-r--r--pym/gentoolkit/equery/belongs.py160
-rw-r--r--pym/gentoolkit/equery/changes.py336
-rw-r--r--pym/gentoolkit/equery/check.py232
-rw-r--r--pym/gentoolkit/equery/depends.py248
-rw-r--r--pym/gentoolkit/equery/depgraph.py194
-rw-r--r--pym/gentoolkit/equery/files.py311
-rw-r--r--pym/gentoolkit/equery/hasuse.py189
-rw-r--r--pym/gentoolkit/equery/list_.py251
-rw-r--r--pym/gentoolkit/equery/meta.py533
-rw-r--r--pym/gentoolkit/equery/size.py199
-rw-r--r--pym/gentoolkit/equery/uses.py340
-rw-r--r--pym/gentoolkit/equery/which.py98
-rw-r--r--pym/gentoolkit/errors.py92
-rw-r--r--pym/gentoolkit/glsa/__init__.py644
-rw-r--r--pym/gentoolkit/helpers.py162
-rw-r--r--pym/gentoolkit/helpers2.py425
-rw-r--r--pym/gentoolkit/package.py582
-rw-r--r--pym/gentoolkit/pprinter.py (renamed from trunk/src/gentoolkit/pprinter.py)0
-rw-r--r--pym/gentoolkit/tests/equery/test_init.py43
-rw-r--r--pym/gentoolkit/tests/test_helpers2.py39
-rw-r--r--pym/gentoolkit/tests/test_template.py38
-rw-r--r--pym/gentoolkit/textwrap_.py97
-rwxr-xr-xsetup.py50
-rw-r--r--src/eclean/AUTHORS (renamed from trunk/src/eclean/AUTHORS)0
-rw-r--r--src/eclean/ChangeLog (renamed from trunk/src/eclean/ChangeLog)0
-rw-r--r--src/eclean/Makefile (renamed from trunk/src/eclean/Makefile)0
-rw-r--r--src/eclean/THANKS (renamed from trunk/src/eclean/THANKS)0
-rw-r--r--src/eclean/TODO (renamed from trunk/src/eclean/TODO)0
-rw-r--r--src/eclean/distfiles.exclude5
-rw-r--r--src/eclean/eclean (renamed from trunk/src/eclean/eclean)0
-rw-r--r--src/eclean/eclean.1176
-rw-r--r--src/eclean/packages.exclude4
-rw-r--r--src/epkginfo/Makefile (renamed from trunk/src/epkginfo/Makefile)0
-rwxr-xr-xsrc/epkginfo/epkginfo (renamed from trunk/src/epkginfo/epkginfo)0
-rw-r--r--src/epkginfo/epkginfo.134
-rw-r--r--src/equery/AUTHORS (renamed from trunk/src/equery/AUTHORS)0
-rw-r--r--src/equery/Makefile (renamed from trunk/src/equery/Makefile)0
-rw-r--r--src/equery/README (renamed from trunk/src/equery/README)0
-rw-r--r--src/equery/TODO (renamed from trunk/src/equery/TODO)0
-rwxr-xr-xsrc/equery/equery (renamed from trunk/src/equery/equery)0
-rw-r--r--src/equery/equery.1278
-rw-r--r--src/equery/tests/common-functions.sh (renamed from trunk/src/equery/tests/common-functions.sh)0
-rwxr-xr-xsrc/equery/tests/run-all-tests.sh (renamed from trunk/src/equery/tests/run-all-tests.sh)0
-rw-r--r--src/equery/tests/test-belongs-help.out (renamed from trunk/src/equery/tests/test-belongs-help.out)0
-rwxr-xr-xsrc/equery/tests/test-belongs.sh (renamed from trunk/src/equery/tests/test-belongs.sh)0
-rw-r--r--src/equery/tests/test-changes-help.out (renamed from trunk/src/equery/tests/test-changes-help.out)0
-rw-r--r--src/equery/tests/test-check-help.out (renamed from trunk/src/equery/tests/test-check-help.out)0
-rwxr-xr-xsrc/equery/tests/test-check.sh (renamed from trunk/src/equery/tests/test-check.sh)0
-rw-r--r--src/equery/tests/test-depends-help.out (renamed from trunk/src/equery/tests/test-depends-help.out)0
-rwxr-xr-xsrc/equery/tests/test-depends.sh (renamed from trunk/src/equery/tests/test-depends.sh)0
-rw-r--r--src/equery/tests/test-depgraph-help.out (renamed from trunk/src/equery/tests/test-depgraph-help.out)0
-rwxr-xr-xsrc/equery/tests/test-depgraph.sh (renamed from trunk/src/equery/tests/test-depgraph.sh)0
-rw-r--r--src/equery/tests/test-files-help.out (renamed from trunk/src/equery/tests/test-files-help.out)0
-rwxr-xr-xsrc/equery/tests/test-files.sh (renamed from trunk/src/equery/tests/test-files.sh)0
-rw-r--r--src/equery/tests/test-glsa-help.out (renamed from trunk/src/equery/tests/test-glsa-help.out)0
-rw-r--r--src/equery/tests/test-hasuses-help.out (renamed from trunk/src/equery/tests/test-hasuses-help.out)0
-rw-r--r--src/equery/tests/test-help.out (renamed from trunk/src/equery/tests/test-help.out)0
-rwxr-xr-xsrc/equery/tests/test-help.sh (renamed from trunk/src/equery/tests/test-help.sh)0
-rw-r--r--src/equery/tests/test-list-help.out (renamed from trunk/src/equery/tests/test-list-help.out)0
-rwxr-xr-xsrc/equery/tests/test-list.sh (renamed from trunk/src/equery/tests/test-list.sh)0
-rw-r--r--src/equery/tests/test-size-help.out (renamed from trunk/src/equery/tests/test-size-help.out)0
-rwxr-xr-xsrc/equery/tests/test-size.sh (renamed from trunk/src/equery/tests/test-size.sh)0
-rw-r--r--src/equery/tests/test-stats-help.out (renamed from trunk/src/equery/tests/test-stats-help.out)0
-rw-r--r--src/equery/tests/test-uses-help.out (renamed from trunk/src/equery/tests/test-uses-help.out)0
-rwxr-xr-xsrc/equery/tests/test-uses.sh (renamed from trunk/src/equery/tests/test-uses.sh)0
-rw-r--r--src/equery/tests/test-which-help.out (renamed from trunk/src/equery/tests/test-which-help.out)0
-rwxr-xr-xsrc/equery/tests/test-which.sh (renamed from trunk/src/equery/tests/test-which.sh)0
-rw-r--r--src/eread/AUTHORS (renamed from trunk/src/eread/AUTHORS)0
-rw-r--r--src/eread/Makefile (renamed from trunk/src/eread/Makefile)0
-rwxr-xr-xsrc/eread/eread94
-rw-r--r--src/eread/eread.112
-rw-r--r--src/euse/AUTHORS (renamed from trunk/src/euse/AUTHORS)0
-rw-r--r--src/euse/ChangeLog (renamed from trunk/src/euse/ChangeLog)0
-rw-r--r--src/euse/Makefile (renamed from trunk/src/euse/Makefile)0
-rwxr-xr-xsrc/euse/euse (renamed from trunk/src/euse/euse)0
-rw-r--r--src/euse/euse.1102
-rw-r--r--src/gentoolkit/AUTHORS (renamed from trunk/src/gentoolkit/AUTHORS)0
-rw-r--r--src/gentoolkit/Makefile (renamed from trunk/src/gentoolkit/Makefile)0
-rw-r--r--src/gentoolkit/README (renamed from trunk/src/gentoolkit/README)0
-rw-r--r--src/gentoolkit/TODO (renamed from trunk/src/distfiles-clean/TODO)0
-rw-r--r--src/gentoolkit/__init__.py (renamed from trunk/src/gentoolkit/__init__.py)0
-rw-r--r--src/gentoolkit/errors.py (renamed from trunk/src/gentoolkit/errors.py)0
-rw-r--r--src/gentoolkit/helpers.py (renamed from trunk/src/gentoolkit/helpers.py)0
-rw-r--r--src/gentoolkit/package.py (renamed from trunk/src/gentoolkit/package.py)0
-rw-r--r--src/gentoolkit/pprinter.py116
-rw-r--r--src/glsa-check/Makefile (renamed from trunk/src/glsa-check/Makefile)0
-rwxr-xr-xsrc/glsa-check/glsa-check (renamed from trunk/src/glsa-check/glsa-check)0
-rw-r--r--src/glsa-check/glsa-check.1 (renamed from trunk/src/glsa-check/glsa-check.1)0
-rw-r--r--src/glsa-check/glsa.py (renamed from trunk/src/glsa-check/glsa.py)0
-rw-r--r--src/revdep-rebuild/99revdep-rebuild21
-rw-r--r--src/revdep-rebuild/AUTHORS (renamed from trunk/src/revdep-rebuild/AUTHORS)0
-rw-r--r--src/revdep-rebuild/ChangeLog (renamed from trunk/src/revdep-rebuild/ChangeLog)0
-rw-r--r--src/revdep-rebuild/Makefile (renamed from trunk/src/revdep-rebuild/Makefile)0
-rw-r--r--src/revdep-rebuild/README (renamed from trunk/src/revdep-rebuild/README)0
-rw-r--r--src/revdep-rebuild/TODO (renamed from trunk/src/revdep-rebuild/TODO)0
-rwxr-xr-xsrc/revdep-rebuild/find_pkgs.py (renamed from trunk/src/revdep-rebuild/find_pkgs.py)0
-rwxr-xr-xsrc/revdep-rebuild/revdep-rebuild (renamed from trunk/src/revdep-rebuild/revdep-rebuild)0
-rwxr-xr-xsrc/revdep-rebuild/revdep-rebuild-old (renamed from trunk/src/revdep-rebuild/revdep-rebuild-old)0
-rwxr-xr-xsrc/revdep-rebuild/revdep-rebuild-sh (renamed from trunk/src/revdep-rebuild/revdep-rebuild-sh)0
-rw-r--r--src/revdep-rebuild/revdep-rebuild.1 (renamed from trunk/src/revdep-rebuild/revdep-rebuild.1)0
-rw-r--r--trunk/AUTHORS6
-rw-r--r--trunk/Makefile88
-rw-r--r--trunk/README.Developer65
-rw-r--r--trunk/makedefs.mak20
-rwxr-xr-xtrunk/release.sh89
-rw-r--r--trunk/src/change/AUTHORS5
-rw-r--r--trunk/src/change/ChangeLog7
-rw-r--r--trunk/src/change/README20
-rw-r--r--trunk/src/change/change343
-rw-r--r--trunk/src/change/change.10
-rw-r--r--trunk/src/dep-clean/AUTHORS9
-rw-r--r--trunk/src/dep-clean/ChangeLog13
-rw-r--r--trunk/src/dep-clean/README4
-rw-r--r--trunk/src/dep-clean/dep-clean164
-rw-r--r--trunk/src/dep-clean/dep-clean.1194
-rw-r--r--trunk/src/dev-scripts/README2
-rwxr-xr-xtrunk/src/dev-scripts/included_headers.sh159
-rwxr-xr-xtrunk/src/dev-scripts/linking_libs.sh204
-rw-r--r--trunk/src/distfiles-clean/AUTHORS6
-rw-r--r--trunk/src/distfiles-clean/ChangeLog2
-rw-r--r--trunk/src/distfiles-clean/distfiles-clean78
-rw-r--r--trunk/src/ebump/AUTHORS5
-rw-r--r--trunk/src/ebump/ChangeLog8
-rw-r--r--trunk/src/ebump/Makefile20
-rw-r--r--trunk/src/ebump/README18
-rw-r--r--trunk/src/ebump/TODO0
-rwxr-xr-xtrunk/src/ebump/ebump356
-rw-r--r--trunk/src/ebump/ebump.1110
-rw-r--r--trunk/src/echangelog/AUTHORS1
-rw-r--r--trunk/src/echangelog/ChangeLog84
-rw-r--r--trunk/src/echangelog/Makefile26
-rw-r--r--trunk/src/echangelog/README11
-rw-r--r--trunk/src/echangelog/TODO0
-rwxr-xr-xtrunk/src/echangelog/echangelog711
-rw-r--r--trunk/src/echangelog/echangelog.1270
-rw-r--r--trunk/src/echangelog/test/TEST.pm26
-rw-r--r--trunk/src/echangelog/test/templates/test.patch6
-rw-r--r--trunk/src/echangelog/test/templates/vcstest-0.0.1.ebuild16
-rwxr-xr-xtrunk/src/echangelog/test/test.sh178
-rw-r--r--trunk/src/ego/AUTHOR1
-rw-r--r--trunk/src/ego/AUTHORS1
-rw-r--r--trunk/src/ego/ChangeLog2
-rw-r--r--trunk/src/ego/Makefile18
-rw-r--r--trunk/src/ego/README2
-rw-r--r--trunk/src/ego/TODO0
-rw-r--r--trunk/src/ego/ego86
-rw-r--r--trunk/src/ekeyword/AUTHORS1
-rw-r--r--trunk/src/ekeyword/ChangeLog46
-rw-r--r--trunk/src/ekeyword/Makefile24
-rw-r--r--trunk/src/ekeyword/README20
-rw-r--r--trunk/src/ekeyword/TODO0
-rwxr-xr-xtrunk/src/ekeyword/ekeyword131
-rw-r--r--trunk/src/ekeyword/ekeyword.pod74
-rwxr-xr-xtrunk/src/ekeyword2/ekeyword296
-rw-r--r--trunk/src/epkgmove/AUTHORS2
-rw-r--r--trunk/src/epkgmove/ChangeLog20
-rw-r--r--trunk/src/epkgmove/Makefile20
-rw-r--r--trunk/src/epkgmove/README16
-rw-r--r--trunk/src/epkgmove/TODO0
-rw-r--r--trunk/src/epkgmove/epkgmove895
-rw-r--r--trunk/src/etc-update/AUTHORS0
-rw-r--r--trunk/src/etc-update/ChangeLog0
-rw-r--r--trunk/src/etc-update/Makefile20
-rw-r--r--trunk/src/etc-update/README0
-rwxr-xr-xtrunk/src/etc-update/etc-update165
-rw-r--r--trunk/src/etc-update/etc-update.112
-rw-r--r--trunk/src/etcat/AUTHORS5
-rw-r--r--trunk/src/etcat/ChangeLog36
-rw-r--r--trunk/src/etcat/Makefile18
-rw-r--r--trunk/src/etcat/README2
-rw-r--r--trunk/src/etcat/TODO0
-rwxr-xr-xtrunk/src/etcat/etcat688
-rw-r--r--trunk/src/etcat/etcat.179
-rw-r--r--trunk/src/eviewcvs/AUTHORS1
-rw-r--r--trunk/src/eviewcvs/Makefile22
-rw-r--r--trunk/src/eviewcvs/README11
-rwxr-xr-xtrunk/src/eviewcvs/eviewcvs95
-rw-r--r--trunk/src/eviewcvs/eviewcvs.pod48
-rw-r--r--trunk/src/genpkgindex/Makefile18
-rw-r--r--trunk/src/genpkgindex/genpkgindex336
-rw-r--r--trunk/src/gensync/AUTHORS5
-rw-r--r--trunk/src/gensync/ChangeLog12
-rw-r--r--trunk/src/gensync/Makefile24
-rw-r--r--trunk/src/gensync/README16
-rw-r--r--trunk/src/gensync/TODO4
-rw-r--r--trunk/src/gensync/bmg-gnome-current.syncsource18
-rw-r--r--trunk/src/gensync/bmg-main.syncsource18
-rwxr-xr-xtrunk/src/gensync/gensync226
-rw-r--r--trunk/src/gensync/gensync.175
-rw-r--r--trunk/src/gensync/gensync.conf8
-rw-r--r--trunk/src/gentoolkit/TODO0
-rw-r--r--trunk/src/lintool/AUTHORS1
-rw-r--r--trunk/src/lintool/COPYING340
-rw-r--r--trunk/src/lintool/ChangeLog71
-rw-r--r--trunk/src/lintool/NEWS0
-rw-r--r--trunk/src/lintool/README23
-rw-r--r--trunk/src/lintool/lintool.141
-rwxr-xr-xtrunk/src/lintool/lintool.py320
-rw-r--r--trunk/src/lintool/lintool/__init__.py3
-rw-r--r--trunk/src/lintool/lintool/changelog.py105
-rw-r--r--trunk/src/lintool/lintool/digest.py28
-rw-r--r--trunk/src/lintool/lintool/ebuild.py349
-rw-r--r--trunk/src/lintool/lintool/test.py30
-rw-r--r--trunk/src/moo/AUTHORS1
-rw-r--r--trunk/src/moo/README0
-rw-r--r--trunk/src/moo/TODO0
-rwxr-xr-xtrunk/src/moo/moo244
-rw-r--r--trunk/src/moo/moo.112
-rw-r--r--trunk/src/old-scripts/Makefile32
-rw-r--r--trunk/src/old-scripts/dep-clean272
-rw-r--r--trunk/src/old-scripts/dep-clean.1190
-rwxr-xr-xtrunk/src/old-scripts/ewhich44
-rw-r--r--trunk/src/old-scripts/ewhich.124
-rw-r--r--trunk/src/old-scripts/mkebuild216
-rw-r--r--trunk/src/old-scripts/mkebuild.120
-rw-r--r--trunk/src/old-scripts/pkg-clean107
-rw-r--r--trunk/src/old-scripts/pkg-clean.120
-rw-r--r--trunk/src/old-scripts/pkg-size63
-rw-r--r--trunk/src/old-scripts/pkg-size.111
-rw-r--r--trunk/src/pkg-clean/AUTHORS5
-rw-r--r--trunk/src/pkg-clean/ChangeLog0
-rw-r--r--trunk/src/pkg-clean/README0
-rw-r--r--trunk/src/pkg-clean/pkg-clean99
-rw-r--r--trunk/src/pkg-clean/pkg-clean.120
-rw-r--r--trunk/src/pkg-size/pkg-size66
-rw-r--r--trunk/src/qpkg/AUTHORS0
-rw-r--r--trunk/src/qpkg/ChangeLog5
-rw-r--r--trunk/src/qpkg/Makefile19
-rw-r--r--trunk/src/qpkg/README0
-rw-r--r--trunk/src/qpkg/TODO0
-rw-r--r--trunk/src/qpkg/qpkg581
-rw-r--r--trunk/src/qpkg/qpkg.1112
-rw-r--r--trunk/src/qpkg/qpkg.sh520
-rw-r--r--trunk/src/useflag/AUTHORS0
-rw-r--r--trunk/src/useflag/ChangeLog0
-rw-r--r--trunk/src/useflag/README0
-rw-r--r--trunk/src/useflag/useflag610
-rw-r--r--trunk/src/useflag/useflag.169
266 files changed, 9806 insertions, 11414 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..fa210a6
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,28 @@
+* gentoolkit
+ Original author: Karl Trygve Kalleberg <karltk@gentoo.org>
+ Further additions: Douglas Anderson <dja@gendja.com>
+ Current maintainer: Paul Varner <fuzzyray@gentoo.org>
+
+* eclean
+ Original author: Thomas de Grenier de Latour (tgl) <degrenier@easyconnect.fr>
+
+* epkginfo
+ Author: Ned Ludd <solar@gentoo.org>
+ earch: Eldad Zack <eldad@gentoo.org>
+ metadata: Olinger <EvvL AT RustedHalo DOT net>
+
+* equery
+ Original author: Karl Trygve Kalleberg <karltk@gentoo.org>
+ Modular redesign: Douglas Anderson <dja@gendja.com>
+
+* eread
+ Original author: Donnie Berkholz <dberkholz@gentoo.org>
+ Updated by: Uwe Klosa <uwe.klosa@gmail.com>
+
+* euse
+ Original perl version: Arun Bhanu <codebear@gentoo.org>
+ New bash version: Marius Mauch <genone@gentoo.org>
+
+* revdep-rebuild
+ Original author: Stanislav Brabec
+ Rewrite author: Michael A. Smith
diff --git a/trunk/COPYING b/COPYING
index 60549be..60549be 100644
--- a/trunk/COPYING
+++ b/COPYING
diff --git a/trunk/ChangeLog b/ChangeLog
index 6597880..6597880 100644
--- a/trunk/ChangeLog
+++ b/ChangeLog
diff --git a/trunk/NEWS b/NEWS
index e69de29..e69de29 100644
--- a/trunk/NEWS
+++ b/NEWS
diff --git a/trunk/README b/README
index 5c785d3..5c785d3 100644
--- a/trunk/README
+++ b/README
diff --git a/THANKS b/THANKS
new file mode 100644
index 0000000..d958556
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,8 @@
+* eclean
+ The starting point ideas were found here:
+ http://forums.gentoo.org/viewtopic.php?t=3011
+
+ Thanks to eswanson and far for their contributions, and to wolf31o2 for his
+ support. Thanks also to karltk, some of this code was at some point inspired
+ by his "equery" tool. And thanks to people who had a look on bug #33877:
+ Benjamin Braatz, fuzzyray, genone, etc.
diff --git a/trunk/TODO b/TODO
index d39ea85..d39ea85 100644
--- a/trunk/TODO
+++ b/TODO
diff --git a/bin/eclean b/bin/eclean
new file mode 100644
index 0000000..8b473f9
--- /dev/null
+++ b/bin/eclean
@@ -0,0 +1,802 @@
+#!/usr/bin/env python
+# Copyright 2003-2005 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+
+###############################################################################
+# Meta:
+__author__ = "Thomas de Grenier de Latour (tgl)"
+__email__ = "degrenier@easyconnect.fr"
+__version__ = open('/etc/gentoolkit-version').read().strip()
+__productname__ = "eclean"
+__description__ = "A cleaning tool for Gentoo distfiles and binaries."
+
+
+###############################################################################
+# Python imports:
+import sys
+import os, stat
+import re
+import time
+import getopt
+import fpformat
+import signal
+
+import portage
+from portage.output import *
+
+listdir = portage.listdir
+
+###############################################################################
+# Misc. shortcuts to some portage stuff:
+port_settings = portage.settings
+distdir = port_settings["DISTDIR"]
+pkgdir = port_settings["PKGDIR"]
+
+
+###############################################################################
+# printVersion:
+def printVersion():
+ print "%s (%s) - %s" \
+ % (__productname__, __version__, __description__)
+ print
+ print "Author: %s <%s>" % (__author__,__email__)
+ print "Copyright 2003-2009 Gentoo Foundation"
+ print "Distributed under the terms of the GNU General Public License v2"
+
+
+###############################################################################
+# printUsage: print help message. May also print partial help to stderr if an
+# error from {'options','actions'} is specified.
+def printUsage(error=None,help=None):
+ out = sys.stdout
+ if error: out = sys.stderr
+ if not error in ('actions', 'global-options', \
+ 'packages-options', 'distfiles-options', \
+ 'merged-packages-options', 'merged-distfiles-options', \
+ 'time', 'size'):
+ error = None
+ if not error and not help: help = 'all'
+ if error == 'time':
+ eerror("Wrong time specification")
+ print >>out, "Time specification should be an integer followed by a"+ \
+ " single letter unit."
+ print >>out, "Available units are: y (years), m (months), w (weeks), "+ \
+ "d (days) and h (hours)."
+ print >>out, "For instance: \"1y\" is \"one year\", \"2w\" is \"two"+ \
+ " weeks\", etc. "
+ return
+ if error == 'size':
+ eerror("Wrong size specification")
+ print >>out, "Size specification should be an integer followed by a"+ \
+ " single letter unit."
+ print >>out, "Available units are: G, M, K and B."
+ print >>out, "For instance: \"10M\" is \"ten megabytes\", \"200K\" "+ \
+ "is \"two hundreds kilobytes\", etc."
+ return
+ if error in ('global-options', 'packages-options', 'distfiles-options', \
+ 'merged-packages-options', 'merged-distfiles-options',):
+ eerror("Wrong option on command line.")
+ print >>out
+ elif error == 'actions':
+ eerror("Wrong or missing action name on command line.")
+ print >>out
+ print >>out, white("Usage:")
+ if error in ('actions','global-options', 'packages-options', \
+ 'distfiles-options') or help == 'all':
+ print >>out, " "+turquoise(__productname__), \
+ yellow("[global-option] ..."), \
+ green("<action>"), \
+ yellow("[action-option] ...")
+ if error == 'merged-distfiles-options' or help in ('all','distfiles'):
+ print >>out, " "+turquoise(__productname__+'-dist'), \
+ yellow("[global-option, distfiles-option] ...")
+ if error == 'merged-packages-options' or help in ('all','packages'):
+ print >>out, " "+turquoise(__productname__+'-pkg'), \
+ yellow("[global-option, packages-option] ...")
+ if error in ('global-options', 'actions'):
+ print >>out, " "+turquoise(__productname__), \
+ yellow("[--help, --version]")
+ if help == 'all':
+ print >>out, " "+turquoise(__productname__+"(-dist,-pkg)"), \
+ yellow("[--help, --version]")
+ if error == 'merged-packages-options' or help == 'packages':
+ print >>out, " "+turquoise(__productname__+'-pkg'), \
+ yellow("[--help, --version]")
+ if error == 'merged-distfiles-options' or help == 'distfiles':
+ print >>out, " "+turquoise(__productname__+'-dist'), \
+ yellow("[--help, --version]")
+ print >>out
+ if error in ('global-options', 'merged-packages-options', \
+ 'merged-distfiles-options') or help:
+ print >>out, "Available global", yellow("options")+":"
+ print >>out, yellow(" -C, --nocolor")+ \
+ " - turn off colors on output"
+ print >>out, yellow(" -d, --destructive")+ \
+ " - only keep the minimum for a reinstallation"
+ print >>out, yellow(" -e, --exclude-file=<path>")+ \
+ " - path to the exclusion file"
+ print >>out, yellow(" -i, --interactive")+ \
+ " - ask confirmation before deletions"
+ print >>out, yellow(" -n, --package-names")+ \
+ " - protect all versions (when --destructive)"
+ print >>out, yellow(" -p, --pretend")+ \
+ " - only display what would be cleaned"
+ print >>out, yellow(" -q, --quiet")+ \
+ " - be as quiet as possible"
+ print >>out, yellow(" -t, --time-limit=<time>")+ \
+ " - don't delete files modified since "+yellow("<time>")
+ print >>out, " "+yellow("<time>"), "is a duration: \"1y\" is"+ \
+ " \"one year\", \"2w\" is \"two weeks\", etc. "
+ print >>out, " "+"Units are: y (years), m (months), w (weeks), "+ \
+ "d (days) and h (hours)."
+ print >>out, yellow(" -h, --help")+ \
+ " - display the help screen"
+ print >>out, yellow(" -V, --version")+ \
+ " - display version info"
+ print >>out
+ if error == 'actions' or help == 'all':
+ print >>out, "Available", green("actions")+":"
+ print >>out, green(" packages")+ \
+ " - clean outdated binary packages from:"
+ print >>out, " ",teal(pkgdir)
+ print >>out, green(" distfiles")+ \
+ " - clean outdated packages sources files from:"
+ print >>out, " ",teal(distdir)
+ print >>out
+ if error in ('packages-options','merged-packages-options') \
+ or help in ('all','packages'):
+ print >>out, "Available", yellow("options"),"for the", \
+ green("packages"),"action:"
+ print >>out, yellow(" NONE :)")
+ print >>out
+ if error in ('distfiles-options', 'merged-distfiles-options') \
+ or help in ('all','distfiles'):
+ print >>out, "Available", yellow("options"),"for the", \
+ green("distfiles"),"action:"
+ print >>out, yellow(" -f, --fetch-restricted")+ \
+ " - protect fetch-restricted files (when --destructive)"
+ print >>out, yellow(" -s, --size-limit=<size>")+ \
+ " - don't delete distfiles bigger than "+yellow("<size>")
+ print >>out, " "+yellow("<size>"), "is a size specification: "+ \
+ "\"10M\" is \"ten megabytes\", \"200K\" is"
+ print >>out, " "+"\"two hundreds kilobytes\", etc. Units are: "+ \
+ "G, M, K and B."
+ print >>out
+ print >>out, "More detailed instruction can be found in", \
+ turquoise("`man %s`" % __productname__)
+
+
+###############################################################################
+# einfo: display an info message depending on a color mode
+def einfo(message="", nocolor=False):
+ if not nocolor: prefix = " "+green('*')
+ else: prefix = ">>>"
+ print prefix,message
+
+
+###############################################################################
+# eerror: display an error depending on a color mode
+def eerror(message="", nocolor=False):
+ if not nocolor: prefix = " "+red('*')
+ else: prefix = "!!!"
+ print >>sys.stderr,prefix,message
+
+
+###############################################################################
+# eprompt: display a user question depending on a color mode.
+def eprompt(message, nocolor=False):
+ if not nocolor: prefix = " "+red('>')+" "
+ else: prefix = "??? "
+ sys.stdout.write(prefix+message)
+ sys.stdout.flush()
+
+
+###############################################################################
+# prettySize: integer -> byte/kilo/mega/giga converter. Optionnally justify the
+# result. Output is a string.
+def prettySize(size,justify=False):
+ units = [" G"," M"," K"," B"]
+ approx = 0
+ while len(units) and size >= 1000:
+ approx = 1
+ size = size / 1024.
+ units.pop()
+ sizestr = fpformat.fix(size,approx)+units[-1]
+ if justify:
+ sizestr = " " + blue("[ ") + " "*(7-len(sizestr)) \
+ + green(sizestr) + blue(" ]")
+ return sizestr
+
+
+###############################################################################
+# yesNoAllPrompt: print a prompt until user answer in yes/no/all. Return a
+# boolean for answer, and also may affect the 'accept_all' option.
+# Note: i gave up with getch-like functions, to much bugs in case of escape
+# sequences. Back to raw_input.
+def yesNoAllPrompt(myoptions,message="Do you want to proceed?"):
+ user_string="xxx"
+ while not user_string.lower() in ["","y","n","a","yes","no","all"]:
+ eprompt(message+" [Y/n/a]: ", myoptions['nocolor'])
+ user_string = raw_input()
+ if user_string.lower() in ["a","all"]:
+ myoptions['accept_all'] = True
+ myanswer = user_string.lower() in ["","y","a","yes","all"]
+ return myanswer
+
+
+###############################################################################
+# ParseArgsException: for parseArgs() -> main() communication
+class ParseArgsException(Exception):
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return repr(self.value)
+
+
+###############################################################################
+# parseSize: convert a file size "Xu" ("X" is an integer, and "u" in [G,M,K,B])
+# into an integer (file size in Bytes). Raises ParseArgsException('size') in
+# case of failure.
+def parseSize(size):
+ myunits = { \
+ 'G': (1024**3), \
+ 'M': (1024**2), \
+ 'K': 1024, \
+ 'B': 1 \
+ }
+ try:
+ mymatch = re.match(r"^(?P<value>\d+)(?P<unit>[GMKBgmkb])?$",size)
+ mysize = int(mymatch.group('value'))
+ if mymatch.group('unit'):
+ mysize *= myunits[mymatch.group('unit').capitalize()]
+ except:
+ raise ParseArgsException('size')
+ return mysize
+
+
+###############################################################################
+# parseTime: convert a duration "Xu" ("X" is an int, and "u" a time unit in
+# [Y,M,W,D,H]) into an integer which is a past EPOCH date.
+# Raises ParseArgsException('time') in case of failure.
+# (yep, big approximations inside... who cares?)
+def parseTime(timespec):
+ myunits = {'H' : (60 * 60)}
+ myunits['D'] = myunits['H'] * 24
+ myunits['W'] = myunits['D'] * 7
+ myunits['M'] = myunits['D'] * 30
+ myunits['Y'] = myunits['D'] * 365
+ try:
+ # parse the time specification
+ mymatch = re.match(r"^(?P<value>\d+)(?P<unit>[YMWDHymwdh])?$",timespec)
+ myvalue = int(mymatch.group('value'))
+ if not mymatch.group('unit'): myunit = 'D'
+ else: myunit = mymatch.group('unit').capitalize()
+ except: raise ParseArgsException('time')
+ # calculate the limit EPOCH date
+ mytime = time.time() - (myvalue * myunits[myunit])
+ return mytime
+
+
+###############################################################################
+# parseCmdLine: parse the command line arguments. Raise exceptions on errors or
+# non-action modes (help/version). Returns an action, and affect the options
+# dict.
+def parseArgs(myoptions={}):
+
+ # local function for interpreting command line options
+ # and setting myoptions accordingly
+ def optionSwitch(myoption,opts,action=None):
+ return_code = True
+ for o, a in opts:
+ if o in ("-h", "--help"):
+ if action: raise ParseArgsException('help-'+action)
+ else: raise ParseArgsException('help')
+ elif o in ("-V", "--version"):
+ raise ParseArgsException('version')
+ elif o in ("-C", "--nocolor"):
+ myoptions['nocolor'] = True
+ nocolor()
+ elif o in ("-d", "--destructive"):
+ myoptions['destructive'] = True
+ elif o in ("-i", "--interactive") and not myoptions['pretend']:
+ myoptions['interactive'] = True
+ elif o in ("-p", "--pretend"):
+ myoptions['pretend'] = True
+ myoptions['interactive'] = False
+ elif o in ("-q", "--quiet"):
+ myoptions['quiet'] = True
+ elif o in ("-t", "--time-limit"):
+ myoptions['time-limit'] = parseTime(a)
+ elif o in ("-e", "--exclude-file"):
+ myoptions['exclude-file'] = a
+ elif o in ("-n", "--package-names"):
+ myoptions['package-names'] = True
+ elif o in ("-f", "--fetch-restricted"):
+ myoptions['fetch-restricted'] = True
+ elif o in ("-s", "--size-limit"):
+ myoptions['size-limit'] = parseSize(a)
+ else: return_code = False
+ # sanity check of --destructive only options:
+ for myopt in ('fetch-restricted', 'package-names'):
+ if (not myoptions['destructive']) and myoptions[myopt]:
+ if not myoptions['quiet']:
+ eerror("--%s only makes sense in --destructive mode." \
+ % myopt, myoptions['nocolor'])
+ myoptions[myopt] = False
+ return return_code
+
+ # here are the different allowed command line options (getopt args)
+ getopt_options = {'short':{}, 'long':{}}
+ getopt_options['short']['global'] = "Cdipqe:t:nhV"
+ getopt_options['long']['global'] = ["nocolor", "destructive", \
+ "interactive", "pretend", "quiet", "exclude-file=", "time-limit=", \
+ "package-names", "help", "version"]
+ getopt_options['short']['distfiles'] = "fs:"
+ getopt_options['long']['distfiles'] = ["fetch-restricted", "size-limit="]
+ getopt_options['short']['packages'] = ""
+ getopt_options['long']['packages'] = [""]
+ # set default options, except 'nocolor', which is set in main()
+ myoptions['interactive'] = False
+ myoptions['pretend'] = False
+ myoptions['quiet'] = False
+ myoptions['accept_all'] = False
+ myoptions['destructive'] = False
+ myoptions['time-limit'] = 0
+ myoptions['package-names'] = False
+ myoptions['fetch-restricted'] = False
+ myoptions['size-limit'] = 0
+ # if called by a well-named symlink, set the acction accordingly:
+ myaction = None
+ if os.path.basename(sys.argv[0]) in \
+ (__productname__+'-pkg', __productname__+'-packages'):
+ myaction = 'packages'
+ elif os.path.basename(sys.argv[0]) in \
+ (__productname__+'-dist', __productname__+'-distfiles'):
+ myaction = 'distfiles'
+ # prepare for the first getopt
+ if myaction:
+ short_opts = getopt_options['short']['global'] \
+ + getopt_options['short'][myaction]
+ long_opts = getopt_options['long']['global'] \
+ + getopt_options['long'][myaction]
+ opts_mode = 'merged-'+myaction
+ else:
+ short_opts = getopt_options['short']['global']
+ long_opts = getopt_options['long']['global']
+ opts_mode = 'global'
+ # apply getopts to command line, show partial help on failure
+ try: opts, args = getopt.getopt(sys.argv[1:], short_opts, long_opts)
+ except: raise ParseArgsException(opts_mode+'-options')
+ # set myoptions accordingly
+ optionSwitch(myoptions,opts,action=myaction)
+ # if action was already set, there should be no more args
+ if myaction and len(args): raise ParseArgsException(opts_mode+'-options')
+ # if action was set, there is nothing left to do
+ if myaction: return myaction
+ # So, we are in "eclean --foo action --bar" mode. Parse remaining args...
+ # Only two actions are allowed: 'packages' and 'distfiles'.
+ if not len(args) or not args[0] in ('packages','distfiles'):
+ raise ParseArgsException('actions')
+ myaction = args.pop(0)
+ # parse the action specific options
+ try: opts, args = getopt.getopt(args, \
+ getopt_options['short'][myaction], \
+ getopt_options['long'][myaction])
+ except: raise ParseArgsException(myaction+'-options')
+ # set myoptions again, for action-specific options
+ optionSwitch(myoptions,opts,action=myaction)
+ # any remaning args? Then die!
+ if len(args): raise ParseArgsException(myaction+'-options')
+ # returns the action. Options dictionary is modified by side-effect.
+ return myaction
+
+###############################################################################
+# isValidCP: check wether a string is a valid cat/pkg-name
+# This is for 2.0.51 vs. CVS HEAD compatibility, i've not found any function
+# for that which would exists in both. Weird...
+def isValidCP(cp):
+ if not '/' in cp: return False
+ try: portage.cpv_getkey(cp+"-0")
+ except: return False
+ else: return True
+
+
+###############################################################################
+# ParseExcludeFileException: for parseExcludeFile() -> main() communication
+class ParseExcludeFileException(Exception):
+ def __init__(self, value):
+ self.value = value
+ def __str__(self):
+ return repr(self.value)
+
+
+###############################################################################
+# parseExcludeFile: parses an exclusion file, returns an exclusion dictionnary
+# Raises ParseExcludeFileException in case of fatal error.
+def parseExcludeFile(filepath):
+ excl_dict = { \
+ 'categories':{}, \
+ 'packages':{}, \
+ 'anti-packages':{}, \
+ 'garbage':{} }
+ try: file = open(filepath,"r")
+ except IOError:
+ raise ParseExcludeFileException("Could not open exclusion file.")
+ filecontents = file.readlines()
+ file.close()
+ cat_re = re.compile('^(?P<cat>[a-zA-Z0-9]+-[a-zA-Z0-9]+)(/\*)?$')
+ cp_re = re.compile('^(?P<cp>[-a-zA-Z0-9_]+/[-a-zA-Z0-9_]+)$')
+ for line in filecontents:
+ line = line.strip()
+ if not len(line): continue
+ if line[0] == '#': continue
+ try: mycat = cat_re.match(line).group('cat')
+ except: pass
+ else:
+ if not mycat in portage.settings.categories:
+ raise ParseExcludeFileException("Invalid category: "+mycat)
+ excl_dict['categories'][mycat] = None
+ continue
+ dict_key = 'packages'
+ if line[0] == '!':
+ dict_key = 'anti-packages'
+ line = line[1:]
+ try:
+ mycp = cp_re.match(line).group('cp')
+ if isValidCP(mycp):
+ excl_dict[dict_key][mycp] = None
+ continue
+ else: raise ParseExcludeFileException("Invalid cat/pkg: "+mycp)
+ except: pass
+ #raise ParseExcludeFileException("Invalid line: "+line)
+ try:
+ excl_dict['garbage'][line] = re.compile(line)
+ except:
+ try:
+ excl_dict['garbage'][line] = re.compile(re.escape(line))
+ except:
+ raise ParseExcludeFileException("Invalid file name/regular expression: "+line)
+ return excl_dict
+
+
+###############################################################################
+# exclDictExpand: returns a dictionary of all CP from porttree which match
+# the exclusion dictionary
+def exclDictExpand(excl_dict):
+ mydict = {}
+ if 'categories' in excl_dict:
+ # XXX: i smell an access to something which is really out of API...
+ for mytree in portage.portdb.porttrees:
+ for mycat in excl_dict['categories']:
+ for mypkg in listdir(os.path.join(mytree,mycat),ignorecvs=1):
+ mydict[mycat+'/'+mypkg] = None
+ if 'packages' in excl_dict:
+ for mycp in excl_dict['packages']:
+ mydict[mycp] = None
+ if 'anti-packages' in excl_dict:
+ for mycp in excl_dict['anti-packages']:
+ if mycp in mydict:
+ del mydict[mycp]
+ return mydict
+
+
+###############################################################################
+# exclDictMatch: checks whether a CP matches the exclusion rules
+def exclDictMatch(excl_dict,pkg):
+ if 'anti-packages' in excl_dict \
+ and pkg in excl_dict['anti-packages']:
+ return False
+ if 'packages' in excl_dict \
+ and pkg in excl_dict['packages']:
+ return True
+ mycat = pkg.split('/')[0]
+ if 'categories' in excl_dict \
+ and mycat in excl_dict['categories']:
+ return True
+ return False
+
+
+###############################################################################
+# findDistfiles: find all obsolete distfiles.
+# XXX: what about cvs ebuilds? i should install some to see where it goes...
+def findDistfiles( \
+ exclude_dict={}, \
+ destructive=False,\
+ fetch_restricted=False, \
+ package_names=False, \
+ time_limit=0, \
+ size_limit=0):
+ # this regexp extracts files names from SRC_URI. It is not very precise,
+ # but we don't care (may return empty strings, etc.), since it is fast.
+ file_regexp = re.compile('([a-zA-Z0-9_,\.\-\+\~]*)[\s\)]')
+ clean_dict = {}
+ keep = []
+ pkg_dict = {}
+
+ # create a big CPV->SRC_URI dict of packages whose distfiles should be kept
+ if (not destructive) or fetch_restricted:
+ # list all CPV from portree (yeah, that takes time...)
+ for package in portage.portdb.cp_all():
+ for my_cpv in portage.portdb.cp_list(package):
+ # get SRC_URI and RESTRICT from aux_get
+ try: (src_uri,restrict) = \
+ portage.portdb.aux_get(my_cpv,["SRC_URI","RESTRICT"])
+ except KeyError: continue
+ # keep either all or fetch-restricted only
+ if (not destructive) or ('fetch' in restrict):
+ pkg_dict[my_cpv] = src_uri
+ if destructive:
+ if not package_names:
+ # list all CPV from vartree
+ pkg_list = portage.db[portage.root]["vartree"].dbapi.cpv_all()
+ else:
+ # list all CPV from portree for CP in vartree
+ pkg_list = []
+ for package in portage.db[portage.root]["vartree"].dbapi.cp_all():
+ pkg_list += portage.portdb.cp_list(package)
+ for my_cp in exclDictExpand(exclude_dict):
+ # add packages from the exclude file
+ pkg_list += portage.portdb.cp_list(my_cp)
+ for my_cpv in pkg_list:
+ # skip non-existing CPV (avoids ugly aux_get messages)
+ if not portage.portdb.cpv_exists(my_cpv): continue
+ # get SRC_URI from aux_get
+ try: pkg_dict[my_cpv] = \
+ portage.portdb.aux_get(my_cpv,["SRC_URI"])[0]
+ except KeyError: continue
+ del pkg_list
+
+ # create a dictionary of files which should be deleted
+ for file in os.listdir(distdir):
+ filepath = os.path.join(distdir, file)
+ try: file_stat = os.stat(filepath)
+ except: continue
+ if not stat.S_ISREG(file_stat[stat.ST_MODE]): continue
+ if size_limit and (file_stat[stat.ST_SIZE] >= size_limit):
+ continue
+ if time_limit and (file_stat[stat.ST_MTIME] >= time_limit):
+ continue
+ if 'garbage' in exclude_dict:
+ # Try to match file name directly
+ if file in exclude_dict['garbage']:
+ file_match = True
+ # See if file matches via regular expression matching
+ else:
+ file_match = False
+ for file_entry in exclude_dict['garbage']:
+ if exclude_dict['garbage'][file_entry].match(file):
+ file_match = True
+ break
+
+ if file_match:
+ continue
+ # this is a candidate for cleaning
+ clean_dict[file]=[filepath]
+ # remove files owned by some protected packages
+ for my_cpv in pkg_dict:
+ for file in file_regexp.findall(pkg_dict[my_cpv]+"\n"):
+ if file in clean_dict:
+ del clean_dict[file]
+ # no need to waste IO time if there is nothing left to clean
+ if not len(clean_dict): return clean_dict
+ return clean_dict
+
+
+###############################################################################
+# findPackages: find all obsolete binary packages.
+# XXX: packages are found only by symlinks. Maybe i should also return .tbz2
+# files from All/ that have no corresponding symlinks.
+def findPackages( \
+ exclude_dict={}, \
+ destructive=False, \
+ time_limit=0, \
+ package_names=False):
+ clean_dict = {}
+ # create a full package dictionnary
+ for root, dirs, files in os.walk(pkgdir):
+ if root[-3:] == 'All': continue
+ for file in files:
+ if not file[-5:] == ".tbz2":
+ # ignore non-tbz2 files
+ continue
+ path = os.path.join(root, file)
+ category = os.path.split(root)[-1]
+ cpv = category+"/"+file[:-5]
+ mystat = os.lstat(path)
+ if time_limit and (mystat[stat.ST_MTIME] >= time_limit):
+ # time-limit exclusion
+ continue
+ # dict is cpv->[files] (2 files in general, because of symlink)
+ clean_dict[cpv] = [path]
+ #if os.path.islink(path):
+ if stat.S_ISLNK(mystat[stat.ST_MODE]):
+ clean_dict[cpv].append(os.path.realpath(path))
+ # keep only obsolete ones
+ if destructive:
+ mydbapi = portage.db[portage.root]["vartree"].dbapi
+ if package_names: cp_all = dict.fromkeys(mydbapi.cp_all())
+ else: cp_all = {}
+ else:
+ mydbapi = portage.db[portage.root]["porttree"].dbapi
+ cp_all = {}
+ for mycpv in clean_dict.keys():
+ if exclDictMatch(exclude_dict,portage.cpv_getkey(mycpv)):
+ # exclusion because of the exclude file
+ del clean_dict[mycpv]
+ continue
+ if mydbapi.cpv_exists(mycpv):
+ # exclusion because pkg still exists (in porttree or vartree)
+ del clean_dict[mycpv]
+ continue
+ if portage.cpv_getkey(mycpv) in cp_all:
+ # exlusion because of --package-names
+ del clean_dict[mycpv]
+
+ return clean_dict
+
+
+###############################################################################
+# doCleanup: takes a dictionnary {'display name':[list of files]}. Calculate
+# size of each entry for display, prompt user if needed, delete files if needed
+# and return the total size of files that [have been / would be] deleted.
+def doCleanup(clean_dict,action,myoptions):
+ # define vocabulary of this action
+ if action == 'distfiles': file_type = 'file'
+ else: file_type = 'binary package'
+ # sorting helps reading
+ clean_keys = clean_dict.keys()
+ clean_keys.sort()
+ clean_size = 0
+ # clean all entries one by one
+ for mykey in clean_keys:
+ key_size = 0
+ for file in clean_dict[mykey]:
+ # get total size for an entry (may be several files, and
+ # symlinks count zero)
+ if os.path.islink(file): continue
+ try: key_size += os.path.getsize(file)
+ except: eerror("Could not read size of "+file, \
+ myoptions['nocolor'])
+ if not myoptions['quiet']:
+ # pretty print mode
+ print prettySize(key_size,True),teal(mykey)
+ elif myoptions['pretend'] or myoptions['interactive']:
+ # file list mode
+ for file in clean_dict[mykey]: print file
+ #else: actually delete stuff, but don't print anything
+ if myoptions['pretend']: clean_size += key_size
+ elif not myoptions['interactive'] \
+ or myoptions['accept_all'] \
+ or yesNoAllPrompt(myoptions, \
+ "Do you want to delete this " \
+ + file_type+"?"):
+ # non-interactive mode or positive answer.
+ # For each file,...
+ for file in clean_dict[mykey]:
+ # ...get its size...
+ filesize = 0
+ if not os.path.exists(file): continue
+ if not os.path.islink(file):
+ try: filesize = os.path.getsize(file)
+ except: eerror("Could not read size of "\
+ +file, myoptions['nocolor'])
+ # ...and try to delete it.
+ try: os.unlink(file)
+ except: eerror("Could not delete "+file, \
+ myoptions['nocolor'])
+ # only count size if successfully deleted
+ else: clean_size += filesize
+ # return total size of deleted or to delete files
+ return clean_size
+
+
+###############################################################################
+# doAction: execute one action, ie display a few message, call the right find*
+# function, and then call doCleanup with its result.
+def doAction(action,myoptions,exclude_dict={}):
+ # define vocabulary for the output
+ if action == 'packages': files_type = "binary packages"
+ else: files_type = "distfiles"
+ # find files to delete, depending on the action
+ if not myoptions['quiet']:
+ einfo("Building file list for "+action+" cleaning...", \
+ myoptions['nocolor'])
+ if action == 'packages':
+ clean_dict = findPackages( \
+ exclude_dict=exclude_dict, \
+ destructive=myoptions['destructive'], \
+ package_names=myoptions['package-names'], \
+ time_limit=myoptions['time-limit'])
+ else:
+ clean_dict = findDistfiles( \
+ exclude_dict=exclude_dict, \
+ destructive=myoptions['destructive'], \
+ fetch_restricted=myoptions['fetch-restricted'], \
+ package_names=myoptions['package-names'], \
+ time_limit=myoptions['time-limit'], \
+ size_limit=myoptions['size-limit'])
+ # actually clean files if something was found
+ if len(clean_dict.keys()):
+ # verbose pretend message
+ if myoptions['pretend'] and not myoptions['quiet']:
+ einfo("Here are "+files_type+" that would be deleted:", \
+ myoptions['nocolor'])
+ # verbose non-pretend message
+ elif not myoptions['quiet']:
+ einfo("Cleaning "+files_type+"...",myoptions['nocolor'])
+ # do the cleanup, and get size of deleted files
+ clean_size = doCleanup(clean_dict,action,myoptions)
+ # vocabulary for final message
+ if myoptions['pretend']: verb = "would be"
+ else: verb = "has been"
+ # display freed space
+ if not myoptions['quiet']:
+ einfo("Total space that "+verb+" freed in " \
+ + action + " directory: " \
+ + red(prettySize(clean_size)), \
+ myoptions['nocolor'])
+ # nothing was found, return
+ elif not myoptions['quiet']:
+ einfo("Your "+action+" directory was already clean.", \
+ myoptions['nocolor'])
+
+
+###############################################################################
+# main: parse command line and execute all actions
+def main():
+ # set default options
+ myoptions = {}
+ myoptions['nocolor'] = port_settings["NOCOLOR"] in ('yes','true') \
+ and sys.stdout.isatty()
+ if myoptions['nocolor']: nocolor()
+ # parse command line options and actions
+ try: myaction = parseArgs(myoptions)
+ # filter exception to know what message to display
+ except ParseArgsException, e:
+ if e.value == 'help':
+ printUsage(help='all')
+ sys.exit(0)
+ elif e.value[:5] == 'help-':
+ printUsage(help=e.value[5:])
+ sys.exit(0)
+ elif e.value == 'version':
+ printVersion()
+ sys.exit(0)
+ else:
+ printUsage(e.value)
+ sys.exit(2)
+ # parse the exclusion file
+ if not 'exclude-file' in myoptions:
+ my_exclude_file = "/etc/%s/%s.exclude" % (__productname__ , myaction)
+ if os.path.isfile(my_exclude_file):
+ myoptions['exclude-file'] = my_exclude_file
+ if 'exclude-file' in myoptions:
+ try: exclude_dict = parseExcludeFile(myoptions['exclude-file'])
+ except ParseExcludeFileException, e:
+ eerror(e, myoptions['nocolor'])
+ eerror("Invalid exclusion file: %s" % myoptions['exclude-file'], \
+ myoptions['nocolor'])
+ eerror("See format of this file in `man %s`" % __productname__, \
+ myoptions['nocolor'])
+ sys.exit(1)
+ else: exclude_dict={}
+ # security check for non-pretend mode
+ if not myoptions['pretend'] and portage.secpass == 0:
+ eerror("Permission denied: you must be root or belong to the portage group.", \
+ myoptions['nocolor'])
+ sys.exit(1)
+ # execute action
+ doAction(myaction, myoptions, exclude_dict=exclude_dict)
+
+
+###############################################################################
+# actually call main() if launched as a script
+if __name__ == "__main__":
+ try: main()
+ except KeyboardInterrupt:
+ print "Aborted."
+ sys.exit(130)
+ sys.exit(0)
+
diff --git a/bin/epkginfo b/bin/epkginfo
new file mode 100755
index 0000000..313170a
--- /dev/null
+++ b/bin/epkginfo
@@ -0,0 +1,207 @@
+#!/usr/bin/python
+##############################################################################
+# $Header: $
+##############################################################################
+# Distributed under the terms of the GNU General Public License, v2 or later
+# Author: Ned Ludd <solar@gentoo.org> (glue all the parts together)
+# Author: Eldad Zack <eldad@gentoo.org> (earch)
+# Author : Eric Olinger <EvvL AT RustedHalo DOT net> (metadata)
+
+# Gentoo metadata xml and arch keyword checking tool.
+
+import os
+import sys
+import re
+from stat import *
+from xml.sax import saxutils, make_parser, handler
+from xml.sax.handler import feature_namespaces
+
+import portage
+from portage.output import *
+
+version = open('/etc/gentoolkit-version').read().strip()
+
+def getvar(pkg, var):
+ file = open(pkg + ".ebuild")
+ for line in file.readlines():
+ line = line.rstrip()
+ if re.match("^"+var+"=",line):
+ vars = re.split("\"",line)[1]
+ file.close
+ return re.split(" ",vars)
+ file.close()
+
+def earch(workdir):
+ """Prints arch keywords for a given dir"""
+ portdir = portage.settings["PORTDIR"]
+ #workdir = "."
+ os.chdir(workdir)
+
+ archdict = {}
+ ebuildlist = []
+ for file in os.listdir(workdir):
+ if re.search("\.ebuild$",file):
+ ebuildlist.append(re.split("\.ebuild$",file)[0])
+
+ ebuildlist.sort(lambda x,y: portage.pkgcmp(portage.pkgsplit(x),portage.pkgsplit(y)))
+
+ for pkg in ebuildlist:
+ keywords = getvar(pkg, "KEYWORDS")
+ for arch in keywords:
+ if arch == "":
+ arch = None
+ archdict[arch] = pkg
+
+ archlist = archdict.keys();
+ archlist.sort()
+
+ for pkg in ebuildlist:
+ print darkgreen("Keywords: ") + pkg + ":",
+ for value in archlist:
+ if (value and archdict[value] == pkg):
+ if value[0] == "-":
+ print red(value),
+ elif "~" == value[0]:
+ print blue(value),
+ else:
+ print green(value),
+ print ""
+
+
+class Metadata_XML(handler.ContentHandler):
+ _inside_herd="No"
+ _inside_maintainer="No"
+ _inside_email="No"
+ _inside_longdescription="No"
+
+ _herd = ""
+ _maintainers = []
+ _longdescription = ""
+
+ def startElement(self, tag, attr):
+ if tag == "herd":
+ self._inside_herd="Yes"
+ if tag == "longdescription":
+ self._inside_longdescription="Yes"
+ if tag == "maintainer":
+ self._inside_maintainer="Yes"
+ if tag == "email":
+ self._inside_email="Yes"
+
+ def endElement(self, tag):
+ if tag == "herd":
+ self._inside_herd="No"
+ if tag == "longdescription":
+ self._inside_longdescription="No"
+ if tag == "maintainer":
+ self._inside_maintainer="No"
+ if tag == "email":
+ self._inside_email="No"
+
+ def characters(self, contents):
+ if self._inside_herd == "Yes":
+ self._herd = contents
+
+ if self._inside_longdescription == "Yes":
+ self._longdescription = contents
+
+ if self._inside_maintainer=="Yes" and self._inside_email=="Yes":
+ self._maintainers.append(contents)
+
+
+def check_metadata(full_package):
+ """Checks that the primary maintainer is still an active dev and list the hed the package belongs to"""
+ metadata_file=portage.settings["PORTDIR"] + "/" + portage.pkgsplit(full_package)[0] + "/metadata.xml"
+ if not os.path.exists(metadata_file):
+ print darkgreen("Maintainer: ") + red("Error (Missing metadata.xml)")
+ return 1
+
+ parser = make_parser()
+ handler = Metadata_XML()
+ handler._maintainers = []
+ parser.setContentHandler(handler)
+ parser.parse( metadata_file )
+
+ if len(handler._herd) < 1:
+ print darkgreen("Herd: ") + red("Error (No Herd)")
+ return 1
+ else:
+ print darkgreen("Herd: ") + handler._herd
+
+ if len(handler._maintainers) < 1:
+ print darkgreen("Maintainer: ") + handler._herd
+ else:
+ print darkgreen("Maintainer: ") + ", ".join(handler._maintainers)
+
+ if len(handler._longdescription) > 1:
+ print darkgreen("Description: ") + handler._longdescription
+ print darkgreen("Location: ") + os.path.normpath(portage.settings["PORTDIR"] + "/" + portage.pkgsplit(full_package)[0])
+
+
+def usage(code):
+ """Prints the uage information for this script"""
+ print green("epkginfo"), "(%s)" % version
+ print
+ print "Usage: epkginfo [package-cat/]package"
+ sys.exit(code)
+
+
+# default color setup
+if ( not sys.stdout.isatty() ) or ( portage.settings["NOCOLOR"] in ["yes","true"] ):
+ nocolor()
+
+def fc(x,y):
+ return cmp(y[0], x[0])
+
+
+def grab_changelog_devs(catpkg):
+ try:
+ os.chdir(portage.settings["PORTDIR"] + "/" + catpkg)
+ foo=""
+ r=re.compile("<[^@]+@gentoo.org>", re.I)
+ s="\n".join(portage.grabfile("ChangeLog"))
+ d={}
+ for x in r.findall(s):
+ if x not in d:
+ d[x] = 0
+ d[x] += 1
+
+ l=[(d[x], x) for x in d.keys()]
+ #l.sort(lambda x,y: cmp(y[0], x[0]))
+ l.sort(fc)
+ for x in l:
+ p = str(x[0]) +" "+ x[1].lstrip("<").rstrip(">")
+ foo += p[:p.find("@")]+", "
+ return foo
+ except:
+ raise
+
+def main ():
+ if len( sys.argv ) < 2:
+ usage(1)
+
+ for pkg in sys.argv[1:]:
+
+ if sys.argv[1:][:1] == "-":
+ print "NOT WORKING?=="+sys.argv[1:]
+ continue
+
+ try:
+ package_list = portage.portdb.xmatch("match-all", pkg)
+ if package_list:
+
+ catpkg = portage.pkgsplit(package_list[0])[0]
+
+ print darkgreen("Package: ") + catpkg
+ check_metadata(package_list[0])
+ earch(portage.settings["PORTDIR"] + "/" + catpkg)
+ #print darkgreen("ChangeLog: ") + grab_changelog_devs(catpkg)
+ print ""
+ else:
+ print "!!! No package '%s'" % pkg
+ except:
+ print red("Error: "+pkg+"\n")
+
+
+if __name__ == '__main__':
+ main()
diff --git a/bin/equery b/bin/equery
new file mode 100644
index 0000000..bac8a3a
--- /dev/null
+++ b/bin/equery
@@ -0,0 +1,32 @@
+#!/usr/bin/python
+#
+# Copyright 2002-2009 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2 or later
+
+"""equery is a flexible utility for Gentoo linux which can display various
+information about packages, such as the files they own, their USE flags,
+the MD5 sum of each file owned by a given package, and many other things.
+"""
+
+import sys
+# This block ensures that ^C interrupts are handled quietly.
+try:
+ import signal
+
+ def exithandler(signum,frame):
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
+ signal.signal(signal.SIGTERM, signal.SIG_IGN)
+ print
+ sys.exit(1)
+
+ signal.signal(signal.SIGINT, exithandler)
+ signal.signal(signal.SIGTERM, exithandler)
+ signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
+except KeyboardInterrupt:
+ print
+ sys.exit(1)
+
+from gentoolkit import equery
+
+equery.main()
diff --git a/trunk/src/eread/eread b/bin/eread
index c6d4de1..c6d4de1 100755
--- a/trunk/src/eread/eread
+++ b/bin/eread
diff --git a/bin/euse b/bin/euse
new file mode 100755
index 0000000..b49b120
--- /dev/null
+++ b/bin/euse
@@ -0,0 +1,547 @@
+#!/bin/bash
+
+# $Header$
+
+# bash replacement for the original euse by Arun Bhanu
+# Author: Marius Mauch <genone@gentoo.org>
+# Licensed under the GPL v2
+
+PROGRAM_NAME=euse
+PROGRAM_VERSION=$(cat /etc/gentoolkit-version)
+
+MAKE_CONF_PATH=/etc/make.conf
+MAKE_GLOBALS_PATH=/etc/make.globals
+MAKE_PROFILE_PATH=/etc/make.profile
+MAKE_CONF_BACKUP_PATH=/etc/make.conf.euse_backup
+
+[ -z "${MODE}" ] && MODE="showhelp" # available operation modes: showhelp, showversion, showdesc, showflags, modify
+
+parse_arguments() {
+ if [ -z "${1}" ]; then
+ return
+ fi
+ while [ -n "${1}" ]; do
+ case "${1}" in
+ -h | --help) MODE="showhelp";;
+ -V | -v | --version) MODE="showversion";;
+ -i | --info) MODE="showdesc";;
+ -I | --info-installed) MODE="showinstdesc";;
+ -l | --local) SCOPE="local";;
+ -g | --global) SCOPE="global";;
+ -a | --active) MODE="showflags";;
+ -E | --enable) MODE="modify"; ACTION="add";;
+ -D | --disable) MODE="modify"; ACTION="remove";;
+ -P | --prune) MODE="modify"; ACTION="prune";;
+ -*)
+ echo "ERROR: unknown option ${1} specified."
+ echo
+ MODE="showhelp"
+ ;;
+ "%active")
+ get_useflags
+ ARGUMENTS="${ARGUMENTS} ${ACTIVE_FLAGS[9]}"
+ ;;
+ *)
+ ARGUMENTS="${ARGUMENTS} ${1}"
+ ;;
+ esac
+ shift
+ done
+}
+
+error() {
+ echo "ERROR: ${1}"
+ set +f
+ exit 1
+}
+
+get_real_path() {
+ set -P
+ cd "$1"
+ pwd
+ cd "$OLDPWD"
+ set +P
+}
+
+check_sanity() {
+ # file permission tests
+ local descdir
+ local make_defaults
+
+ descdir="$(get_portdir)/profiles"
+
+ [ ! -r "${MAKE_CONF_PATH}" ] && error "${MAKE_CONF_PATH} is not readable"
+ [ ! -r "${MAKE_GLOBALS_PATH}" ] && error "${MAKE_GLOBALS_PATH} is not readable"
+ [ ! -h "${MAKE_PROFILE_PATH}" ] && error "${MAKE_PROFILE_PATH} is not a symlink"
+ [ -z "$(get_portdir)" ] && error "\$PORTDIR couldn't be determined"
+ [ ! -d "${descdir}" ] && error "${descdir} does not exist or is not a directory"
+ [ ! -r "${descdir}/use.desc" ] && error "${descdir}/use.desc is not readable"
+ [ ! -r "${descdir}/use.local.desc" ] && error "${descdir}/use.local.desc is not readable"
+ for make_defaults in $(get_all_make_defaults); do
+ [ ! -r "$make_defaults" ] && error "$_make_defaults is not readable"
+ done
+# [ ! -r "$(get_make_defaults)" ] && error "$(get_make_defaults) is not readable"
+ [ "${MODE}" == "modify" -a ! -w "${MAKE_CONF_PATH}" ] && error ""${MAKE_CONF_PATH}" is not writable"
+}
+
+showhelp() {
+cat << HELP
+${PROGRAM_NAME} (${PROGRAM_VERSION})
+
+Syntax: ${PROGRAM_NAME} <option> [suboptions] [useflaglist]
+
+Options: -h, --help - show this message
+ -V, --version - show version information
+ -i, --info - show descriptions for the given useflags
+ -I, --info-installed - show descriptions for the given useflags and
+ their current impact on the installed system
+ -g, --global - show only global use flags (suboption)
+ -l, --local - show only local use flags (suboption)
+ -a, --active - show currently active useflags and their origin
+ -E, --enable - enable the given useflags
+ -D, --disable - disable the given useflags
+ -P, --prune - remove all references to the given flags from
+ make.conf to revert to default settings
+
+Notes: ${PROGRAM_NAME} currently only works for global flags defined
+ in make.globals, make.defaults or make.conf, it doesn't handle
+ use.defaults, use.mask or package.use yet (see portage(5) for details on
+ these files). It also might have issues with cascaded profiles.
+ If multiple options are specified only the last one will be used.
+HELP
+}
+
+showversion() {
+cat << VER
+${PROGRAM_NAME} (${PROGRAM_VERSION})
+Written by Marius Mauch
+
+Copyright (C) 2004-2009 Gentoo Foundation, Inc.
+This is free software; see the source for copying conditions.
+VER
+}
+
+# remove duplicate flags from the given list in both positive and negative forms
+# (but unlike portage always keep the last value even if it's negative)
+# Otherwise the status flags could be incorrect if a flag appers multiple times in
+# one location (like make.conf).
+# Using python here as bash sucks for list handling.
+# NOTE: bash isn't actually that bad at handling lists -- sh is. This may be
+# worth another look to avoid calling python unnecessariy. Or we could
+# just write the whole thing in python. ;)
+reduce_incrementals() {
+ echo $@ | python -c "import sys
+r=[]
+for x in sys.stdin.read().split():
+ if x[0] == '-' and x[1:] in r:
+ r.remove(x[1:])
+ r.append(x)
+ elif x[0] != '-' and '-'+x in r:
+ r.remove('-'+x)
+ r.append(x)
+ elif x == '-*':
+ r = []
+ r.append(x)
+ elif x not in r:
+ r.append(x)
+print ' '.join(r)"
+}
+
+# the following function creates a bash array ACTIVE_FLAGS that contains the
+# global use flags, indexed by origin: 0: environment, 1: make.conf,
+# 2: make.defaults, 3: make.globals
+get_useflags() {
+ # only calculate once as calling emerge is painfully slow
+ [ -n "${USE_FLAGS_CALCULATED}" ] && return
+
+ # backup portdir so get_portdir() doesn't give false results later
+ portdir_backup="${PORTDIR}"
+
+ ACTIVE_FLAGS[0]="$(reduce_incrementals ${USE})"
+ USE=""
+ source "${MAKE_CONF_PATH}"
+ ACTIVE_FLAGS[1]="$(reduce_incrementals ${USE})"
+ USE=""
+ for x in $(get_all_make_defaults); do
+ source "${x}"
+ ACTIVE_FLAGS[2]="$(reduce_incrementals ${ACTIVE_FLAGS[2]} ${USE})"
+ done
+ USE=""
+ source "${MAKE_GLOBALS_PATH}"
+ ACTIVE_FLAGS[3]="$(reduce_incrementals ${USE})"
+
+ # restore saved env variables
+ USE="${ACTIVE_FLAGS[0]}"
+ PORTDIR="${portdir_backup}"
+
+ # get the currently active USE flags as seen by portage, this has to be after
+ # restoring USE or portage won't see the original environment
+ ACTIVE_FLAGS[9]="$(emerge --info | grep 'USE=' | cut -b 5- | sed -e 's:"::g')" #'
+ USE_FLAGS_CALCULATED=1
+}
+
+# get the list of all known USE flags by reading use.desc and/or use.local.desc
+# (depending on the value of $SCOPE)
+get_useflaglist() {
+ local descdir
+
+ descdir="$(get_portdir)/profiles"
+
+ if [ -z "${SCOPE}" -o "${SCOPE}" == "global" ]; then
+ egrep "^[^# ]+ +-" "${descdir}/use.desc" | cut -d\ -f 1
+ fi
+ if [ -z "${SCOPE}" -o "${SCOPE}" == "local" ]; then
+ egrep "^[^# :]+:[^ ]+ +-" "${descdir}/use.local.desc" | cut -d: -f 2 | cut -d\ -f 1
+ fi
+}
+
+# get all make.defaults by traversing the cascaded profile directories
+get_all_make_defaults() {
+ local curdir
+ local parent
+ local rvalue
+
+ curdir="${1:-$(get_real_path ${MAKE_PROFILE_PATH})}"
+
+ [ -f "${curdir}/make.defaults" ] && rvalue="${curdir}/make.defaults ${rvalue}"
+ if [ -f "${curdir}/parent" ]; then
+ for parent in $(egrep -v '(^#|^ *$)' ${curdir}/parent); do
+ pdir="$(get_real_path ${curdir}/${parent})"
+ rvalue="$(get_all_make_defaults ${pdir}) ${rvalue}"
+ done
+ fi
+
+ echo "${rvalue}"
+}
+
+# get the path to make.defaults by traversing the cascaded profile directories
+get_make_defaults() {
+ local curdir
+ local parent
+
+ curdir="${1:-$(get_real_path ${MAKE_PROFILE_PATH})}"
+
+ if [ ! -f "${curdir}/make.defaults" -a -f "${curdir}/parent" ]; then
+ for parent in $(egrep -v '(^#|^ *$)' ${curdir}/parent); do
+ if [ -f "$(get_make_defaults ${curdir}/${parent})" ]; then
+ curdir="${curdir}/${parent}"
+ break
+ fi
+ done
+ fi
+
+ echo "${curdir}/make.defaults"
+}
+
+# little helper function to get the status of a given flag in one of the
+# ACTIVE_FLAGS elements. Arguments are 1: flag to test, 2: index of ACTIVE_FLAGS,
+# 3: echo value for positive (and as lowercase for negative) test result,
+# 4 (optional): echo value for "missing" test result, defaults to blank
+get_flagstatus_helper() {
+ if echo " ${ACTIVE_FLAGS[${2}]} " | grep " ${1} " > /dev/null; then
+ echo -n "${3}"
+ elif echo " ${ACTIVE_FLAGS[${2}]} " | grep " -${1} " > /dev/null; then
+ echo -n "$(echo ${3} | tr [[:upper:]] [[:lower:]])"
+ else
+ echo -n "${4:- }"
+ fi
+}
+
+# prints a status string for the given flag, each column indicating the presence
+# for portage, in the environment, in make.conf, in make.defaults and in make.globals.
+# full positive value would be "[+ECDG]", full negative value would be [-ecdg],
+# full missing value would be "[- ]" (portage only sees present or not present)
+get_flagstatus() {
+ get_useflags
+
+ echo -n '['
+ get_flagstatus_helper "${1}" 9 "+" "-"
+ get_flagstatus_helper "${1}" 0 "E"
+ get_flagstatus_helper "${1}" 1 "C"
+ get_flagstatus_helper "${1}" 2 "D"
+ get_flagstatus_helper "${1}" 3 "G"
+ echo -n '] '
+}
+
+# faster replacement to `portageq portdir`
+get_portdir() {
+ if [ -z "${PORTDIR}" ]; then
+ use_backup="${USE}"
+ source "${MAKE_GLOBALS_PATH}"
+ for x in $(get_all_make_defaults); do
+ source "${x}"
+ done
+ source "${MAKE_CONF_PATH}"
+ USE="${use_backup}"
+ fi
+ echo "${PORTDIR}"
+}
+
+# This function takes a list of use flags and shows the status and
+# the description for each one, honoring $SCOPE
+showdesc() {
+ local descdir
+ local current_desc
+ local found_one
+ local args
+
+ args="${*:-*}"
+
+ if [ -z "${SCOPE}" ]; then
+ SCOPE="global" showdesc ${args}
+ echo
+ SCOPE="local" showdesc ${args}
+ return
+ fi
+
+ descdir="$(get_portdir)/profiles"
+
+ [ "${SCOPE}" == "global" ] && echo "global use flags (searching: ${args})"
+ [ "${SCOPE}" == "local" ] && echo "local use flags (searching: ${args})"
+ echo "************************************************************"
+
+ if [ "${args}" == "*" ]; then
+ args="$(get_useflaglist | sort -u)"
+ fi
+
+ set ${args}
+
+ foundone=0
+ while [ -n "${1}" ]; do
+ if [ "${SCOPE}" == "global" ]; then
+ if grep "^${1} *-" "${descdir}/use.desc" > /dev/null; then
+ get_flagstatus "${1}"
+ foundone=1
+ fi
+ grep "^${1} *-" "${descdir}/use.desc"
+ fi
+ # local flags are a bit more complicated as there can be multiple
+ # entries per flag and we can't pipe into printf
+ if [ "${SCOPE}" == "local" ]; then
+ if grep ":${1} *-" "${descdir}/use.local.desc" > /dev/null; then
+ foundone=1
+ fi
+ grep ":${1} *-" "${descdir}/use.local.desc" \
+ | sed -e "s/^\([^:]\+\):\(${1}\) *- *\(.\+\)/\1|\2|\3/g" \
+ | while read line; do
+ pkg="$(echo $line | cut -d\| -f 1)"
+ flag="$(echo $line | cut -d\| -f 2)"
+ desc="$(echo $line | cut -d\| -f 3)"
+ get_flagstatus "${flag}"
+ printf "%s (%s):\n%s\n\n" "${flag}" "${pkg}" "${desc}"
+ done
+ fi
+ shift
+ done
+
+ if [ ${foundone} == 0 ]; then
+ echo "no matching entries found"
+ fi
+}
+
+# Works like showdesc() but displays only descriptions of which the appropriate
+# ebuild is installed and prints the name of those packages.
+showinstdesc() {
+ local descdir
+ local current_desc
+ local args
+ local -i foundone=0
+ local IFS
+
+ args=("${@:-*}")
+
+ case "${SCOPE}" in
+ "global") echo "global use flags (searching: ${args})";;
+ "local") echo "local use flags (searching: ${args})";;
+ *) SCOPE="global" showinstdesc "${args[@]}"
+ echo
+ SCOPE="local" showinstdesc "${args[@]}"
+ return;;
+ esac
+
+ descdir="$(get_portdir)/profiles"
+ echo "************************************************************"
+
+ if [ "${args}" = "*" ]; then
+ args="$(get_useflaglist | sort -u)"
+ fi
+
+ set "${args[@]}"
+
+ while [ -n "${1}" ]; do
+ case "${SCOPE}" in
+ "global")
+ if desc=$(grep "^${1} *-" "${descdir}/use.desc"); then
+ get_flagstatus "${1}"
+ echo "$desc"
+ # get list of installed packages matching this USE flag.
+ IFS=$'\n'
+ packages=($(equery -q -C hasuse -i "${1}" | awk '{ print $(NF-1) }'))
+ foundone+=${#packages[@]}
+ printf "\nInstalled packages matching this USE flag: "
+ if [ ${foundone} -gt 0 ]; then
+ echo $'\n'"${packages[*]}"
+ else
+ echo "none"
+ fi
+ fi
+ ;;
+ "local")
+ # local flags are a bit more complicated as there can be multiple
+ # entries per flag and we can't pipe into printf
+ IFS=': ' # Use a space instead of a dash because dashes occur in cat/pkg
+ while read pkg flag desc; do
+ # print name only if package is installed
+ # NOTE: If we implement bug #114086 's enhancement we can just use the
+ # exit status of equery instead of a subshell and pipe to wc -l
+ if [ $(equery -q -C list -i -e "${pkg}" | wc -l) -gt 0 ]; then
+ foundone=1
+ get_flagstatus "${flag}"
+ printf "%s (%s):\n%s\n\n" "${flag}" "${pkg}" "${desc#- }"
+ fi
+ done < <(grep ":${1} *-" "${descdir}/use.local.desc")
+ ;;
+ esac
+ shift
+ done
+
+ if [ ${foundone} -lt 1 ]; then
+ echo "no matching entries found"
+ fi
+}
+
+# show a list of all currently active flags and where they are activated
+showflags() {
+ local args
+
+ get_useflags
+
+ args="${*:-*}"
+
+ if [ "${args}" == "*" ]; then
+ args="$(get_useflaglist | sort -u)"
+ fi
+
+ set ${args}
+
+ while [ -n "${1}" ]; do
+ if echo " ${ACTIVE_FLAGS[9]} " | grep " ${1} " > /dev/null; then
+ printf "%-20s" ${1}
+ get_flagstatus ${1}
+ echo
+ fi
+ shift
+ done
+}
+
+# two small helpers to add or remove a flag from a USE string
+add_flag() {
+ NEW_MAKE_CONF_USE="${NEW_MAKE_CONF_USE} ${1}"
+}
+
+remove_flag() {
+ NEW_MAKE_CONF_USE="${NEW_MAKE_CONF_USE// ${1} / }"
+}
+
+# USE flag modification function. Mainly a loop with calls to add_flag and
+# remove_flag to create a new USE string which is then inserted into make.conf.
+modify() {
+ if [ -z "${*}" ]; then
+ if [ "${ACTION}" != "prune" ]; then
+ echo "WARNING: no USE flags listed for modification, do you really"
+ echo " want to ${ACTION} *all* known USE flags?"
+ echo " If you don't please press Ctrl-C NOW!!!"
+ sleep 5
+ set $(get_useflaglist | sort -u)
+ fi
+ fi
+
+ get_useflags
+
+ NEW_MAKE_CONF_USE=" ${ACTIVE_FLAGS[1]} "
+
+ while [ -n "${1}" ]; do
+ if [ "${ACTION}" == "add" ]; then
+ if echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
+ shift
+ elif echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
+ remove_flag "-${1}"
+ else
+ add_flag "${1}"
+ shift
+ fi
+ elif [ "${ACTION}" == "remove" ]; then
+ if echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
+ shift
+ elif echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
+ remove_flag "${1}"
+ else
+ add_flag "-${1}"
+ shift
+ fi
+ elif [ "${ACTION}" == "prune" ]; then
+ if echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
+ remove_flag "${1}"
+ elif echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
+ remove_flag "-${1}"
+ fi
+ shift
+ fi
+ done
+
+ #echo "old flags:"
+ #echo ${ACTIVE_FLAGS[1]}
+ #echo
+ #echo "new flags:"
+ #echo ${NEW_MAKE_CONF_USE}
+
+ # a little loop to add linebreaks so we don't end with one ultra-long line
+ NEW_MAKE_CONF_USE_2=""
+ for x in ${NEW_MAKE_CONF_USE}; do
+ if [ $(((${#NEW_MAKE_CONF_USE_2}%70)+${#x}+2)) -gt 70 ]; then
+ NEW_MAKE_CONF_USE_2="${NEW_MAKE_CONF_USE_2}\\ \\n $x "
+ else
+ NEW_MAKE_CONF_USE_2="${NEW_MAKE_CONF_USE_2}${x} "
+ fi
+ done
+
+ # make a backup just in case the user doesn't like the new make.conf
+ cp -p "${MAKE_CONF_PATH}" "${MAKE_CONF_BACKUP_PATH}"
+
+ # as sed doesn't really work with multi-line patterns we have to replace USE
+ # on our own here. Basically just skip everything between USE=" and the
+ # closing ", printing our new USE line there instead.
+ inuse=0
+ had_use=0
+ x=0
+ (while [ "$x" -eq "0" ]; do
+ read -r line
+ x="$?"
+ [ "${line:0:4}" == "USE=" ] && inuse=1
+ [ "${inuse}" == "0" ] && echo -E "${line}"
+ if [ "${inuse}" == "1" ] && echo "${line}" | egrep '" *(#.*)?$' > /dev/null; then
+ echo -n 'USE="'
+ echo -ne "${NEW_MAKE_CONF_USE_2%% }"
+ echo '"'
+ inuse=0
+ had_use=1
+ fi
+ done
+ if [ ${had_use} -eq 0 ]; then
+ echo -n 'USE="'
+ echo -ne "${NEW_MAKE_CONF_USE_2%% }"
+ echo '"'
+ fi ) < "${MAKE_CONF_BACKUP_PATH}" | sed -e 's:\\ $:\\:' > "${MAKE_CONF_PATH}"
+
+ echo "${MAKE_CONF_PATH} was modified, a backup copy has been placed at ${MAKE_CONF_BACKUP_PATH}"
+}
+
+##### main program comes now #####
+
+# disable globbing as it fucks up with args=*
+set -f
+parse_arguments "$@"
+check_sanity
+
+eval ${MODE} ${ARGUMENTS}
+set +f
diff --git a/bin/glsa-check b/bin/glsa-check
new file mode 100644
index 0000000..1fb577d
--- /dev/null
+++ b/bin/glsa-check
@@ -0,0 +1,366 @@
+#!/usr/bin/python
+
+# $Header: $
+# This program is licensed under the GPL, version 2
+
+import os
+import sys
+try:
+ import portage
+except ImportError:
+ sys.path.insert(0, "/usr/lib/portage/pym")
+ import portage
+
+try:
+ from portage.output import *
+except ImportError:
+ from output import *
+
+from getopt import getopt,GetoptError
+
+__program__ = "glsa-check"
+__author__ = "Marius Mauch <genone@gentoo.org>"
+__version__ = open("/etc/gentoolkit-version").read().strip()
+
+optionmap = [
+["-l", "--list", "list all unapplied GLSA"],
+["-d", "--dump", "--print", "show all information about the given GLSA"],
+["-t", "--test", "test if this system is affected by the given GLSA"],
+["-p", "--pretend", "show the necessary commands to apply this GLSA"],
+["-f", "--fix", "try to auto-apply this GLSA (experimental)"],
+["-i", "--inject", "inject the given GLSA into the checkfile"],
+["-n", "--nocolor", "disable colors (option)"],
+["-e", "--emergelike", "do not use a least-change algorithm (option)"],
+["-h", "--help", "show this help message"],
+["-V", "--version", "some information about this tool"],
+["-v", "--verbose", "print more information (option)"],
+["-c", "--cve", "show CAN ids in listing mode (option)"],
+["-m", "--mail", "send a mail with the given GLSAs to the administrator"]
+]
+
+# print a warning as this is beta code (but proven by now, so no more warning)
+#sys.stderr.write("WARNING: This tool is completely new and not very tested, so it should not be\n")
+#sys.stderr.write("used on production systems. It's mainly a test tool for the new GLSA release\n")
+#sys.stderr.write("and distribution system, it's functionality will later be merged into emerge\n")
+#sys.stderr.write("and equery.\n")
+#sys.stderr.write("Please read http://www.gentoo.org/proj/en/portage/glsa-integration.xml\n")
+#sys.stderr.write("before using this tool AND before reporting a bug.\n\n")
+
+# option parsing
+args = []
+params = []
+try:
+ args, params = getopt(sys.argv[1:], "".join([o[0][1] for o in optionmap]), \
+ [x[2:] for x in reduce(lambda x,y: x+y, [z[1:-1] for z in optionmap])])
+# ["dump", "print", "list", "pretend", "fix", "inject", "help", "verbose", "version", "test", "nocolor", "cve", "mail"])
+ args = [a for a,b in args]
+
+ for option in ["--nocolor", "-n"]:
+ if option in args:
+ nocolor()
+ args.remove(option)
+
+ verbose = False
+ for option in ["--verbose", "-v"]:
+ if option in args:
+ verbose = True
+ args.remove(option)
+
+ list_cve = False
+ for option in ["--cve", "-c"]:
+ if option in args:
+ list_cve = True
+ args.remove(option)
+
+ least_change = True
+ for option in ["--emergelike", "-e"]:
+ if option in args:
+ least_change = False
+ args.remove(option)
+
+ # sanity checking
+ if len(args) <= 0:
+ sys.stderr.write("no option given: what should I do ?\n")
+ mode="help"
+ elif len(args) > 1:
+ sys.stderr.write("please use only one command per call\n")
+ mode = "help"
+ else:
+ # in what mode are we ?
+ args = args[0]
+ for m in optionmap:
+ if args in [o for o in m[:-1]]:
+ mode = m[1][2:]
+
+except GetoptError, e:
+ sys.stderr.write("unknown option given: ")
+ sys.stderr.write(str(e)+"\n")
+ mode = "help"
+
+# we need a set of glsa for most operation modes
+if len(params) <= 0 and mode in ["fix", "test", "pretend", "dump", "inject", "mail"]:
+ sys.stderr.write("\nno GLSA given, so we'll do nothing for now. \n")
+ sys.stderr.write("If you want to run on all GLSA please tell me so \n")
+ sys.stderr.write("(specify \"all\" as parameter)\n\n")
+ mode = "help"
+elif len(params) <= 0 and mode == "list":
+ params.append("new")
+
+# show help message
+if mode == "help":
+ sys.stderr.write("\nSyntax: glsa-check <option> [glsa-list]\n\n")
+ for m in optionmap:
+ sys.stderr.write(m[0] + "\t" + m[1] + " \t: " + m[-1] + "\n")
+ for o in m[2:-1]:
+ sys.stderr.write("\t" + o + "\n")
+ sys.stderr.write("\nglsa-list can contain an arbitrary number of GLSA ids, \n")
+ sys.stderr.write("filenames containing GLSAs or the special identifiers \n")
+ sys.stderr.write("'all', 'new' and 'affected'\n")
+ sys.exit(1)
+
+# we need root priviledges for write access
+if mode in ["fix", "inject"] and os.geteuid() != 0:
+ sys.stderr.write("\nThis tool needs root access to "+mode+" this GLSA\n\n")
+ sys.exit(2)
+
+# show version and copyright information
+if mode == "version":
+ sys.stderr.write("%(program)s (%(version)s)\n" % {
+ "program": __program__,
+ "version": __version__
+ })
+ sys.stderr.write("Author: %s\n" % __author__)
+ sys.stderr.write("This program is licensed under the GPL, version 2\n")
+ sys.exit(0)
+
+# delay this for speed increase
+from gentoolkit.glsa import *
+
+glsaconfig = checkconfig(portage.config(clone=portage.settings))
+
+vardb = portage.db["/"]["vartree"].dbapi
+portdb = portage.db["/"]["porttree"].dbapi
+
+# Check that we really have a glsa dir to work on
+if not (os.path.exists(glsaconfig["GLSA_DIR"]) and os.path.isdir(glsaconfig["GLSA_DIR"])):
+ sys.stderr.write(red("ERROR")+": GLSA_DIR %s doesn't exist. Please fix this.\n" % glsaconfig["GLSA_DIR"])
+ sys.exit(1)
+
+# build glsa lists
+completelist = get_glsa_list(glsaconfig["GLSA_DIR"], glsaconfig)
+
+if os.access(glsaconfig["CHECKFILE"], os.R_OK):
+ checklist = [line.strip() for line in open(glsaconfig["CHECKFILE"], "r").readlines()]
+else:
+ checklist = []
+todolist = [e for e in completelist if e not in checklist]
+
+glsalist = []
+if "new" in params:
+ glsalist = todolist
+ params.remove("new")
+
+if "all" in params:
+ glsalist = completelist
+ params.remove("all")
+if "affected" in params:
+ # replaced completelist with todolist on request of wschlich
+ for x in todolist:
+ try:
+ myglsa = Glsa(x, glsaconfig)
+ except (GlsaTypeException, GlsaFormatException), e:
+ if verbose:
+ sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (x, e)))
+ continue
+ if myglsa.isVulnerable():
+ glsalist.append(x)
+ params.remove("affected")
+
+# remove invalid parameters
+for p in params[:]:
+ if not (p in completelist or os.path.exists(p)):
+ sys.stderr.write(("(removing %s from parameter list as it isn't a valid GLSA specification)\n" % p))
+ params.remove(p)
+
+glsalist.extend([g for g in params if g not in glsalist])
+
+def summarylist(myglsalist, fd1=sys.stdout, fd2=sys.stderr):
+ fd2.write(white("[A]")+" means this GLSA was already applied,\n")
+ fd2.write(green("[U]")+" means the system is not affected and\n")
+ fd2.write(red("[N]")+" indicates that the system might be affected.\n\n")
+
+ for myid in myglsalist:
+ try:
+ myglsa = Glsa(myid, glsaconfig)
+ except (GlsaTypeException, GlsaFormatException), e:
+ if verbose:
+ fd2.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
+ continue
+ if myglsa.isApplied():
+ status = "[A]"
+ color = white
+ elif myglsa.isVulnerable():
+ status = "[N]"
+ color = red
+ else:
+ status = "[U]"
+ color = green
+
+ if verbose:
+ access = ("[%-8s] " % myglsa.access)
+ else:
+ access=""
+
+ fd1.write(color(myglsa.nr) + " " + color(status) + " " + color(access) + myglsa.title + " (")
+ if not verbose:
+ for pkg in myglsa.packages.keys()[:3]:
+ fd1.write(" " + pkg + " ")
+ if len(myglsa.packages) > 3:
+ fd1.write("... ")
+ else:
+ for pkg in myglsa.packages.keys():
+ mylist = vardb.match(portage.dep_getkey(pkg))
+ if len(mylist) > 0:
+ pkg = color(" ".join(mylist))
+ fd1.write(" " + pkg + " ")
+
+ fd1.write(")")
+ if list_cve:
+ fd1.write(" "+(",".join([r[:13] for r in myglsa.references if r[:4] in ["CAN-", "CVE-"]])))
+ fd1.write("\n")
+ return 0
+
+if mode == "list":
+ sys.exit(summarylist(glsalist))
+
+# dump, fix, inject and fix are nearly the same code, only the glsa method call differs
+if mode in ["dump", "fix", "inject", "pretend"]:
+ for myid in glsalist:
+ try:
+ myglsa = Glsa(myid, glsaconfig)
+ except (GlsaTypeException, GlsaFormatException), e:
+ if verbose:
+ sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
+ continue
+ if mode == "dump":
+ myglsa.dump()
+ elif mode == "fix":
+ sys.stdout.write("fixing "+myid+"\n")
+ mergelist = myglsa.getMergeList(least_change=least_change)
+ for pkg in mergelist:
+ sys.stdout.write(">>> merging "+pkg+"\n")
+ # using emerge for the actual merging as it contains the dependency
+ # code and we want to be consistent in behaviour. Also this functionality
+ # will be integrated in emerge later, so it shouldn't hurt much.
+ emergecmd = "emerge --oneshot " + glsaconfig["EMERGE_OPTS"] + " =" + pkg
+ if verbose:
+ sys.stderr.write(emergecmd+"\n")
+ exitcode = os.system(emergecmd)
+ # system() returns the exitcode in the high byte of a 16bit integer
+ if exitcode >= 1<<8:
+ exitcode >>= 8
+ if exitcode:
+ sys.exit(exitcode)
+ myglsa.inject()
+ elif mode == "pretend":
+ sys.stdout.write("Checking GLSA "+myid+"\n")
+ mergelist = myglsa.getMergeList(least_change=least_change)
+ if mergelist:
+ sys.stdout.write("The following updates will be performed for this GLSA:\n")
+ for pkg in mergelist:
+ oldver = None
+ for x in vardb.match(portage.dep_getkey(pkg)):
+ if vardb.aux_get(x, ["SLOT"]) == portdb.aux_get(pkg, ["SLOT"]):
+ oldver = x
+ if oldver == None:
+ raise ValueError("could not find old version for package %s" % pkg)
+ oldver = oldver[len(portage.dep_getkey(oldver))+1:]
+ sys.stdout.write(" " + pkg + " (" + oldver + ")\n")
+ else:
+ sys.stdout.write("Nothing to do for this GLSA\n")
+ elif mode == "inject":
+ sys.stdout.write("injecting " + myid + "\n")
+ myglsa.inject()
+ sys.stdout.write("\n")
+ sys.exit(0)
+
+# test is a bit different as Glsa.test() produces no output
+if mode == "test":
+ outputlist = []
+ for myid in glsalist:
+ try:
+ myglsa = Glsa(myid, glsaconfig)
+ except (GlsaTypeException, GlsaFormatException), e:
+ if verbose:
+ sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
+ continue
+ if myglsa.isVulnerable():
+ if verbose:
+ outputlist.append(str(myglsa.nr)+" ( "+myglsa.title+" ) ")
+ else:
+ outputlist.append(str(myglsa.nr))
+ if len(outputlist) > 0:
+ sys.stderr.write("This system is affected by the following GLSAs:\n")
+ sys.stdout.write("\n".join(outputlist)+"\n")
+ else:
+ sys.stderr.write("This system is not affected by any of the listed GLSAs\n")
+ sys.exit(0)
+
+# mail mode as requested by solar
+if mode == "mail":
+ try:
+ import portage.mail as portage_mail
+ except ImportError:
+ import portage_mail
+
+ import socket
+ from StringIO import StringIO
+ try:
+ from email.mime.text import MIMEText
+ except ImportError:
+ from email.MIMEText import MIMEText
+
+ # color doesn't make any sense for mail
+ nocolor()
+
+ if glsaconfig.has_key("PORTAGE_ELOG_MAILURI"):
+ myrecipient = glsaconfig["PORTAGE_ELOG_MAILURI"].split()[0]
+ else:
+ myrecipient = "root@localhost"
+
+ if glsaconfig.has_key("PORTAGE_ELOG_MAILFROM"):
+ myfrom = glsaconfig["PORTAGE_ELOG_MAILFROM"]
+ else:
+ myfrom = "glsa-check"
+
+ mysubject = "[glsa-check] Summary for %s" % socket.getfqdn()
+
+ # need a file object for summarylist()
+ myfd = StringIO()
+ myfd.write("GLSA Summary report for host %s\n" % socket.getfqdn())
+ myfd.write("(Command was: %s)\n\n" % " ".join(sys.argv))
+ summarylist(glsalist, fd1=myfd, fd2=myfd)
+ summary = str(myfd.getvalue())
+ myfd.close()
+
+ myattachments = []
+ for myid in glsalist:
+ try:
+ myglsa = Glsa(myid, glsaconfig)
+ except (GlsaTypeException, GlsaFormatException), e:
+ if verbose:
+ sys.stderr.write(("invalid GLSA: %s (error message was: %s)\n" % (myid, e)))
+ continue
+ myfd = StringIO()
+ myglsa.dump(outstream=myfd)
+ myattachments.append(MIMEText(str(myfd.getvalue()), _charset="utf8"))
+ myfd.close()
+
+ mymessage = portage_mail.create_message(myfrom, myrecipient, mysubject, summary, myattachments)
+ portage_mail.send_mail(glsaconfig, mymessage)
+
+ sys.exit(0)
+
+# something wrong here, all valid paths are covered with sys.exit()
+sys.stderr.write("nothing more to do\n")
+sys.exit(2)
diff --git a/bin/revdep-rebuild b/bin/revdep-rebuild
new file mode 100755
index 0000000..fac03d8
--- /dev/null
+++ b/bin/revdep-rebuild
@@ -0,0 +1,1094 @@
+#!/bin/bash
+# Copyright 1999-2008 Gentoo Foundation
+
+# revdep-rebuild: Reverse dependency rebuilder.
+# Original Author: Stanislav Brabec
+# Rewrite Author: Michael A. Smith
+# Current Maintainer: Paul Varner <fuzzyray@gentoo.org>
+
+# TODO:
+# - Use more /etc/init.d/functions.sh
+# - Try to reduce the number of global vars
+
+##
+# Global Variables:
+
+# Must-be-blank:
+unset GREP_OPTIONS
+
+# Readonly variables:
+declare -r APP_NAME="${0##*/}" # The name of this application
+declare -r OIFS="$IFS" # Save the IFS
+declare -r ENV_FILE=0_env.rr # Contains environment variables
+declare -r FILES_FILE=1_files.rr # Contains a list of files to search
+declare -r LDPATH_FILE=2_ldpath.rr # Contains the LDPATH
+declare -r BROKEN_FILE=3_broken.rr # Contains the list of broken files
+declare -r ERRORS_FILE=3_errors.rr # Contains the ldd error output
+declare -r RAW_FILE=4_raw.rr # Contains the raw list of packages
+declare -r OWNERS_FILE=4_owners.rr # Contains the file owners
+declare -r PKGS_FILE=4_pkgs.rr # Contains the unsorted bare package names
+declare -r EBUILDS_FILE=4_ebuilds.rr # Contains the unsorted atoms
+ # (Appropriately slotted or versioned)
+declare -r ORDER_FILE=5_order.rr # Contains the sorted atoms
+declare -r STATUS_FILE=6_status.rr # Contains the ldd error output
+declare -ra FILES=(
+ "$ENV_FILE"
+ "$FILES_FILE"
+ "$LDPATH_FILE"
+ "$BROKEN_FILE"
+ "$ERRORS_FILE"
+ "$RAW_FILE"
+ "$OWNERS_FILE"
+ "$PKGS_FILE"
+ "$EBUILDS_FILE"
+ "$ORDER_FILE"
+ "$STATUS_FILE"
+)
+
+# "Boolean" variables: Considered "true" if it has any value at all
+# "True" indicates we should...
+declare FULL_LD_PATH # ...search across the COMPLETE_LD_LIBRARY_PATH
+declare KEEP_TEMP # ...not delete tempfiles from the current run
+declare ORDER_PKGS # ...sort the atoms in deep dependency order
+declare PACKAGE_NAMES # ...emerge by slot, not by versionated atom
+declare RM_OLD_TEMPFILES # ...remove tempfiles from prior runs
+declare SEARCH_BROKEN # ...search for broken libraries and binaries
+declare VERBOSE # ...give verbose output
+
+# Globals that impact portage directly:
+declare EMERGE_DEFAULT_OPTS # String of options portage assumes to be set
+declare EMERGE_OPTIONS # Array of options to pass to portage
+declare PORTAGE_NICENESS # Renice to this value
+declare PORTAGE_ROOT # The root path for portage
+
+# Customizable incremental variables:
+# These variables can be prepended to either by setting the variable in
+# your environment prior to execution, or by placing an entry in
+# /etc/make.conf.
+#
+# An entry of "-*" means to clear the variable from that point forward.
+# Example: env SEARCH_DIRS="/usr/bin -*" revdep-rebuild will set SEARCH_DIRS
+# to contain only /usr/bin
+declare LD_LIBRARY_MASK # Mask of specially evaluated libraries
+declare SEARCH_DIRS # List of dirs to search for executables and libraries
+declare SEARCH_DIRS_MASK # List of dirs not to search
+
+# Other globals:
+declare OLDPROG # Previous pass through the progress meter
+declare EXACT_PKG # Versionated atom to emerge
+declare HEAD_TEXT # Feedback string about the search
+declare NOCOLOR # Set to "true" not to output term colors
+declare OK_TEXT # Feedback about a search which found no errors
+declare RC_NOCOLOR # Hack to insure we respect NOCOLOR
+declare REBUILD_LIST # Array of atoms to emerge
+declare SKIP_LIST # Array of atoms that cannot be emerged (masked?)
+declare SONAME # Soname/soname path pattern given on commandline
+declare SONAME_SEARCH # Value of SONAME modified to match ldd's output
+declare WORKING_TEXT # Feedback about the search
+declare WORKING_DIR # Working directory where cache files are kept
+
+main() {
+ # preliminary setup
+ get_opts "$@"
+ setup_portage
+ setup_search_paths_and_masks
+ get_search_env
+ echo
+
+ # Search for broken binaries
+ get_files
+ get_ldpath
+ main_checks
+
+ # Associate broken binaries with packages to rebuild
+ if [[ $PACKAGE_NAMES ]]; then
+ get_packages
+ clean_packages
+ assign_packages_to_ebuilds
+ else
+ get_exact_ebuilds
+ fi
+
+ # Rebuild packages owning broken binaries
+ get_build_order
+ rebuild
+
+ # All done
+ cleanup
+}
+##
+# Refuse to delete anything before we cd to our tmpdir
+# (See mkdir_and_cd_to_tmpdir()
+rm() {
+ eerror "I was instructed to rm '$@'"
+ die 1 "Refusing to delete anything before changing to temporary directory."
+}
+##
+# GNU find has -executable, but if our users' finds do not have that flag
+# we emulate it with this function. Also emulates -writable and -readable.
+# Usage: find PATH ARGS -- use find like normal, except use -executable instead
+# of various versions of -perm /+ blah blah and hacks
+find() {
+ hash find || { die 1 'find not found!'; }
+ # We can be pretty sure find itself should be executable.
+ local testsubject="$(type -P find)"
+ if [[ $(command find "$testsubject" -executable 2> /dev/null) ]]; then
+ unset -f find # We can just use the command find
+ elif [[ $(command find "$testsubject" -perm /u+x 2> /dev/null) ]]; then
+ find() {
+ a=(${@//-executable/-perm \/u+x})
+ a=(${a[@]//-writable/-perm \/u+w})
+ a=(${a[@]//-readable/-perm \/r+w})
+ command find "${a[@]}"
+ }
+ elif [[ $(command find "$testsubject" -perm +u+x 2> /dev/null) ]]; then
+ find() {
+ a=(${@//-executable/-perm +u+x})
+ a=(${a[@]//-writable/-perm +u+w})
+ a=(${a[@]//-readable/-perm +r+w})
+ command find "${a[@]}"
+ }
+ else # Last resort
+ find() {
+ a=(${@//-executable/-exec test -x '{}' \; -print})
+ a=(${a[@]//-writable/-exec test -w '{}' \; -print})
+ a=(${a[@]//-readable/-exec test -r '{}' \; -print})
+ command find "${a[@]}"
+ }
+ fi
+ find "$@"
+}
+
+print_usage() {
+cat << EOF
+Usage: $APP_NAME [OPTIONS] [--] [EMERGE_OPTIONS]
+
+Broken reverse dependency rebuilder.
+
+ -C, --nocolor Turn off colored output
+ -d, --debug Print way too much information (uses bash's set -xv)
+ -e, --exact Emerge based on exact package version
+ -h, --help Print this usage
+ -i, --ignore Ignore temporary files from previous runs
+ -k, --keep-temp Do not delete temporary files on exit
+ -L, --library NAME Emerge existing packages that use the library with NAME
+ --library=NAME NAME can be a full path to the library or a basic
+ regular expression (man grep)
+ -l, --no-ld-path Do not set LD_LIBRARY_PATH
+ -o, --no-order Do not check the build order
+ (Saves time, but may cause breakage.)
+ -p, --pretend Do a trial run without actually emerging anything
+ (also passed to emerge command)
+ -P, --no-progress Turn off the progress meter
+ -q, --quiet Be less verbose (also passed to emerge command)
+ -v, --verbose Be more verbose (also passed to emerge command)
+
+Calls emerge, options after -- are ignored by $APP_NAME
+and passed directly to emerge.
+
+Report bugs to <http://bugs.gentoo.org>
+EOF
+}
+##
+# Usage: progress i n
+# i: current item
+# n: total number of items to process
+progress() {
+ if [[ -t 1 ]]; then
+ progress() {
+ local curProg=$(( $1 * 100 / $2 ))
+ (( curProg == OLDPROG )) && return # no change, output nothing
+ OLDPROG="$curProg" # must be a global variable
+ (( $1 == $2 )) && local lb=$'\n'
+ echo -ne '\r \r'"[ $curProg% ] $lb"
+ }
+ progress $@
+ else # STDOUT is not a tty. Disable progress meter.
+ progress() { :; }
+ fi
+}
+##
+# Usage: countdown n
+# n: number of seconds to count
+countdown() {
+ local i
+ for ((i=1; i<$1; i++)); do
+ echo -ne '\a.'
+ ((i<$1)) && sleep 1
+ done
+ echo -e '\a.'
+}
+##
+# Replace whitespace with linebreaks, normalize repeated '/' chars, and sort -u
+# (If any libs have whitespace in their filenames, someone needs punishment.)
+clean_var() {
+ awk 'BEGIN {RS="[[:space:]]"}
+ /-\*/ {exit}
+ /[^[:space:]]/ {gsub(/\/\/+/, "/"); print}' | sort -u
+}
+##
+# Exit and optionally output to sterr
+die() {
+ local status=$1
+ shift
+ eerror "$@"
+ exit $status
+}
+##
+# What to do when dynamic linking is consistent
+clean_exit() {
+ if [[ ! $KEEP_TEMP ]]; then
+ rm -f "${FILES[@]}"
+ if [[ "$WORKING_DIR" != "/var/cache/${APP_NAME}" ]]; then
+ # Remove the working directory
+ builtin cd; rmdir "$WORKING_DIR"
+ fi
+ fi
+ echo
+ einfo "$OK_TEXT... All done. "
+ exit 0
+}
+##
+# Get the name of the package that owns a file or list of files given as args.
+get_file_owner() {
+ local IFS=$'\n'
+ # ${*/%/ } adds a space to the end of each object name to prevent false
+ # matches, for example /usr/bin/dia matching /usr/bin/dialog (bug #196460).
+ find -L /var/db/pkg -name CONTENTS -print0 |
+ xargs -0 grep -Fl "${*/%/ }" |
+ sed 's:/var/db/pkg/\(.*\)/CONTENTS:\1:'
+}
+##
+# Normalize some EMERGE_OPTIONS
+normalize_emerge_opts() {
+ # Normalize some EMERGE_OPTIONS
+ EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-p/--pretend})
+ EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-f/--fetchonly})
+ EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]/%-v/--verbose})
+}
+##
+# Use the color preference from portage
+setup_color() {
+ # This should still work if NOCOLOR is set by the -C flag or in the user's
+ # environment.
+ export NOCOLOR=$(portageq envvar NOCOLOR)
+ [[ $NOCOLOR = yes || $NOCOLOR = true ]] && export RC_NOCOLOR=yes # HACK! (grr)
+ . /etc/init.d/functions.sh
+}
+##
+# Die if an argument is missing.
+die_if_missing_arg() {
+ [[ ! $2 || $2 = -* ]] && die 1 "Missing expected argument to $1"
+}
+##
+# Die because an option is not recognized.
+die_invalid_option() {
+ # Can't use eerror and einfo because this gets called before function.sh
+ # is sourced
+ echo
+ echo "Encountered unrecognized option $1." >&2
+ echo
+ echo "$APP_NAME no longer automatically passes unrecognized options to portage."
+ echo "Separate emerge-only options from revdep-rebuild options with the -- flag."
+ echo
+ echo "For example, $APP_NAME -v -- --ask"
+ echo
+ echo "See the man page or $APP_NAME -h for more detail."
+ echo
+ exit 1
+}
+##
+# Warn about deprecated options.
+warn_deprecated_opt() {
+ # Can't use eerror and einfo because this gets called before function.sh
+ # is sourced
+ echo
+ echo "Encountered deprecated option $1." >&2
+ [[ $2 ]] && echo "Please use $2 instead." >&2
+}
+##
+# Get whole-word commandline options preceded by two dashes.
+get_longopts() {
+ case $1 in
+ --nocolor) export NOCOLOR="yes";;
+ --no-color) warn_deprecated_opt "$1" "--nocolor"
+ export NOCOLOR="yes";;
+ --debug) set -xv;;
+ --exact) unset PACKAGE_NAMES;;
+ --help) print_usage
+ exit 0;;
+ --ignore) RM_OLD_TEMPFILES=1;;
+ --keep-temp) KEEP_TEMP=1;;
+ --library=*) # TODO: check for invalid values
+ SONAME="${1#*=}"
+ unset SEARCH_BROKEN;;
+ --soname=*|--soname-regexp=*) # TODO: check for invalid values
+ warn_deprecated_opt "${1%=*}" "--library"
+ SONAME="${1#*=}"
+ unset SEARCH_BROKEN;;
+ --library) # TODO: check for invalid values
+ die_if_missing_arg $1 $2
+ shift
+ SONAME="$1"
+ unset SEARCH_BROKEN;;
+ --soname|--soname-regexp) # TODO: check for invalid values
+ warn_deprecated_opt "$1" "--library"
+ die_if_missing_arg $1 $2
+ shift
+ SONAME="$1"
+ unset SEARCH_BROKEN;;
+ --no-ld-path) unset FULL_LD_PATH;;
+ --no-order) unset ORDER_PKGS;;
+ --no-progress) progress() { :; };;
+ --pretend) EMERGE_OPTIONS+=("--pretend");;
+ --quiet) echo_v() { :; }
+ progress() { :; }
+ quiet=1
+ EMERGE_OPTIONS+=($1);;
+ --verbose) VERBOSE=1
+ EMERGE_OPTIONS+=("--verbose");;
+ --extra-verbose) warn_deprecated_opt "$1" "--verbose"
+ VERBOSE=1
+ EMERGE_OPTIONS+=("--verbose");;
+ --package-names) # No longer used, since it is the
+ # default. We accept it for
+ # backwards compatibility.
+ warn_deprecated_opt "$1"
+ PACKAGE_NAMES=1;;
+ *) die_invalid_option $1;;
+ esac
+}
+
+##
+# Get single-letter commandline options preceded by a single dash.
+get_shortopts() {
+ local OPT OPTSTRING OPTARG OPTIND
+ while getopts ":CdehikL:loPpqu:vX" OPT; do
+ case "$OPT" in
+ C) # TODO: Match syntax with the rest of gentoolkit
+ export NOCOLOR="yes";;
+ d) set -xv;;
+ e) unset PACKAGE_NAMES;;
+ h) print_usage
+ exit 0;;
+ i) RM_OLD_TEMPFILES=1;;
+ k) KEEP_TEMP=1;;
+ L) # TODO: Check for invalid values
+ SONAME="${OPTARG#*=}"
+ unset SEARCH_BROKEN;;
+ l) unset FULL_LD_PATH;;
+ o) unset ORDER_PKGS;;
+ P) progress() { :; };;
+ p) EMERGE_OPTIONS+=("--pretend");;
+ q) echo_v() { :; }
+ progress() { :; }
+ quiet=1
+ EMERGE_OPTIONS+=("--quiet");;
+ v) VERBOSE=1
+ EMERGE_OPTIONS+=("--verbose");;
+ X) # No longer used, since it is the default.
+ # We accept it for backwards compatibility.
+ warn_deprecated_opt "-X"
+ PACKAGE_NAMES=1;;
+ *) die_invalid_option "-$OPTARG";;
+ esac
+ done
+}
+##
+# Get command-line options.
+get_opts() {
+ local avoid_utils
+ local -a args
+ echo_v() { ewarn "$@"; }
+ unset VERBOSE KEEP_TEMP EMERGE_OPTIONS RM_OLD_TEMPFILES
+ ORDER_PKGS=1
+ PACKAGE_NAMES=1
+ SONAME="not found"
+ SEARCH_BROKEN=1
+ FULL_LD_PATH=1
+ while [[ $1 ]]; do
+ case $1 in
+ --) shift
+ EMERGE_OPTIONS+=("$@")
+ break;;
+ -*) while true; do
+ args+=("$1")
+ shift
+ [[ ${1:--} = -* ]] && break
+ done
+ if [[ ${args[0]} = --* ]]; then
+ get_longopts "${args[@]}"
+ else
+ get_shortopts "${args[@]}"
+ fi;;
+ *) die_invalid_option "$1";;
+ esac
+ unset args
+ done
+
+ setup_color
+ normalize_emerge_opts
+
+ # If the user is not super, add --pretend to EMERGE_OPTIONS
+ if [[ ${EMERGE_OPTIONS[@]} != *--pretend* && $UID -ne 0 ]]; then
+ ewarn "You are not superuser. Adding --pretend to emerge options."
+ EMERGE_OPTIONS+=(--pretend)
+ fi
+}
+##
+# Is there a --pretend or --fetchonly flag in the EMERGE_OPTIONS array?
+is_real_merge() {
+ [[ ${EMERGE_OPTIONS[@]} != *--pretend* &&
+ ${EMERGE_OPTIONS[@]} != *--fetchonly* ]]
+}
+##
+# Clean up temporary files and exit
+cleanup_and_die() {
+ rm -f "$@"
+ die 1 " ...terminated. Removing incomplete $@."
+}
+##
+# Clean trap
+clean_trap() {
+ trap "cleanup_and_die $*" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+ rm -f "$@"
+}
+##
+# Returns 0 if the first arg is found in the remaining args, 1 otherwise
+# (Returns 2 if given fewer than 2 arguments)
+has() {
+ (( $# > 1 )) || return 2
+ local IFS=$'\a' target="$1"
+ shift
+ [[ $'\a'"$*"$'\a' = *$'\a'$target$'\a'* ]]
+}
+##
+# Dies when it can't change directories
+cd() {
+ if builtin cd -P "$@"; then
+ if [[ $1 != $PWD ]]; then
+ # Some symlink malfeasance is going on
+ die 1 "Working directory expected to be $1, but it is $PWD"
+ fi
+ else
+ die 1 "Unable to change working directory to '$@'"
+ fi
+}
+##
+# Tries not to delete any files or directories it shouldn't
+setup_rm() {
+ ##
+ # Anything in the FILES array in tmpdir is fair game for removal
+ rm() {
+ local i IFS=$'\a'
+ [[ $APP_NAME ]] || die 1 '$APP_NAME is not defined! (This is a bug.)'
+ case $@ in
+ */*|*-r*|*-R*) die 1 "Oops, I'm not allowed to delete that. ($@)";;
+ esac
+ for i; do
+ # Don't delete files that are not listed in the array
+ # Allow no slashes or recursive deletes at all.
+ case $i in
+ */*|-*r*|-*R*) :;; # Not OK
+ -*) continue;; # OK
+ esac
+ has "$i" "${FILES[@]}" && continue
+ die 1 "Oops, I'm not allowed to delete that. ($@)"
+ done
+ command rm "$@"
+ }
+ # delete this setup function so it's harmless to re-run
+ setup_rm() { :; }
+}
+##
+# Make our temporary files directory
+# $1 - directory name
+# $2 - user name
+verify_tmpdir() {
+ umask 007 || die $? "Unable to set umask 007"
+ if [[ ! $1 ]]; then
+ die 1 'Temporary file path is unset! (This is a bug.)'
+ elif [[ -d $1 ]]; then
+ # HACK: I hate using find this way
+ if [[ $(find "$1" -type d ! \( -user $2 -perm -0700 \) ) ]]; then
+ eerror "Incorrect permissions on $1"
+ eerror "or at least one file in $1."
+ die 1 "Please make sure it's not a symlink and then remove it."
+ fi
+ cd "$1"
+ else
+ die 1 "Unable to find a satisfactory location for temporary files ($1)"
+ fi
+ [[ $VERBOSE ]] && einfo "Temporary cache files are located in $PWD"
+ setup_rm
+}
+get_search_env() {
+ local new_env
+ local old_env
+ local uid=$(python -c 'import os; import pwd; print pwd.getpwuid(os.getuid())[0]')
+ # Find a place to put temporary files
+ if [[ "$uid" == "root" ]]; then
+ local tmp_target="/var/cache/${APP_NAME}"
+ else
+ local tmp_target="$(mktemp -d -t revdep-rebuild.XXXXXXXXXX)"
+ fi
+
+ # From here on all work is done inside the temporary directory
+ verify_tmpdir "$tmp_target" "$uid"
+ WORKING_DIR="$tmp_target"
+
+ if [[ $SEARCH_BROKEN ]]; then
+ SONAME_SEARCH="$SONAME"
+ HEAD_TEXT="broken by a package update"
+ OK_TEXT="Dynamic linking on your system is consistent"
+ WORKING_TEXT="consistency"
+ else
+ # first case is needed to test against /path/to/foo.so
+ if [[ $SONAME = /* ]]; then
+ # Set to "<space>$SONAME<space>"
+ SONAME_SEARCH=" $SONAME "
+ # Escape the "/" characters
+ SONAME_SEARCH="${SONAME_SEARCH//\//\\/}"
+ else
+ # Set to "<tab>$SONAME<space>"
+ SONAME_SEARCH=$'\t'"$SONAME "
+ fi
+ HEAD_TEXT="using $SONAME"
+ OK_TEXT="There are no dynamic links to $SONAME"
+ unset WORKING_TEXT
+ fi
+
+ # If any of our temporary files are older than 1 day, remove them all
+ if [[ ! $KEEP_TEMP ]]; then
+ while read; do
+ RM_OLD_TEMPFILES=1
+ break
+ done < <(find -L . -maxdepth 1 -type f -name '*.rr' -mmin +1440 -print 2>/dev/null)
+ fi
+
+ # Compare old and new environments
+ # Don't use our previous files if environment doesn't match
+ new_env=$(
+ # We do not care if these emerge options change
+ EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--pretend/})
+ EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--fetchonly/})
+ EMERGE_OPTIONS=(${EMERGE_OPTIONS[@]//--verbose/})
+ cat <<- EOF
+ SEARCH_DIRS="$SEARCH_DIRS"
+ SEARCH_DIRS_MASK="$SEARCH_DIRS_MASK"
+ LD_LIBRARY_MASK="$LD_LIBRARY_MASK"
+ PORTAGE_ROOT="$PORTAGE_ROOT"
+ EMERGE_OPTIONS="${EMERGE_OPTIONS[@]}"
+ ORDER_PKGS="$ORDER_PKGS"
+ FULL_LD_PATH="$FULL_LD_PATH"
+ EOF
+ )
+ if [[ -r "$ENV_FILE" && -s "$ENV_FILE" ]]; then
+ old_env=$(<"$ENV_FILE")
+ if [[ $old_env != $new_env ]]; then
+ ewarn 'Environment mismatch from previous run, deleting temporary files...'
+ RM_OLD_TEMPFILES=1
+ fi
+ else
+ # No env file found, silently delete any other tempfiles that may exist
+ RM_OLD_TEMPFILES=1
+ fi
+
+ # If we should remove old tempfiles, do so
+ if [[ $RM_OLD_TEMPFILES ]]; then
+ rm -f "${FILES[@]}"
+ else
+ for file in "${FILES[@]}"; do
+ if [ -e "$file" ]; then
+ chown ${uid}:portage "$file"
+ chmod 700 "$file"
+ fi
+ done
+ fi
+
+ # Save the environment in a file for next time
+ echo "$new_env" > "$ENV_FILE"
+
+ [[ $VERBOSE ]] && echo $'\n'"$APP_NAME environment:"$'\n'"$new_env"
+
+ echo
+ einfo "Checking reverse dependencies"
+ einfo "Packages containing binaries and libraries $HEAD_TEXT"
+ einfo "will be emerged."
+}
+
+get_files() {
+ einfo "Collecting system binaries and libraries"
+ if [[ -r "$FILES_FILE" && -s "$FILES_FILE" ]]; then
+ einfo "Found existing $FILES_FILE"
+ else
+ # Be safe and remove any extraneous temporary files
+ # Don't remove 0_env.rr - The first file in the array
+ rm -f "${FILES[@]:1}"
+
+ clean_trap "$FILES_FILE"
+
+ if [[ $SEARCH_DIRS_MASK ]]; then
+ findMask=($SEARCH_DIRS_MASK)
+ findMask="${findMask[@]/#/-o -path }"
+ findMask="( ${findMask#-o } ) -prune -o"
+ fi
+ # TODO: Check this
+ find ${SEARCH_DIRS[@]} $findMask -type f \( -executable -o \
+ -name '*.so' -o -name '*.so.*' -o -name '*.la' \) -print 2> /dev/null |
+ sort -u > "$FILES_FILE" ||
+ die $? "find failed to list binary files (This is a bug.)"
+ einfo "Generated new $FILES_FILE"
+ fi
+}
+get_ldpath() {
+ local COMPLETE_LD_LIBRARY_PATH
+ [[ $SEARCH_BROKEN && $FULL_LD_PATH ]] || return
+ einfo 'Collecting complete LD_LIBRARY_PATH'
+ if [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]]; then
+ einfo "Found existing $LDPATH_FILE."
+ else
+ clean_trap "$LDPATH_FILE"
+ # Ensure that the "trusted" lib directories are at the start of the path
+ COMPLETE_LD_LIBRARY_PATH=(
+ /lib*
+ /usr/lib*
+ $(sed '/^#/d;s/#.*$//' < /etc/ld.so.conf)
+ $(sed 's:/[^/]*$::' < "$FILES_FILE" | sort -ru)
+ )
+ IFS=':'
+ COMPLETE_LD_LIBRARY_PATH="${COMPLETE_LD_LIBRARY_PATH[*]}"
+ IFS="$OIFS"
+ echo "$COMPLETE_LD_LIBRARY_PATH" > "$LDPATH_FILE"
+ einfo "Generated new $LDPATH_FILE"
+ fi
+}
+main_checks() {
+ local target_file
+ local -a files
+ local i=0
+ local ldd_output
+ local ldd_status
+ local numFiles
+ local COMPLETE_LD_LIBRARY_PATH
+ if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
+ [[ -r "$LDPATH_FILE" && -s "$LDPATH_FILE" ]] ||
+ die 1 "Unable to find $LDPATH_FILE"
+ COMPLETE_LD_LIBRARY_PATH=$(<"$LDPATH_FILE")
+ fi
+ einfo "Checking dynamic linking $WORKING_TEXT"
+ if [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]]; then
+ einfo "Found existing $BROKEN_FILE."
+ else
+ clean_trap "$BROKEN_FILE" "$ERRORS_FILE"
+ files=($(<"$FILES_FILE"))
+ numFiles="${#files[@]}"
+ for target_file in "${files[@]}"; do
+ if [[ $target_file != *.la ]]; then
+ # Note: double checking seems to be faster than single with complete path
+ # (special add ons are rare).
+ ldd_output=$(ldd "$target_file" 2>> "$ERRORS_FILE" | sort -u)
+ ldd_status=$? # TODO: Check this for problems with sort
+ # HACK: if LD_LIBRARY_MASK is null or undefined grep -vF doesn't work
+ if grep -vF "${LD_LIBRARY_MASK:=$'\a'}" <<< "$ldd_output" |
+ grep -q "$SONAME_SEARCH"; then
+ if [[ $SEARCH_BROKEN && $FULL_LD_PATH ]]; then
+ if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" ldd "$target_file" 2>/dev/null |
+ grep -vF "$LD_LIBRARY_MASK" | grep -q "$SONAME_SEARCH"; then
+ # FIXME: I hate duplicating code
+ # Only build missing direct dependencies
+ MISSING_LIBS=$(
+ expr='s/[[:space:]]*\([^[:space:]]*\) => not found/\1/p'
+ sed -n "$expr" <<< "$ldd_output"
+ )
+ REQUIRED_LIBS=$(
+ expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
+ objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
+ )
+ MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
+ if [[ $MISSING_LIBS ]]; then
+ echo "obj $target_file" >> "$BROKEN_FILE"
+ echo_v " broken $target_file (requires $MISSING_LIBS)"
+ fi
+ fi
+ else
+ # FIXME: I hate duplicating code
+ # Only rebuild for direct dependencies
+ MISSING_LIBS=$(
+ expr="/$SONAME_SEARCH/s/^[[:space:]]*\([^[:space:]]*\).*$/\1/p"
+ sort -u <<< "$ldd_output" | sed -n "$expr"
+ )
+ REQUIRED_LIBS=$(
+ expr='s/^[[:space:]]*NEEDED[[:space:]]*\([^[:space:]]*\).*/\1/p';
+ objdump -x "$target_file" | grep NEEDED | sed "$expr" | sort -u
+ )
+ MISSING_LIBS=$(grep -F "$REQUIRED_LIBS" <<< "$MISSING_LIBS")
+ if [[ $MISSING_LIBS ]]; then
+ echo "obj $target_file" >> "$BROKEN_FILE"
+ if [[ $SEARCH_BROKEN ]]; then
+ echo_v " broken $target_file (requires $MISSING_LIBS)"
+ else
+ echo_v " found $target_file"
+ fi
+ fi
+ fi
+ fi
+ elif [[ $SEARCH_BROKEN ]]; then
+ # Look for broken .la files
+ for depend in $(
+ awk -F"[=']" '/^dependency_libs/{
+ gsub("^-[^[:space:]]*", "", $3);
+ gsub("[[:space:]]-[^[:space:]]*", "", $3);
+ print $3
+ }' "$target_file"
+ ); do
+ if [[ $depend = /* && ! -e $depend ]]; then
+ echo "obj $target_file" >> "$BROKEN_FILE"
+ echo_v " broken $target_file (requires $depend)"
+ fi
+ done
+ fi
+ [[ $VERBOSE ]] &&
+ progress $((++i)) $numFiles $target_file ||
+ progress $((++i)) $numFiles
+ done
+ if [[ $SEARCH_BROKEN ]]; then
+ # Look for missing version
+ while read target_file; do
+ echo "obj $target_file" >> "$BROKEN_FILE"
+ echo_v " broken $target_file (no version information available)"
+ done < <(
+ # Regexify LD_LIBRARY_MASK. Exclude it from the search.
+ LD_LIBRARY_MASK="${LD_LIBRARY_MASK//$'\n'/|}"
+ awk -v ldmask="(${LD_LIBRARY_MASK//./\\\.})" '
+ /no version information available/ && $0 !~ ldmask {
+ gsub(/[()]/, "", $NF)
+ if (seen[$NF]++) next
+ print $NF
+ }' "$ERRORS_FILE"
+ )
+ fi
+ [[ -r "$BROKEN_FILE" && -s "$BROKEN_FILE" ]] || clean_exit
+ sort -u "$BROKEN_FILE" -o "$BROKEN_FILE"
+ einfo "Generated new $BROKEN_FILE"
+ fi
+}
+get_packages() {
+ local target_file
+ local EXACT_PKG
+ local PKG
+ local obj
+ einfo 'Assigning files to packages'
+ if [[ -r "$RAW_FILE" && -s "$RAW_FILE" ]]; then
+ einfo "Found existing $RAW_FILE"
+ else
+ clean_trap "$RAW_FILE" "$OWNERS_FILE"
+ while read obj target_file; do
+ EXACT_PKG=$(get_file_owner $target_file)
+ if [[ $EXACT_PKG ]]; then
+ # Strip version information
+ PKG="${EXACT_PKG%%-r[[:digit:]]*}"
+ PKG="${PKG%-*}"
+ echo "$EXACT_PKG" >> "$RAW_FILE"
+ echo "$target_file -> $EXACT_PKG" >> "$OWNERS_FILE"
+ echo_v " $target_file -> $PKG"
+ else
+ ewarn " !!! $target_file not owned by any package is broken !!!"
+ echo "$target_file -> (none)" >> "$OWNERS_FILE"
+ echo_v " $target_file -> (none)"
+ fi
+ done < "$BROKEN_FILE"
+ einfo "Generated new $RAW_FILE and $OWNERS_FILE"
+ fi
+ # if we find '(none)' on every line, exit out
+ if ! grep -qvF '(none)' "$OWNERS_FILE"; then
+ ewarn "Found some broken files, but none of them were associated with known packages"
+ ewarn "Unable to proceed with automatic repairs."
+ ewarn "The broken files are listed in $OWNERS_FILE"
+ if [[ $VERBOSE ]]; then
+ ewarn "The broken files are:"
+ while read filename junk; do
+ ewarn " $filename"
+ done < "$OWNERS_FILE"
+ fi
+ exit 0 # FIXME: Should we exit 1 here?
+ fi
+}
+clean_packages() {
+ einfo 'Cleaning list of packages to rebuild'
+ if [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
+ einfo "Found existing $PKGS_FILE"
+ else
+ sort -u "$RAW_FILE" > "$PKGS_FILE"
+ einfo "Generated new $PKGS_FILE"
+ fi
+}
+assign_packages_to_ebuilds() {
+ local EXACT_PKG
+ local PKG
+ local SLOT
+ einfo 'Assigning packages to ebuilds'
+ if [[ -r "$EBUILDS_FILE" && -s "$EBUILDS_FILE" ]]; then
+ einfo "Found existing $EBUILDS_FILE"
+ elif [[ -r "$PKGS_FILE" && -s "$PKGS_FILE" ]]; then
+ clean_trap "$EBUILDS_FILE"
+ while read EXACT_PKG; do
+ # Get the slot
+ PKG="${EXACT_PKG%%-r[[:digit:]]*}"
+ PKG="${PKG%-*}"
+ SLOT=$(</var/db/pkg/$EXACT_PKG/SLOT)
+ echo "$PKG:$SLOT"
+ done < "$PKGS_FILE" > "$EBUILDS_FILE"
+ einfo "Generated new $EBUILDS_FILE"
+ else
+ einfo 'Nothing to rebuild.'
+ die 1 '(The program should have already quit, so this is a minor bug.)'
+ fi
+}
+get_exact_ebuilds() {
+ einfo 'Assigning files to ebuilds'
+ if [[ -r $EBUILDS_FILE && -s $EBUILDS_FILE ]]; then
+ einfo "Found existing $EBUILDS_FILE"
+ elif [[ -r $BROKEN_FILE && -s $BROKEN_FILE ]]; then
+ rebuildList=" $(<"$BROKEN_FILE") "
+ rebuildList=(${rebuildList//[[:space:]]obj[[:space:]]/ })
+ get_file_owner "${rebuildList[@]}" | sed 's/^/=/' > "$EBUILDS_FILE"
+ einfo "Generated new $EBUILDS_FILE"
+ else
+ einfo 'Nothing to rebuild.'
+ die 1 '(The program should have already quit, so this is a minor bug.)'
+ fi
+}
+list_skipped_packages() {
+ ewarn
+ ewarn 'Portage could not find any version of the following packages it could build:'
+ ewarn "${SKIP_LIST[@]}"
+ ewarn
+ ewarn '(Perhaps they are masked, blocked, or removed from portage.)'
+ ewarn 'Try to emerge them manually.'
+ ewarn
+}
+get_build_order() {
+ local -r OLD_EMERGE_DEFAULT_OPTS="$EMERGE_DEFAULT_OPTS"
+ local RAW_REBUILD_LIST
+ local REBUILD_GREP
+ local i
+ if [[ ! $ORDER_PKGS ]]; then
+ einfo 'Skipping package ordering'
+ return
+ fi
+ einfo 'Evaluating package order'
+ if [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]]; then
+ einfo "Found existing $ORDER_FILE"
+ else
+ clean_trap "$ORDER_FILE"
+ RAW_REBUILD_LIST=$(<"$EBUILDS_FILE")
+ if [[ $RAW_REBUILD_LIST ]]; then
+ export EMERGE_DEFAULT_OPTS="--nospinner --pretend --oneshot --quiet"
+ RAW_REBUILD_LIST=($RAW_REBUILD_LIST) # convert into array
+ # If PACKAGE_NAMES is defined we're using slots, not versions
+ if [[ $PACKAGE_NAMES ]]; then
+ # Eliminate atoms that can't be built
+ for i in "${!RAW_REBUILD_LIST[@]}"; do
+ if [[ "${RAW_REBUILD_LIST[i]}" = *[A-Za-z]* ]]; then
+ portageq best_visible "$PORTAGE_ROOT" "${RAW_REBUILD_LIST[i]}" >/dev/null && continue
+ SKIP_LIST+=("${RAW_REBUILD_LIST[i]}")
+ fi
+ unset RAW_REBUILD_LIST[i]
+ done
+ # If RAW_REBUILD_LIST is empty, then we have nothing to build.
+ if (( ${#RAW_REBUILD_LIST[@]} == 0 )); then
+ if (( ${#SKIP_LIST[@]} == 0 )); then
+ ewarn "The list of packages to skip is empty, but there are no"
+ ewarn "packages listed to rebuild either. (This is a bug.)"
+ else
+ list_skipped_packages
+ fi
+ die 1 'Warning: Portage cannot rebuild any of the necessary packages.'
+ fi
+ fi
+ RAW_REBUILD_LIST="${RAW_REBUILD_LIST[@]}"
+ REBUILD_GREP=$(emerge --nodeps $RAW_REBUILD_LIST | sed 's/\[[^]]*\]//g')
+ if (( ${PIPESTATUS[0]} == 0 )); then
+ emerge --deep $RAW_REBUILD_LIST |
+ sed 's/\[[^]]*\]//g' |
+ grep -F "$REBUILD_GREP" > "$ORDER_FILE"
+ fi
+
+ # Here we use the PIPESTATUS from the second emerge, the --deep one.
+ if (( ${PIPESTATUS[0]} != 0 )); then
+ eerror
+ eerror 'Warning: Failed to resolve package order.'
+ eerror 'Will merge in arbitrary order'
+ eerror
+ cat <<- EOF
+ Possible reasons:
+ - An ebuild is no longer in the portage tree.
+ - An ebuild is masked, use /etc/portage/packages.keyword
+ and/or /etc/portage/package.unmask to unmask it
+ EOF
+ countdown 5
+ rm -f "$ORDER_FILE"
+ fi
+ export EMERGE_DEFAULT_OPTS="$OLD_EMERGE_DEFAULT_OPTS"
+ else
+ einfo 'Nothing to rebuild.'
+ die 1 '(The program should have already quit, so this is a minor bug.)'
+ fi
+ fi
+ [[ -r "$ORDER_FILE" && -s "$ORDER_FILE" ]] && einfo "Generated new $ORDER_FILE"
+}
+
+show_unowned_files() {
+ if grep -qF '(none)' "$OWNERS_FILE"; then
+ ewarn "Found some broken files that weren't associated with known packages"
+ ewarn "The broken files are:"
+ while read filename junk; do
+ [[ $junk = *none* ]] && ewarn " $filename"
+ done < "$OWNERS_FILE" | awk '!s[$0]++' # (omit dupes)
+ fi
+}
+##
+# Setup portage and the search paths
+setup_portage() {
+ local PORTAGE_NICENESS=$(portageq envvar PORTAGE_NICENESS)
+ PORTAGE_ROOT=$(portageq envvar ROOT)
+
+ # Obey PORTAGE_NICENESS
+ if [[ $PORTAGE_NICENESS ]]; then
+ renice $PORTAGE_NICENESS $$ > /dev/null
+ # Since we have already set our nice value for our processes,
+ # reset PORTAGE_NICENESS to zero to avoid having emerge renice again.
+ export PORTAGE_NICENESS="0"
+ fi
+
+ PORTAGE_ROOT="${PORTAGE_ROOT:-/}"
+}
+
+##
+# Setup the paths to search (and filter the ones to avoid)
+setup_search_paths_and_masks() {
+ local configfile sdir mdir skip_me filter_SEARCH_DIRS
+
+ einfo "Configuring search environment for $APP_NAME"
+
+ # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf,
+ # portage, and the environment
+
+ # Read the incremental variables from environment and portage
+ # Until such time as portage supports these variables as incrementals
+ # The value will be what is in /etc/make.conf
+ SEARCH_DIRS+=" "$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS)
+ SEARCH_DIRS_MASK+=" "$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK)
+ LD_LIBRARY_MASK+=" "$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK)
+
+ # Add the defaults
+ if [[ -d /etc/revdep-rebuild ]]; then
+ for configfile in /etc/revdep-rebuild/*; do
+ SEARCH_DIRS+=" "$(. $configfile; echo $SEARCH_DIRS)
+ SEARCH_DIRS_MASK+=" "$(. $configfile; echo $SEARCH_DIRS_MASK)
+ LD_LIBRARY_MASK+=" "$(. $configfile; echo $LD_LIBRARY_MASK)
+ done
+ else
+ SEARCH_DIRS+=" /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
+ SEARCH_DIRS_MASK+=" /opt/OpenOffice /usr/lib/openoffice"
+ LD_LIBRARY_MASK+=" libodbcinst.so libodbc.so libjava.so libjvm.so"
+ fi
+
+ # Get the ROOTPATH and PATH from /etc/profile.env
+ if [[ -r "/etc/profile.env" && -s "/etc/profile.env" ]]; then
+ SEARCH_DIRS+=" "$(. /etc/profile.env; /usr/bin/tr ':' ' ' <<< "$ROOTPATH $PATH")
+ fi
+
+ # Get the directories from /etc/ld.so.conf
+ if [[ -r /etc/ld.so.conf && -s /etc/ld.so.conf ]]; then
+ SEARCH_DIRS+=" "$(sed '/^#/d;s/#.*$//' /etc/ld.so.conf)
+ fi
+
+ # Set the final variables
+ SEARCH_DIRS=$(clean_var <<< "$SEARCH_DIRS")
+ SEARCH_DIRS_MASK=$(clean_var <<< "$SEARCH_DIRS_MASK")
+ LD_LIBRARY_MASK=$(clean_var <<< "$LD_LIBRARY_MASK")
+ # Filter masked paths from SEARCH_DIRS
+ for sdir in ${SEARCH_DIRS} ; do
+ skip_me=
+ for mdir in ${SEARCH_DIRS_MASK}; do
+ [[ ${sdir} == ${mdir}/* ]] && skip_me=1 && break
+ done
+ [[ -n ${skip_me} ]] || filter_SEARCH_DIRS+=" ${sdir}"
+ done
+ SEARCH_DIRS=$(clean_var <<< "${filter_SEARCH_DIRS}")
+ [[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug."
+}
+##
+# Rebuild packages owning broken binaries
+rebuild() {
+ if [[ -r $LIST.5_order && -s $LIST.5_order ]]; then
+ REBUILD_LIST=( $(<"$LIST.5_order") )
+ REBUILD_LIST="${REBUILD_LIST[@]/#/=}"
+ else
+ REBUILD_LIST=$(sort -u "$EBUILDS_FILE")
+ fi
+
+ trap - SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+
+ einfo 'All prepared. Starting rebuild'
+ echo "emerge --oneshot ${EMERGE_OPTIONS[@]} $REBUILD_LIST"
+
+ is_real_merge && countdown 10
+
+ # Link file descriptor #6 with stdin so --ask will work
+ exec 6<&0
+
+ # Run in background to correctly handle Ctrl-C
+ {
+ EMERGE_DEFAULT_OPTS="--oneshot ${EMERGE_OPTIONS[@]}" emerge $REBUILD_LIST <&6
+ echo $? > "$STATUS_FILE"
+ } &
+ wait
+
+ # Now restore stdin from fd #6, where it had been saved, and close fd #6 ( 6<&- ) to free it for other processes to use.
+ exec 0<&6 6<&-
+}
+##
+# Finish up
+cleanup() {
+ if (( $(<"$STATUS_FILE") != 0 )); then
+ ewarn
+ ewarn "$APP_NAME failed to emerge all packages."
+ ewarn 'you have the following choices:'
+ einfo "- If emerge failed during the build, fix the problems and re-run $APP_NAME."
+ einfo '- Use /etc/portage/package.keywords to unmask a newer version of the package.'
+ einfo " (and remove $ORDER_FILE to be evaluated again)"
+ einfo '- Modify the above emerge command and run it manually.'
+ einfo '- Compile or unmerge unsatisfied packages manually,'
+ einfo ' remove temporary files, and try again.'
+ einfo ' (you can edit package/ebuild list first)'
+ einfo
+ einfo 'To remove temporary files, please run:'
+ einfo "rm ${WORKING_DIR}/*.rr"
+ show_unowned_files
+ exit $EMERGE_STATUS
+ elif is_real_merge; then
+ trap_cmd() {
+ eerror "terminated. Please remove the temporary files manually:"
+ eerror "rm ${WORKING_DIR}/*.rr"
+ exit 1
+ }
+ [[ "${SKIP_LIST[@]}" != "" ]] && list_skipped_packages
+ trap trap_cmd SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
+ einfo 'Build finished correctly. Removing temporary files...'
+ einfo
+ einfo 'You can re-run revdep-rebuild to verify that all libraries and binaries'
+ einfo 'are fixed. If some inconsistency remains, it can be orphaned file, deep'
+ einfo 'dependency, binary package or specially evaluated library.'
+ if [[ -r "$OWNERS_FILE" && -s "$OWNERS_FILE" ]]; then
+ show_unowned_files
+ fi
+ [[ $KEEP_TEMP ]] || rm "${FILES[@]}"
+ else
+ einfo 'Now you can remove -p (or --pretend) from arguments and re-run revdep-rebuild.'
+ fi
+}
+
+main "$@"
diff --git a/trunk/src/99gentoolkit-env b/data/99gentoolkit-env
index 3933874..3933874 100644
--- a/trunk/src/99gentoolkit-env
+++ b/data/99gentoolkit-env
diff --git a/trunk/src/eclean/distfiles.exclude b/data/eclean/distfiles.exclude
index a31be55..a31be55 100644
--- a/trunk/src/eclean/distfiles.exclude
+++ b/data/eclean/distfiles.exclude
diff --git a/trunk/src/eclean/packages.exclude b/data/eclean/packages.exclude
index 8277155..8277155 100644
--- a/trunk/src/eclean/packages.exclude
+++ b/data/eclean/packages.exclude
diff --git a/trunk/src/revdep-rebuild/99revdep-rebuild b/data/revdep-rebuild/99revdep-rebuild
index bdaecc7..bdaecc7 100644
--- a/trunk/src/revdep-rebuild/99revdep-rebuild
+++ b/data/revdep-rebuild/99revdep-rebuild
diff --git a/trunk/src/eclean/eclean.1 b/man/eclean.1
index 7d785af..7d785af 100644
--- a/trunk/src/eclean/eclean.1
+++ b/man/eclean.1
diff --git a/trunk/src/epkginfo/epkginfo.1 b/man/epkginfo.1
index cefe602..cefe602 100644
--- a/trunk/src/epkginfo/epkginfo.1
+++ b/man/epkginfo.1
diff --git a/trunk/src/equery/equery.1 b/man/equery.1
index 27b8078..27b8078 100644
--- a/trunk/src/equery/equery.1
+++ b/man/equery.1
diff --git a/trunk/src/eread/eread.1 b/man/eread.1
index 5e18214..5e18214 100644
--- a/trunk/src/eread/eread.1
+++ b/man/eread.1
diff --git a/trunk/src/euse/euse.1 b/man/euse.1
index b5148fd..b5148fd 100644
--- a/trunk/src/euse/euse.1
+++ b/man/euse.1
diff --git a/trunk/src/genpkgindex/genpkgindex.1 b/man/genpkgindex.1
index 8a3956e..8a3956e 100644
--- a/trunk/src/genpkgindex/genpkgindex.1
+++ b/man/genpkgindex.1
diff --git a/man/glsa-check.1 b/man/glsa-check.1
new file mode 100644
index 0000000..5a7a525
--- /dev/null
+++ b/man/glsa-check.1
@@ -0,0 +1,57 @@
+.TH "glsa-check" "1" "0.6" "Marius Mauch" "gentoolkit"
+.SH "NAME"
+.LP
+glsa\-check \- Gentoo: Tool to locally monitor and manage GLSA's
+.SH "SYNTAX"
+.LP
+glsa\-check <\fIoption\fP> [\fIglsa\-list\fP]
+
+[\fIglsa\-list\fR] can contain an arbitrary number of GLSA ids, filenames containing GLSAs or the special identifiers 'all', 'new' and 'affected'
+.SH "DESCRIPTION"
+.LP
+This tool is used to locally monitor and manage Gentoo Linux Security Advisories.
+Please read:
+.br
+http://www.gentoo.org/proj/en/portage/glsa\-integration.xml
+.br
+before reporting a bug.
+.LP
+Note: In order for this tool to be effective, you must regularly sync your local portage tree.
+.SH "OPTIONS"
+.LP
+.TP
+.B \-l, \-\-list
+list all unapplied GLSA
+.TP
+.B \-d, \-\-dump, \-\-print
+show all information about the given GLSA
+.TP
+.B \-t, \-\-test
+test if this system is affected by the given GLSA
+.TP
+.B \-p, \-\-pretend
+show the necessary commands to apply this GLSA
+.TP
+.B \-f, \-\-fix
+try to auto\-apply this GLSA (experimental)
+.TP
+.B \-i, \-\-inject
+inject the given GLSA into the checkfile
+.TP
+.B \-n, \-\-nocolor
+disable colors (option)
+.TP
+.B \-h, \-\-help
+show this help message
+.TP
+.B \-V, \-\-version
+some information about this tool
+.TP
+.B \-v, \-\-verbose
+print more messages (option)
+.TP
+.B \-c, \-\-cve
+show CAN ids in listing mode (option)
+.TP
+.B \-m, \-\-mail
+send a mail with the given GLSAs to the administrator
diff --git a/man/revdep-rebuild.1 b/man/revdep-rebuild.1
new file mode 100644
index 0000000..267f7f1
--- /dev/null
+++ b/man/revdep-rebuild.1
@@ -0,0 +1,101 @@
+.TH "revdep\-rebuild" "1" "" "gentoolkit" ""
+.SH "NAME"
+revdep\-rebuild \- Gentoo: Reverse Dependency Rebuilder
+.SH "SYNOPSIS"
+.B revdep\-rebuild
+[OPTIONS] [\-\-] [EMERGE OPTIONS]
+.SH "DESCRIPTION"
+revdep\-rebuild scans libraries and binaries for missing shared library dependencies and attempts to fix them by re\-emerging those broken binaries and shared libraries. It is useful when an upgraded package breaks other software packages that are dependent upon the upgraded package.
+.SH "OPTIONS"
+.TP
+.B \-C | \-\-nocolor
+Turn off colored output. (This option is also passed to portage.)
+.TP
+.B \-e | \-\-exact
+Emerge the most recent version of found packages, without regard to SLOT.
+.TP
+.B \-h | \-\-help
+Print usage.
+.TP
+.B \-i | \-\-ignore
+Delete temporary files from previous runs.
+.TP
+.B \-k | \-\-keep\-temp
+Force revdep\-rebuild not to delete temporary files after it successfully rebuilds packages. This option will NOT prevent revdep\-rebuild from deleting inconsistent or out\-of\-date temporary files.
+.TP
+.B \-\-library NAME | -L NAME
+Search for reverse dependencies for a particular library or group of libraries, rather than every library on the system. Emerge packages that use the named library. NAME can be a full path to a library or basic regular expression. (See regex(7).)
+.TP
+.B \-l | \-\-no\-ld\-path
+Do not set LD_LIBRARY_PATH. \fBNote:\fR Using this option will cause revdep-rebuild to report some false positives.
+.TP
+.B \-o | \-\-no-order
+Do not check the build order against the deep dependency list. This will make revdep-rebuild faster, but it can cause emerge failures. Please try revdep\-rebuild without \-o before reporting any bugs.
+.TP
+.B \-p | \-\-pretend
+Do a dry-run. Do not delete temporary files. (\-k \-p is redundant, but harmless.) \-\-pretend is assumed when not running revdep\-rebuild as root.
+.TP
+.B \-P | \-\-no\-progress
+Turn off the progress meter
+.TP
+.B \-q | \-\-quiet
+Print less output and disable the progress meter. (This option is also passed to portage.)
+.TP
+.B \-u UTIL | \-\-no-util UTIL
+Do not use features provided by UTIL.
+UTIL can be one of portage-utils or pkgcore, or it can be a \fBquoted\fR space-delimited list.
+.TP
+.B \-v | \-\-verbose
+More output. (Prints the revdep\-rebuild search environment.)
+.TP
+.B All other options (including unrecognized ones) are passed to the emerge command. Single\-letter options may not be combined, so for example, \-pv is not valid. Please use \-p \-v.
+.SH "CONFIGURATION"
+revdep\-rebuild no longer uses hardcoded paths. To change the default behavior the following variables can be changed by the user.
+
+LD_LIBRARY_MASK \- Mask of specially evaluated libraries
+.LP
+SEARCH_DIRS \- List of directories to search for executables and libraries
+.LP
+SEARCH_DIRS_MASK \- List of directories to not search
+
+You can prepend to these variables by setting the variable in your environment prior to execution, by placing an entry in /etc/make.conf, or by placing a file in /etc/revdep\-rebuild containing the appropriate variables.
+
+The variables are read and set in the following order:
+
+environment settings \- one time changes by user
+.br
+/etc/make.conf \- persistent changes by user
+.br
+/etc/revdep\-rebuild/* \- persistent changes by ebuild authors
+
+While a user can edit and modify the files in the /etc/revdep\-rebuild directory, please be aware that the /etc/revdep\-rebuild directory is not under configuration protection and files can be removed and/or overwritten by an ebuild. To change this add /etc/revdep\-rebuild to the CONFIG_PROTECT variable in /etc/make.conf.
+
+An entry of "\-*" means to clear the variable from that point forward.
+Example: SEARCH_DIRS="/usr/bin \-*" will set SEARCH_DIRS to contain only /usr/bin
+
+revdep\-rebuild honors the NOCOLOR and PORTAGE_NICENESS variables from /etc/make.conf
+.SH "EXAMPLES"
+It is recommended that when running revdep\-rebuild that the following command be used initially:
+.br
+\fBrevdep\-rebuild \-\-ignore \-\-pretend\fR
+
+To search the entire system, while excluding /mnt and /home:
+.br
+\fBenv SEARCH_DIRS="/ \-*" SEARCH_DIRS_MASK="/mnt /home" revdep\-rebuild\fR
+
+To rebuild packages that depend on libkdecore.so.4 from KDE 3.3:
+.br
+\fBrevdep\-rebuild \-\-library /usr/kde/3.3/lib/libkdecore.so.4\fR
+
+To rebuild packages that depend upon libImlib.so and libImlib2.so:
+.br
+\fBrevdep\-rebuild \-\-library libImlib[2]*.so.*\fR
+
+.SH "EXIT STATUS"
+revdep\-rebuild returns a zero exit status if it \fBand emerge\fR succeeds, and a nonzero exit status otherwise.
+.SH "BUGS"
+.LP
+Report bugs to <http://bugs.gentoo.org>. Please do not report emerge failures caused by \-o or \-e. Please include your .revdep\-rebuild* files, your emerge \-\-info, and patches. ;)
+
+.SH "SEE ALSO"
+emerge(1), portage(5), regex(7)
diff --git a/pym/gentoolkit/__init__.py b/pym/gentoolkit/__init__.py
new file mode 100644
index 0000000..62e359b
--- /dev/null
+++ b/pym/gentoolkit/__init__.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+#
+# Copyright 2003-2004 Karl Trygve Kalleberg
+# Copyright 2003-2009 Gentoo Technologies, Inc.
+# Distributed under the terms of the GNU General Public License v2
+#
+# $Header$
+
+__author__ = "Karl Trygve Kalleberg"
+__productname__ = "gentoolkit"
+__description__ = "Gentoolkit Common Library"
+
+import os
+import sys
+try:
+ import portage
+except ImportError:
+ sys.path.insert(0, "/usr/lib/portage/pym")
+ import portage
+import re
+try:
+ from threading import Lock
+except ImportError:
+ # If we don't have thread support, we don't need to worry about
+ # locking the global settings object. So we define a "null" Lock.
+ class Lock:
+ def acquire(self):
+ pass
+ def release(self):
+ pass
+
+try:
+ import portage.exception as portage_exception
+except ImportError:
+ import portage_exception
+
+try:
+ settingslock = Lock()
+ settings = portage.config(clone=portage.settings)
+ porttree = portage.db[portage.root]["porttree"]
+ vartree = portage.db[portage.root]["vartree"]
+ virtuals = portage.db[portage.root]["virtuals"]
+except portage_exception.PermissionDenied, e:
+ sys.stderr.write("Permission denied: '%s'\n" % str(e))
+ sys.exit(e.errno)
+
+Config = {
+ "verbosityLevel": 3
+}
+
+from helpers import *
+from package import *
diff --git a/pym/gentoolkit/equery/__init__.py b/pym/gentoolkit/equery/__init__.py
new file mode 100644
index 0000000..6bb04a9
--- /dev/null
+++ b/pym/gentoolkit/equery/__init__.py
@@ -0,0 +1,407 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header: $
+
+"""Gentoo package query tool"""
+
+# Move to Imports section after Python 2.6 is stable
+from __future__ import with_statement
+
+__all__ = (
+ 'format_options',
+ 'format_package_names',
+ 'mod_usage'
+)
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import errno
+import sys
+import time
+from getopt import getopt, GetoptError
+
+import gentoolkit
+import gentoolkit.pprinter as pp
+from gentoolkit import catpkgsplit, settings, Package, Config
+from gentoolkit.textwrap_ import TextWrapper
+
+__productname__ = "equery"
+__authors__ = """\
+Karl Trygve Kalleberg - Original author
+Douglas Anderson - Modular redesign; author of meta, changes"""
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @param with_description (bool): Option to print module's __doc__ or not
+ """
+
+ if with_description:
+ print __doc__
+ print main_usage()
+ print
+ print pp.globaloption("global options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -q, --quiet", "minimal output"),
+ (" -C, --no-color", "turn off colors"),
+ (" -N, --no-pipe", "turn off pipe detection"),
+ (" -V, --version", "display version info")
+ ))
+ print
+ print pp.command("modules") + " (" + pp.command("short name") + ")"
+ print format_options((
+ (" (b)elongs", "list what package FILES belong to"),
+ (" (c)hanges", "list changelog entries for PKG"),
+ (" chec(k)", "verify checksums and timestamps for PKG"),
+ (" (d)epends", "list all packages directly depending on PKG"),
+ (" dep(g)raph", "display a tree of all dependencies for PKG"),
+ (" (f)iles", "list all files installed by PKG"),
+ (" (h)asuse", "list all packages that have USE flag"),
+ (" (l)ist", "list package matching PKG"),
+ (" (m)eta", "display metadata about PKG"),
+ (" (s)ize", "display total size of all files owned by PKG"),
+ (" (u)ses", "display USE flags for PKG"),
+ (" (w)hich", "print full path to ebuild for PKG")
+ ))
+
+
+def expand_module_name(module_name):
+ """Returns one of the values of name_map or raises KeyError"""
+
+ name_map = {
+ 'b': 'belongs',
+ 'c': 'changes',
+ 'k': 'check',
+ 'd': 'depends',
+ 'g': 'depgraph',
+ 'f': 'files',
+ 'h': 'hasuse',
+ 'l': 'list_',
+ 'm': 'meta',
+ 's': 'size',
+ 'u': 'uses',
+ 'w': 'which'
+ }
+
+ if module_name == 'list':
+ # list is a Python builtin type, so we must rename our module
+ return 'list_'
+ elif module_name in name_map.values():
+ return module_name
+ else:
+ return name_map[module_name]
+
+
+def format_options(options):
+ """Format module options.
+
+ @type options: list
+ @param options: [('option 1', 'description 1'), ('option 2', 'des... )]
+ @rtype: str
+ @return: formatted options string
+ """
+
+ result = []
+ twrap = TextWrapper(width=Config['termWidth'])
+ opts = (x[0] for x in options)
+ descs = (x[1] for x in options)
+ for opt, desc in zip(opts, descs):
+ twrap.initial_indent = pp.emph(opt.ljust(25))
+ twrap.subsequent_indent = " " * 25
+ result.append(twrap.fill(desc))
+
+ return '\n'.join(result)
+
+
+def format_package_names(match_set, status):
+ """Add location and mask status to package names.
+
+ @type match_set: list of gentoolkit.package.Package
+ @param match_set: packages to format
+ @rtype: list
+ @return: formatted packages
+ """
+
+ arch = gentoolkit.settings["ARCH"]
+ formatted_packages = []
+ pfxmodes = ['---', 'I--', '-P-', '--O']
+ maskmodes = [' ', ' ~', ' -', 'M ', 'M~', 'M-']
+
+ for pkg in match_set:
+ mask = get_mask_status(pkg, arch)
+ pkgcpv = pkg.get_cpv()
+ slot = pkg.get_env_var("SLOT")
+
+ formatted_packages.append("[%s] [%s] %s (%s)" %
+ (pfxmodes[status],
+ pp.maskflag(maskmodes[mask]),
+ pp.cpv(pkgcpv),
+ str(slot)))
+
+ return formatted_packages
+
+
+def format_filetype(path, fdesc, show_type=False, show_md5=False,
+ show_timestamp=False):
+ """Format a path for printing.
+
+ @type path: str
+ @param path: the path
+ @type fdesc: list
+ @param fdesc: [file_type, timestamp, MD5 sum/symlink target]
+ file_type is one of dev, dir, obj, sym.
+ If file_type is dir, there is no timestamp or MD5 sum.
+ If file_type is sym, fdesc[2] is the target of the symlink.
+ @type show_type: bool
+ @param show_type: if True, prepend the file's type to the formatted string
+ @type show_md5: bool
+ @param show_md5: if True, append MD5 sum to the formatted string
+ @type show_timestamp: bool
+ @param show_timestamp: if True, append time-of-creation after pathname
+ @rtype: str
+ @return: formatted pathname with optional added information
+ """
+
+ ftype = fpath = stamp = md5sum = ""
+
+ if fdesc[0] == "obj":
+ ftype = "file"
+ fpath = path
+ stamp = format_timestamp(fdesc[1])
+ md5sum = fdesc[2]
+ elif fdesc[0] == "dir":
+ ftype = "dir"
+ fpath = pp.path(path)
+ elif fdesc[0] == "sym":
+ ftype = "sym"
+ stamp = format_timestamp(fdesc[1])
+ tgt = fdesc[2].split()[0]
+ if Config["piping"]:
+ fpath = path
+ else:
+ fpath = pp.path_symlink(path + " -> " + tgt)
+ elif fdesc[0] == "dev":
+ ftype = "dev"
+ fpath = path
+ else:
+ pp.print_error("%s has unknown type: %s" % (path, fdesc[0]))
+
+ result = ""
+ if show_type:
+ result += "%4s " % ftype
+ result += fpath
+ if show_timestamp:
+ result += " " + stamp
+ if show_md5:
+ result += " " + md5sum
+
+ return result
+
+
+def format_timestamp(timestamp):
+ """Format a timestamp into, e.g., '2009-01-31 21:19:44' format"""
+
+ return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(timestamp)))
+
+
+def get_mask_status(pkg, arch):
+ """Get the mask status of a given package.
+
+ @type pkg: gentoolkit.package.Package
+ @param pkg: pkg to get mask status of
+ @type arch: str
+ @param arch: output of gentoolkit.settings["ARCH"]
+ @rtype: int
+ @return: an index for this list: [" ", " ~", " -", "M ", "M~", "M-"]
+ 0 = not masked
+ 1 = keyword masked
+ 2 = arch masked
+ 3 = hard masked
+ 4 = hard and keyword masked,
+ 5 = hard and arch masked
+ """
+
+ # Determining mask status
+ keywords = pkg.get_env_var("KEYWORDS").split()
+ mask_status = 0
+ if pkg.is_masked():
+ mask_status += 3
+ if ("~%s" % arch) in keywords:
+ mask_status += 1
+ elif ("-%s" % arch) in keywords or "-*" in keywords:
+ mask_status += 2
+
+ return mask_status
+
+
+def initialize_configuration():
+ """Setup the standard equery config"""
+
+ # Get terminal size
+ term_width = pp.output.get_term_size()[1]
+ if term_width == -1:
+ # get_term_size() failed. Set a sane default width:
+ term_width = 80
+
+ # Terminal size, minus a 1-char margin for text wrapping
+ Config['termWidth'] = term_width - 1
+
+ # Color handling: -1: Use Portage settings, 0: Force off, 1: Force on
+ Config['color'] = -1
+
+ # Guess color output
+ if (Config['color'] == -1 and (not sys.stdout.isatty() or
+ settings["NOCOLOR"] in ("yes", "true")) or
+ Config['color'] == 0):
+ pp.output.nocolor()
+
+ # Guess piping output
+ if not sys.stdout.isatty():
+ Config["piping"] = True
+ else:
+ Config["piping"] = False
+
+
+def main_usage():
+ """Print the main usage message for equery"""
+
+ return "%(usage)s %(product)s [%(g_opts)s] %(mod_name)s [%(mod_opts)s]" % {
+ 'usage': pp.emph("Usage:"),
+ 'product': pp.productname(__productname__),
+ 'g_opts': pp.globaloption("global-options"),
+ 'mod_name': pp.command("module-name"),
+ 'mod_opts': pp.localoption("module-options")
+ }
+
+
+def mod_usage(mod_name="module", arg="pkgspec", optional=False):
+ """Provide a consistant usage message to the calling module.
+
+ @type arg: string
+ @param arg: what kind of argument the module takes (pkgspec, filename, etc)
+ @type optional: bool
+ @param optional: is the argument optional?
+ """
+
+ return "%(usage)s: %(mod_name)s [%(opts)s] %(arg)s" % {
+ 'usage': pp.emph("Usage"),
+ 'mod_name': pp.command(mod_name),
+ 'opts': pp.localoption("options"),
+ 'arg': ("[%s]" % pp.emph(arg)) if optional else pp.emph(arg)
+ }
+
+
+def parse_global_options(global_opts, args):
+ """Parse global input args and return True if we should display help for
+ the called module, else False (or display help and exit from here).
+ """
+
+ need_help = False
+ opts = (opt[0] for opt in global_opts)
+ for opt in opts:
+ if opt in ('-h', '--help'):
+ if args:
+ need_help = True
+ else:
+ print_help()
+ sys.exit(0)
+ elif opt in ('-q','--quiet'):
+ Config["verbosityLevel"] = 0
+ elif opt in ('-C', '--no-color', '--nocolor'):
+ Config['color'] = 0
+ pp.output.nocolor()
+ elif opt in ('-N', '--no-pipe'):
+ Config["piping"] = False
+ elif opt in ('-V', '--version'):
+ print_version()
+ sys.exit(0)
+
+ return need_help
+
+
+def print_version():
+ """Print the version of this tool to the console."""
+
+ try:
+ with open('/etc/gentoolkit-version') as gentoolkit_version:
+ version = gentoolkit_version.read().strip()
+ except IOError, err:
+ pp.die(2, str(err))
+
+ print "%(product)s (%(version)s) - %(docstring)s" % {
+ "product": pp.productname(__productname__),
+ "version": version,
+ "docstring": __doc__
+ }
+ print
+ print __authors__
+
+
+def split_arguments(args):
+ """Separate module name from module arguments"""
+
+ return args.pop(0), args
+
+
+def main():
+ """Parse input and run the program."""
+
+ initialize_configuration()
+
+ short_opts = "hqCNV"
+ long_opts = ('help', 'quiet', 'nocolor', 'no-color', 'no-pipe', 'version')
+
+ try:
+ global_opts, args = getopt(sys.argv[1:], short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Global %s" % err)
+ print_help(with_description=False)
+ sys.exit(2)
+
+
+ # Parse global options
+ need_help = parse_global_options(global_opts, args)
+
+ try:
+ module_name, module_args = split_arguments(args)
+ except IndexError:
+ print_help()
+ sys.exit(2)
+
+ if need_help:
+ module_args.append('--help')
+
+ try:
+ expanded_module_name = expand_module_name(module_name)
+ except KeyError:
+ pp.print_error("Unknown module '%s'" % module_name)
+ print_help(with_description=False)
+ sys.exit(2)
+
+ try:
+ loaded_module = __import__(expanded_module_name, globals(),
+ locals(), [], -1)
+ loaded_module.main(module_args)
+ except ValueError, err:
+ if isinstance(err[0], list):
+ pp.print_error("Ambiguous package name. Use one of: ")
+ while err[0]:
+ print " " + err[0].pop()
+ else:
+ pp.print_error("Internal portage error, terminating")
+ if err:
+ pp.print_error(str(err[0]))
+ sys.exit(1)
+ except IOError, err:
+ if err.errno != errno.EPIPE:
+ raise
diff --git a/pym/gentoolkit/equery/belongs.py b/pym/gentoolkit/equery/belongs.py
new file mode 100644
index 0000000..6408ec7
--- /dev/null
+++ b/pym/gentoolkit/equery/belongs.py
@@ -0,0 +1,160 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header: $
+
+"""List all packages owning a particular file
+
+Note: Normally, only one package will own a file. If multiple packages own
+ the same file, it usually consitutes a problem, and should be reported.
+"""
+
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import re
+import sys
+from getopt import gnu_getopt, GetoptError
+
+import gentoolkit.pprinter as pp
+from gentoolkit.equery import format_filetype, format_options, mod_usage, \
+ Config
+from gentoolkit.helpers2 import get_installed_cpvs
+from gentoolkit.package import Package
+
+# =======
+# Globals
+# =======
+
+QUERY_OPTS = {
+ "fullRegex": False,
+ "earlyOut": False,
+ "nameOnly": False
+}
+
+# =========
+# Functions
+# =========
+
+def parse_module_options(module_opts):
+ """Parse module options and update GLOBAL_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ for opt in opts:
+ if opt in ('-h','--help'):
+ print_help()
+ sys.exit(0)
+ elif opt in ('-c', '--category'):
+ # Remove this warning after a reasonable amount of time
+ # (djanderson, 2/2009)
+ pp.print_warn("Module option -c, --category not implemented")
+ print
+ elif opt in ('-e', '--early-out', '--earlyout'):
+ if opt == '--earlyout':
+ pp.print_warn("Use of --earlyout is deprecated.")
+ pp.print_warn("Please use --early-out.")
+ print
+ QUERY_OPTS['earlyOut'] = True
+ elif opt in ('-f', '--full-regex'):
+ QUERY_OPTS['fullRegex'] = True
+ elif opt in ('-n', '--name-only'):
+ QUERY_OPTS['nameOnly'] = True
+
+
+def prepare_search_regex(queries):
+ """Create a regex out of the queries"""
+
+ if QUERY_OPTS["fullRegex"]:
+ result = queries
+ else:
+ result = []
+ # Trim trailing and multiple slashes from queries
+ slashes = re.compile('/+')
+ for query in queries:
+ query = slashes.sub('/', query).rstrip('/')
+ if query.startswith('/'):
+ query = "^%s$" % re.escape(query)
+ else:
+ query = "/%s$" % re.escape(query)
+ result.append(query)
+
+ result = "|".join(result)
+
+ return re.compile(result)
+
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print __doc__.strip()
+ print
+ print mod_usage(mod_name="belongs", arg="filename")
+ print
+ print pp.command("options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -f, --full-regex", "supplied query is a regex" ),
+ (" -e, --early-out", "stop when first match is found"),
+ (" -n, --name-only", "don't print the version")
+ ))
+
+
+def main(input_args):
+ """Parse input and run the program"""
+
+ # -c, --category is not implemented
+ short_opts = "hc:fen"
+ long_opts = ('help', 'category=', 'full-regex', 'early-out', 'earlyout',
+ 'name-only')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Module %s" % err)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ query_re = prepare_search_regex(queries)
+
+ if not Config["piping"]:
+ pp.print_info(3, " * Searching for %s ... "
+ % (pp.regexpquery(",".join(queries))))
+
+ matches = get_installed_cpvs()
+
+ # Print matches to screen or pipe
+ found_match = False
+ for pkg in [Package(x) for x in matches]:
+ files = pkg.get_contents()
+ for cfile in files:
+ if query_re.search(cfile):
+ if QUERY_OPTS["nameOnly"]:
+ pkg_str = pkg.key
+ else:
+ pkg_str = pkg.cpv
+ if Config['piping']:
+ print pkg_str
+ else:
+ file_str = pp.path(format_filetype(cfile, files[cfile]))
+ pp.print_info(0, "%s (%s)" % (pkg_str, file_str))
+
+ found_match = True
+
+ if found_match and QUERY_OPTS["earlyOut"]:
+ break
diff --git a/pym/gentoolkit/equery/changes.py b/pym/gentoolkit/equery/changes.py
new file mode 100644
index 0000000..b7644be
--- /dev/null
+++ b/pym/gentoolkit/equery/changes.py
@@ -0,0 +1,336 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2 or higher
+#
+# $Header: $
+
+"""Display the Gentoo ChangeLog entry for the latest installable version of a
+given package
+"""
+
+# Move to Imports sections when Python 2.6 is stable
+from __future__ import with_statement
+
+__author__ = 'Douglas Anderson'
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import os
+import sys
+from getopt import gnu_getopt, GetoptError
+
+from portage.versions import pkgsplit
+
+import gentoolkit.pprinter as pp
+from gentoolkit import errors
+from gentoolkit.equery import format_options, mod_usage
+from gentoolkit.helpers2 import find_best_match, find_packages
+from gentoolkit.package import Package, VersionMatch
+
+# =======
+# Globals
+# =======
+
+QUERY_OPTS = {
+ 'onlyLatest': False,
+ 'showFullLog': False,
+ 'limit': None,
+ 'from': None,
+ 'to': None
+}
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print __doc__.strip()
+ print
+ print mod_usage(mod_name="changes")
+ print
+ print pp.emph("examples")
+ print (" c portage # show latest visible "
+ "version's entry")
+ print " c portage --full --limit=3 # show 3 latest entries"
+ print " c '=sys-apps/portage-2.1.6*' # use atom syntax"
+ print " c portage --from=2.2_rc20 --to=2.2_rc30 # use version ranges"
+ print
+ print pp.command("options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -l, --latest", "display only the latest ChangeLog entry"),
+ (" -f, --full", "display the full ChangeLog"),
+ (" --limit=NUM",
+ "limit the number of entries displayed (with --full)"),
+ (" --from=VER", "set which version to display from"),
+ (" --to=VER", "set which version to display to"),
+ ))
+
+
+def get_logpath(pkg):
+ """Test that the package's ChangeLog path is valid and readable, else
+ die.
+
+ @type pkg: gentoolkit.package.Package
+ @param pkg: package to find logpath for
+ @rtype: str
+ @return: a path to a readable ChangeLog
+ """
+
+ logpath = os.path.join(pkg.get_package_path(), 'ChangeLog')
+ if not os.path.isfile(logpath) or not os.access(logpath, os.R_OK):
+ pp.die(1, "%s does not exist or is unreadable"
+ % pp.path(logpath))
+
+ return logpath
+
+
+def get_match(query):
+ """Find a valid package to get the ChangeLog path from or raise
+ GentoolkitNoMatches.
+ """
+
+ match = matches = None
+ match = find_best_match(query)
+
+ if not match:
+ matches = find_packages(query, include_masked=True)
+ else:
+ matches = [match]
+
+ if not matches:
+ pp.print_warn("Try using an unversioned query with "
+ "--from and --to.")
+ raise errors.GentoolkitNoMatches(query)
+
+ return matches[0]
+
+
+def index_changelog(entries):
+ """Convert the list from split_changelog into a dict with VersionMatch
+ instance as the index.
+
+ @todo: UPDATE THIS
+ @type entries: list
+ @param entries: output of split_changelog
+ @rtype: dict
+ @return: dict with gentoolkit.package.Package instances as keys and the
+ corresponding ChangeLog entree as its value
+ """
+
+ result = []
+ for entry in entries:
+ # Extract the package name from the entry, ex:
+ # *xterm-242 (07 Mar 2009) => xterm-242
+ pkg_name = entry.split(' ', 1)[0].lstrip('*')
+ pkg_split = pkgsplit(pkg_name)
+ result.append(
+ (VersionMatch(op="=", ver=pkg_split[1], rev=pkg_split[2]), entry))
+
+ return result
+
+
+def is_ranged(atom):
+ """Return True if an atom string appears to be ranged, else False."""
+
+ return atom.startswith(('~', '<', '>')) or atom.endswith('*')
+
+
+def parse_module_options(module_opts):
+ """Parse module options and update GLOBAL_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ('-h', '--help'):
+ print_help()
+ sys.exit(0)
+ elif opt in ('-f', '--full'):
+ QUERY_OPTS['showFullLog'] = True
+ elif opt in ('-l', '--latest'):
+ QUERY_OPTS['onlyLatest'] = True
+ elif opt in ('--limit',):
+ set_limit(posarg)
+ elif opt in ('--from',):
+ set_from(posarg)
+ elif opt in ('--to',):
+ set_to(posarg)
+
+
+def print_matching_entries(indexed_entries, pkg, first_run):
+ """Print only the entries which interect with the pkg version."""
+
+ from_restriction = QUERY_OPTS['from']
+ to_restriction = QUERY_OPTS['to']
+
+ for entry_set in indexed_entries:
+ i, entry = entry_set
+ # a little hackery, since versionmatch doesn't store the
+ # package key, but intersects checks that it matches.
+ i.key = pkg.key
+ if from_restriction or to_restriction:
+ if from_restriction and not from_restriction.match(i):
+ continue
+ if to_restriction and not to_restriction.match(i):
+ continue
+ elif not pkg.intersects(i):
+ continue
+
+ if not first_run:
+ print "\n"
+ print entry.strip()
+ first_run = False
+
+ return first_run
+
+
+def set_from(posarg):
+ """Set a starting version to filter the ChangeLog with or die if posarg
+ is not a valid version.
+ """
+
+ pkg_split = pkgsplit('null-%s' % posarg)
+
+ if pkg_split and not is_ranged(posarg):
+ ver_match = VersionMatch(
+ op=">=",
+ ver=pkg_split[1],
+ rev=pkg_split[2] if pkg_split[2] != 'r0' else '')
+ QUERY_OPTS['from'] = ver_match
+ else:
+ err = "Module option --from requires valid unranged version (got '%s')"
+ pp.print_error(err % posarg)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+
+def set_limit(posarg):
+ """Set a limit in QUERY_OPTS on how many ChangeLog entries to display or
+ die if posarg is not an integer.
+ """
+
+ if posarg.isdigit():
+ QUERY_OPTS['limit'] = int(posarg)
+ else:
+ err = "Module option --limit requires integer (got '%s')"
+ pp.print_error(err % posarg)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+
+def set_to(posarg):
+ """Set an ending version to filter the ChangeLog with or die if posarg
+ is not a valid version.
+ """
+
+ pkg_split = pkgsplit('null-%s' % posarg)
+ if pkg_split and not is_ranged(posarg):
+ ver_match = VersionMatch(
+ op="<=",
+ ver=pkg_split[1],
+ rev=pkg_split[2] if pkg_split[2] != 'r0' else '')
+ QUERY_OPTS['to'] = ver_match
+ else:
+ err = "Module option --to requires valid unranged version (got '%s')"
+ pp.print_error(err % posarg)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+
+def split_changelog(logpath):
+ """Split the changelog up into individual entries.
+
+ @type logpath: str
+ @param logpath: valid path to ChangeLog file
+ @rtype: list
+ @return: individual ChangeLog entrees
+ """
+
+ result = []
+ partial_entries = []
+ with open(logpath) as log:
+ for line in log:
+ if line.startswith('#'):
+ continue
+ elif line.startswith('*'):
+ # Append last entry to result...
+ entry = ''.join(partial_entries)
+ if entry and not entry.isspace():
+ result.append(entry)
+ # ... and start a new entry
+ partial_entries = [line]
+ else:
+ partial_entries.append(line)
+ else:
+ # Append the final entry
+ entry = ''.join(partial_entries)
+ result.append(entry)
+
+ return result
+
+
+def main(input_args):
+ """Parse input and run the program"""
+
+ short_opts = "hlf"
+ long_opts = ('help', 'full', 'from=', 'latest', 'limit=', 'to=')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Module %s" % err)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ first_run = True
+ for query in queries:
+ if not first_run:
+ print
+
+ ranged_query = None
+ if is_ranged(query):
+ # Raises GentoolkitInvalidCPV here if invalid
+ ranged_query = Package(query)
+
+ pkg = get_match(query)
+ logpath = get_logpath(pkg)
+ log_entries = split_changelog(logpath)
+ indexed_entries = index_changelog(log_entries)
+
+ #
+ # Output
+ #
+
+ if QUERY_OPTS['onlyLatest']:
+ print log_entries[0].strip()
+ elif QUERY_OPTS['showFullLog']:
+ end = QUERY_OPTS['limit'] or len(log_entries)
+ for entry in log_entries[:end]:
+ print entry
+ first_run = False
+ else:
+ if ranged_query:
+ pkg = ranged_query
+ first_run = print_matching_entries(indexed_entries, pkg, first_run)
+
+ first_run = False
diff --git a/pym/gentoolkit/equery/check.py b/pym/gentoolkit/equery/check.py
new file mode 100644
index 0000000..ffddf72
--- /dev/null
+++ b/pym/gentoolkit/equery/check.py
@@ -0,0 +1,232 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header: $
+
+"""Check timestamps and MD5sums for files owned by a given installed package"""
+
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import os
+import sys
+from getopt import gnu_getopt, GetoptError
+
+try:
+ import portage.checksum as checksum
+except ImportError:
+ import portage_checksum as checksum
+
+import gentoolkit.pprinter as pp
+from gentoolkit.equery import format_options, mod_usage, Config
+from gentoolkit.helpers2 import do_lookup
+
+# =======
+# Globals
+# =======
+
+QUERY_OPTS = {
+ "categoryFilter": None,
+ "includeInstalled": False,
+ "includeOverlayTree": False,
+ "includePortTree": False,
+ "checkMD5sum": True,
+ "checkTimestamp" : True,
+ "isRegex": False,
+ "matchExact": True,
+ "printMatchInfo": False,
+ "showSummary" : True,
+ "showPassedFiles" : False,
+ "showFailedFiles" : True
+}
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print __doc__.strip()
+ print
+
+ # Deprecation warning added by djanderson, 12/2008
+ pp.print_warn("Default action for this module has changed in Gentoolkit 0.3.")
+ pp.print_warn("Use globbing to simulate the old behavior (see man equery).")
+ pp.print_warn("Use '*' to check all installed packages.")
+ print
+
+ print mod_usage(mod_name="check")
+ print
+ print pp.command("options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -c, --category CAT", "only check files from packages in CAT"),
+ (" -f, --full-regex", "query is a regular expression"),
+ ))
+
+
+def parse_module_options(module_opts):
+ """Parse module options and update GLOBAL_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ('-h', '--help'):
+ print_help()
+ sys.exit(0)
+ elif opt in ('-c', '--category'):
+ QUERY_OPTS['categoryFilter'] = posarg
+ elif opt in ('-f', '--full-regex'):
+ QUERY_OPTS['isRegex'] = True
+
+
+def run_checks(files):
+ """Run some basic sanity checks on a package's contents.
+
+ If the file type (ftype) is not a directory or symlink, optionally
+ verify MD5 sums or mtimes via verify_obj().
+
+ @see: gentoolkit.packages.get_contents()
+ @type files: dict
+ @param files: in form {'PATH': ['TYPE', 'TIMESTAMP', 'MD5SUM']}
+ @rtype: tuple
+ @return:
+ passed (int): number of files that passed all checks
+ checked (int): number of files checked
+ errs (list): check errors' descriptions
+ """
+
+ checked = 0
+ passed = 0
+ errs = []
+ for cfile in files:
+ checked += 1
+ ftype = files[cfile][0]
+ if not os.path.exists(cfile):
+ errs.append("%s does not exist" % cfile)
+ continue
+ elif ftype == "dir":
+ if not os.path.isdir(cfile):
+ err = "%(cfile)s exists, but is not a directory"
+ errs.append(err % locals())
+ continue
+ elif ftype == "obj":
+ new_errs = verify_obj(files, cfile, errs)
+ if new_errs != errs:
+ errs = new_errs
+ continue
+ elif ftype == "sym":
+ target = files[cfile][2].strip()
+ if not os.path.islink(cfile):
+ err = "%(cfile)s exists, but is not a symlink"
+ errs.append(err % locals())
+ continue
+ tgt = os.readlink(cfile)
+ if tgt != target:
+ err = "%(cfile)s does not point to %(target)s"
+ errs.append(err % locals())
+ continue
+ else:
+ err = "%(cfile)s has unknown type %(ftype)s"
+ errs.append(err % locals())
+ continue
+ passed += 1
+
+ return passed, checked, errs
+
+
+def verify_obj(files, cfile, errs):
+ """Verify the MD5 sum and/or mtime and return any errors."""
+
+ if QUERY_OPTS["checkMD5sum"]:
+ md5sum = files[cfile][2]
+ try:
+ cur_checksum = checksum.perform_md5(cfile, calc_prelink=1)
+ except IOError:
+ err = "Insufficient permissions to read %(cfile)s"
+ errs.append(err % locals())
+ return errs
+ if cur_checksum != md5sum:
+ err = "%(cfile)s has incorrect MD5sum"
+ errs.append(err % locals())
+ return errs
+ if QUERY_OPTS["checkTimestamp"]:
+ mtime = int(files[cfile][1])
+ st_mtime = os.lstat(cfile).st_mtime
+ if st_mtime != mtime:
+ err = "%(cfile)s has wrong mtime (is %(st_mtime)d, " + \
+ "should be %(mtime)d)"
+ errs.append(err % locals())
+ return errs
+
+ return errs
+
+
+def main(input_args):
+ """Parse input and run the program"""
+
+ short_opts = "hac:f"
+ long_opts = ('help', 'all', 'category=', 'full-regex')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Module %s" % err)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries and not QUERY_OPTS["includeInstalled"]:
+ print_help()
+ sys.exit(2)
+ elif queries and not QUERY_OPTS["includeInstalled"]:
+ QUERY_OPTS["includeInstalled"] = True
+ elif QUERY_OPTS["includeInstalled"]:
+ queries = ["*"]
+
+ #
+ # Output
+ #
+
+ first_run = True
+ for query in queries:
+ if not first_run:
+ print
+
+ matches = do_lookup(query, QUERY_OPTS)
+
+ if not matches:
+ pp.print_error("No package found matching %s" % query)
+
+ matches.sort()
+
+ for pkg in matches:
+ if not Config["piping"] and Config["verbosityLevel"] >= 3:
+ print "[ Checking %s ]" % pp.cpv(pkg.cpv)
+ else:
+ print "%s:" % pkg.cpv
+
+ passed, checked, errs = run_checks(pkg.get_contents())
+
+ if not Config["piping"] and Config["verbosityLevel"] >= 3:
+ for err in errs:
+ pp.print_error(err)
+
+ passed = pp.number(str(passed))
+ checked = pp.number(str(checked))
+ info = " * %(passed)s out of %(checked)s files passed"
+ print info % locals()
+
+ first_run = False
diff --git a/pym/gentoolkit/equery/depends.py b/pym/gentoolkit/equery/depends.py
new file mode 100644
index 0000000..394c35b
--- /dev/null
+++ b/pym/gentoolkit/equery/depends.py
@@ -0,0 +1,248 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header: $
+
+"""List all direct dependencies matching a given query"""
+
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import sys
+from getopt import gnu_getopt, GetoptError
+
+from portage.util import unique_array
+
+import gentoolkit.pprinter as pp
+from gentoolkit.equery import format_options, mod_usage, Config
+from gentoolkit.helpers2 import compare_package_strings, do_lookup, \
+ find_packages, get_cpvs, get_installed_cpvs
+from gentoolkit.package import Package
+
+# =======
+# Globals
+# =======
+
+QUERY_OPTS = {
+ "categoryFilter": None,
+ "includeInstalled": True,
+ "includePortTree": False,
+ "includeOverlayTree": False,
+ "isRegex": False,
+ "matchExact": True,
+ "onlyDirect": True,
+ "onlyInstalled": True,
+ "printMatchInfo": True,
+ "indentLevel": 0,
+ "depth": -1
+}
+
+# Used to cache and detect looping
+PKGSEEN = set()
+PKGDEPS = {}
+DEPPKGS = {}
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print __doc__.strip()
+ print
+ print mod_usage(mod_name="depends")
+ print
+ print pp.command("options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -a, --all-packages",
+ "include packages that are not installed (slow)"),
+ (" -D, --indirect",
+ "search both direct and indirect dependencies"),
+ (" --depth=N", "limit indirect dependency tree to specified depth")
+ ))
+
+
+def cache_package_list(pkg_cache=None):
+ """Ensure that the package cache is set."""
+
+ if not pkg_cache:
+ if QUERY_OPTS["onlyInstalled"]:
+ # TODO: move away from using strings here
+ packages = get_installed_cpvs()
+ else:
+ packages = get_cpvs()
+ packages.sort(compare_package_strings)
+ pkg_cache = packages
+ else:
+ packages = pkg_cache
+
+ return packages
+
+
+def display_dependencies(cpv_is_displayed, dependency, cpv):
+ """Output dependencies calculated by find_dependencies.
+
+ @type cpv_is_displayed: bool
+ @param cpv_is_displayed: if True, the cpv has already been printed
+ @see: gentoolkit.package.get_*_deps()
+ @type dependency: tuple
+ @param dependency: (comparator, [use flags], cpv)
+ @type cpv: string
+ @param cpv: cat/pkg-ver
+ """
+
+ atom = pp.pkgquery(dependency[0] + dependency[2])
+ indent = " " * (QUERY_OPTS["indentLevel"] * 2)
+ useflags = pp.useflag(" & ".join(dependency[1]))
+
+ if not cpv_is_displayed:
+ if dependency[1]:
+ if not Config["piping"] and Config["verbosityLevel"] >= 3:
+ print indent + pp.cpv(cpv),
+ print "(" + useflags + " ? " + atom + ")"
+ else:
+ print indent + cpv
+ else:
+ if not Config["piping"] and Config["verbosityLevel"] >= 3:
+ print indent + pp.cpv(cpv),
+ print "(" + atom + ")"
+ else:
+ print indent + cpv
+ elif not Config["piping"] and Config["verbosityLevel"] >= 3:
+ indent = indent + " " * len(cpv)
+ if dependency[1]:
+ print indent + " (" + useflags + " ? " + atom + ")"
+ else:
+ print indent + " (" + atom + ")"
+
+
+def find_dependencies(matches, pkg_cache):
+ """Find dependencies for the packaged named in queries.
+
+ @type queries: list
+ @param queries: packages to find the dependencies for
+ """
+
+ for pkg in [Package(x) for x in cache_package_list(pkg_cache)]:
+ if not pkg.cpv in PKGDEPS:
+ try:
+ deps = pkg.get_runtime_deps() + pkg.get_compiletime_deps()
+ deps.extend(pkg.get_postmerge_deps())
+ except KeyError:
+ # If the ebuild is not found...
+ continue
+ # Remove duplicate deps
+ deps = unique_array(deps)
+ PKGDEPS[pkg.cpv] = deps
+ else:
+ deps = PKGDEPS[pkg.cpv]
+
+ cpv_is_displayed = False
+ for dependency in deps:
+ # TODO: (old) determine if dependency is enabled by USE flag
+ # Find all packages matching the dependency
+ depstr = dependency[0] + dependency[2]
+ if not depstr in DEPPKGS:
+ depcpvs = find_packages(depstr)
+ DEPPKGS[depstr] = depcpvs
+ else:
+ depcpvs = DEPPKGS[depstr]
+
+ for depcpv in depcpvs:
+ is_match = False
+ if depcpv in matches:
+ is_match = True
+
+ if is_match:
+ display_dependencies(cpv_is_displayed, dependency, pkg.cpv)
+ cpv_is_displayed = True
+ break
+
+ # if --indirect specified, call ourselves again with the dependency
+ # Do not call if we have already called ourselves.
+ if (cpv_is_displayed and not QUERY_OPTS["onlyDirect"] and
+ pkg not in PKGSEEN and
+ (QUERY_OPTS["indentLevel"] < QUERY_OPTS["depth"] or
+ QUERY_OPTS["depth"] == -1)):
+
+ PKGSEEN.add(pkg)
+ QUERY_OPTS["indentLevel"] += 1
+ find_dependencies([pkg], pkg_cache)
+ QUERY_OPTS["indentLevel"] -= 1
+
+
+def parse_module_options(module_opts):
+ """Parse module options and update GLOBAL_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ('-h', '--help'):
+ print_help()
+ sys.exit(0)
+ elif opt in ('-a', '--all-packages'):
+ QUERY_OPTS["onlyInstalled"] = False
+ elif opt in ('-d', '--direct'):
+ continue
+ elif opt in ('-D', '--indirect'):
+ QUERY_OPTS["onlyDirect"] = False
+ elif opt in ('--depth'):
+ if posarg.isdigit():
+ depth = int(posarg)
+ else:
+ err = "Module option --depth requires integer (got '%s')"
+ pp.print_error(err % posarg)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+ QUERY_OPTS["depth"] = depth
+
+
+def main(input_args):
+ """Parse input and run the program"""
+
+ short_opts = "hadD" # -d, --direct was old option for default action
+ long_opts = ('help', 'all-packages', 'direct', 'indirect', 'depth=')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Module %s" % err)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ #
+ # Output
+ #
+
+ first_run = True
+ for query in queries:
+ if not first_run:
+ print
+
+ matches = do_lookup(query, QUERY_OPTS)
+
+ if matches:
+ find_dependencies(matches, None)
+ else:
+ pp.print_error("No matching package found for %s" % query)
+
+ first_run = False
diff --git a/pym/gentoolkit/equery/depgraph.py b/pym/gentoolkit/equery/depgraph.py
new file mode 100644
index 0000000..f4723c2
--- /dev/null
+++ b/pym/gentoolkit/equery/depgraph.py
@@ -0,0 +1,194 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header: $
+
+"""Display a dependency graph for a given package"""
+
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import sys
+from getopt import gnu_getopt, GetoptError
+
+import gentoolkit
+import gentoolkit.pprinter as pp
+from gentoolkit import errors
+from gentoolkit.equery import format_options, mod_usage, Config
+from gentoolkit.helpers2 import do_lookup
+
+# =======
+# Globals
+# =======
+
+QUERY_OPTS = {
+ "categoryFilter": None,
+ "depth": 0,
+ "displayUseflags": True,
+ "fancyFormat": True,
+ "includeInstalled": True,
+ "includePortTree": True,
+ "includeOverlayTree": True,
+ "includeMasked": True,
+ "isRegex": False,
+ "matchExact": True,
+ "printMatchInfo": True
+}
+
+if not Config["piping"] and Config["verbosityLevel"] >= 3:
+ VERBOSE = True
+else:
+ VERBOSE = False
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print __doc__.strip()
+ print
+ print mod_usage(mod_name="depgraph")
+ print
+ print pp.command("options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -U, --no-useflags", "do not show USE flags"),
+ (" -l, --linear", "do not use fancy formatting"),
+ (" --depth=N", "limit dependency graph to specified depth")
+ ))
+
+
+def display_graph(pkg, stats, level=0, seen_pkgs=None, suffix=""):
+ """Display a dependency graph for a package
+
+ @type pkg: gentoolkit.package.Package
+ @param pkg: package to check dependencies of
+ @type level: int
+ @param level: current depth level
+ @type seen_pkgs: set
+ @param seen_pkgs: a set of all packages that have had their deps graphed
+ """
+
+ if not seen_pkgs:
+ seen_pkgs = set()
+
+ stats["packages"] += 1
+ stats["maxdepth"] = max(stats["maxdepth"], level)
+
+ pfx = ""
+ if QUERY_OPTS["fancyFormat"]:
+ pfx = (level * " ") + "`-- "
+ pp.print_info(0, pfx + pkg.cpv + suffix)
+
+ seen_pkgs.add(pkg.cpv)
+
+ deps = pkg.get_runtime_deps() + pkg.get_compiletime_deps()
+ deps.extend(pkg.get_postmerge_deps())
+ for dep in deps:
+ suffix = ""
+ depcpv = dep[2]
+ deppkg = gentoolkit.find_best_match(dep[0] + depcpv)
+ if not deppkg:
+ print (pfx + dep[0] + depcpv),
+ print "(unable to resolve: package masked or removed)"
+ continue
+ if deppkg.get_cpv() in seen_pkgs:
+ continue
+ if depcpv.find("virtual") == 0:
+ suffix += " (%s)" % pp.cpv(depcpv)
+ if dep[1] and QUERY_OPTS["displayUseflags"]:
+ suffix += " [%s]" % pp.useflagon(' '.join(dep[1]))
+ if (level < QUERY_OPTS["depth"] or QUERY_OPTS["depth"] <= 0):
+ seen_pkgs, stats = display_graph(deppkg, stats, level+1,
+ seen_pkgs, suffix)
+
+ return seen_pkgs, stats
+
+
+def parse_module_options(module_opts):
+ """Parse module options and update GLOBAL_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ('-h', '--help'):
+ print_help()
+ sys.exit(0)
+ if opt in ('-U', '--no-useflags'):
+ QUERY_OPTS["displayUseflags"] = False
+ if opt in ('-l', '--linear'):
+ QUERY_OPTS["fancyFormat"] = False
+ if opt in ('--depth'):
+ if posarg.isdigit():
+ depth = int(posarg)
+ else:
+ err = "Module option --depth requires integer (got '%s')"
+ pp.print_error(err % posarg)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+ QUERY_OPTS["depth"] = depth
+
+
+def main(input_args):
+ """Parse input and run the program"""
+
+ short_opts = "hUl"
+ long_opts = ('help', 'no-useflags', 'depth=')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Module %s" % err)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ #
+ # Output
+ #
+
+ first_run = True
+ for query in queries:
+ if not first_run:
+ print
+
+ matches = do_lookup(query, QUERY_OPTS)
+
+ if not matches:
+ errors.GentoolkitNoMatches(query)
+
+ for pkg in matches:
+ stats = {"maxdepth": 0, "packages": 0}
+
+ if VERBOSE:
+ pp.print_info(3, " * dependency graph for %s:" % pp.cpv(pkg.cpv))
+ else:
+ pp.print_info(0, "%s:" % pkg.cpv)
+
+ stats = display_graph(pkg, stats)[1]
+
+ if VERBOSE:
+ info = ''.join(["[ ", pp.cpv(pkg.cpv), " stats: packages (",
+ pp.number(str(stats["packages"])), "), max depth (",
+ pp.number(str(stats["maxdepth"])), ") ]"])
+ pp.print_info(0, info)
+
+ first_run = False
diff --git a/pym/gentoolkit/equery/files.py b/pym/gentoolkit/equery/files.py
new file mode 100644
index 0000000..f25ae5a
--- /dev/null
+++ b/pym/gentoolkit/equery/files.py
@@ -0,0 +1,311 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header: $
+
+"""List files owned by a given package"""
+
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import os
+import sys
+from getopt import gnu_getopt, GetoptError
+
+import gentoolkit
+import gentoolkit.pprinter as pp
+from gentoolkit.equery import format_filetype, format_options, mod_usage, \
+ Config
+from gentoolkit.helpers2 import do_lookup
+
+# =======
+# Globals
+# =======
+
+QUERY_OPTS = {
+ "categoryFilter": None,
+ "includeInstalled": True,
+ "includePortTree": False,
+ "includeOverlayTree": False,
+ "includeMasked": True,
+ "isRegex": False,
+ "matchExact": True,
+ "outputTree": False,
+ "printMatchInfo": True,
+ "showType": False,
+ "showTimestamp": False,
+ "showMD5": False,
+ "typeFilter": None
+}
+
+FILTER_RULES = ('dir', 'obj', 'sym', 'dev', 'path', 'conf', 'cmd', 'doc',
+ 'man', 'info')
+
+if not Config["piping"] and Config["verbosityLevel"] >= 3:
+ VERBOSE = True
+else:
+ VERBOSE = False
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print __doc__.strip()
+ print
+ print mod_usage(mod_name="files")
+ print
+ print pp.command("options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -m, --md5sum", "include MD5 sum in output"),
+ (" -s, --timestamp", "include timestamp in output"),
+ (" -t, --type", "include file type in output"),
+ (" --tree", "display results in a tree (turns off other options)"),
+ (" -f, --filter=RULES", "filter output by file type"),
+ (" RULES",
+ "a comma-separated list (no spaces); choose from:")
+ ))
+ print " " * 24, ', '.join(pp.emph(x) for x in FILTER_RULES)
+
+
+def display_files(contents):
+ """Display the content of an installed package.
+
+ @see: gentoolkit.package.Package.get_contents
+ @type contents: dict
+ @param contents: {'path': ['filetype', ...], ...}
+ """
+
+ filenames = contents.keys()
+ filenames.sort()
+ last = []
+
+ for name in filenames:
+ if QUERY_OPTS["outputTree"]:
+ basename = name.split("/")[1:]
+ if contents[name][0] == "dir":
+ if len(last) == 0:
+ last = basename
+ print pp.path(" /" + basename[0])
+ continue
+ numol = 0
+ for i, directory in enumerate(basename):
+ try:
+ if directory in last[i]:
+ numol = i + 1
+ continue
+ # W0704: Except doesn't do anything
+ # pylint: disable-msg=W0704
+ except IndexError:
+ pass
+ last = basename
+ if len(last) == 1:
+ print pp.path(" " + last[0])
+ continue
+ ind = " " * (numol * 3)
+ print pp.path(ind + "> " + "/" + last[-1])
+ elif contents[name][0] == "sym":
+ print pp.path(" " * (len(last) * 3) + "+"),
+ print pp.path_symlink(basename[-1] + " -> " + contents[name][2])
+ else:
+ print pp.path(" " * (len(last) * 3) + "+ ") + basename[-1]
+ else:
+ pp.print_info(0, format_filetype(
+ name,
+ contents[name],
+ show_type=QUERY_OPTS["showType"],
+ show_md5=QUERY_OPTS["showMD5"],
+ show_timestamp=QUERY_OPTS["showTimestamp"]))
+
+
+def filter_by_doc(contents, content_filter):
+ """Return a copy of content filtered by documentation."""
+
+ filtered_content = {}
+ for doctype in ('doc' ,'man' ,'info'):
+ # List only files from /usr/share/{doc,man,info}
+ if doctype in content_filter:
+ docpath = os.path.join(os.sep, 'usr', 'share', doctype)
+ for path in contents:
+ if contents[path][0] == 'obj' and path.startswith(docpath):
+ filtered_content[path] = contents[path]
+
+ return filtered_content
+
+
+def filter_by_command(contents):
+ """Return a copy of content filtered by executable commands."""
+
+ filtered_content = {}
+ userpath = os.environ["PATH"].split(os.pathsep)
+ userpath = [os.path.normpath(x) for x in userpath]
+ for path in contents:
+ if (contents[path][0] in ['obj', 'sym'] and
+ os.path.dirname(path) in userpath):
+ filtered_content[path] = contents[path]
+
+ return filtered_content
+
+
+def filter_by_path(contents):
+ """Return a copy of content filtered by file paths."""
+
+ filtered_content = {}
+ paths = list(reversed(sorted(contents.keys())))
+ while paths:
+ basepath = paths.pop()
+ if contents[basepath][0] == 'dir':
+ check_subdirs = False
+ for path in paths:
+ if (contents[path][0] != "dir" and
+ os.path.dirname(path) == basepath):
+ filtered_content[basepath] = contents[basepath]
+ check_subdirs = True
+ break
+ if check_subdirs:
+ while (paths and paths[-1].startswith(basepath)):
+ paths.pop()
+
+ return filtered_content
+
+
+def filter_by_conf(contents):
+ """Return a copy of content filtered by configuration files."""
+
+ filtered_content = {}
+ conf_path = gentoolkit.settings["CONFIG_PROTECT"].split()
+ conf_path = tuple(os.path.normpath(x) for x in conf_path)
+ conf_mask_path = gentoolkit.settings["CONFIG_PROTECT_MASK"].split()
+ conf_mask_path = tuple(os.path.normpath(x) for x in conf_mask_path)
+ for path in contents:
+ if contents[path][0] == 'obj' and path.startswith(conf_path):
+ if not path.startswith(conf_mask_path):
+ filtered_content[path] = contents[path]
+
+ return filtered_content
+
+
+def filter_contents(contents):
+ """Filter files by type if specified by the user.
+
+ @see: gentoolkit.package.Package.get_contents
+ @type contents: dict
+ @param contents: {'path': ['filetype', ...], ...}
+ @rtype: dict
+ @return: contents with unrequested filetypes stripped
+ """
+
+ if QUERY_OPTS['typeFilter']:
+ content_filter = QUERY_OPTS['typeFilter']
+ else:
+ return contents
+
+ filtered_content = {}
+ if frozenset(('dir', 'obj', 'sym', 'dev')).intersection(content_filter):
+ # Filter elements by type (as recorded in CONTENTS)
+ for path in contents:
+ if contents[path][0] in content_filter:
+ filtered_content[path] = contents[path]
+ if "cmd" in content_filter:
+ filtered_content.update(filter_by_command(contents))
+ if "path" in content_filter:
+ filtered_content.update(filter_by_path(contents))
+ if "conf" in content_filter:
+ filtered_content.update(filter_by_conf(contents))
+ if frozenset(('doc' ,'man' ,'info')).intersection(content_filter):
+ filtered_content.update(filter_by_doc(contents, content_filter))
+
+ return filtered_content
+
+
+def parse_module_options(module_opts):
+ """Parse module options and update GLOBAL_OPTS"""
+
+ content_filter = []
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ('-h', '--help'):
+ print_help()
+ sys.exit(0)
+ elif opt in ('-e', '--exact-name'):
+ QUERY_OPTS["matchExact"] = True
+ elif opt in ('-m', '--md5sum'):
+ QUERY_OPTS["showMD5"] = True
+ elif opt in ('-s', '--timestamp'):
+ QUERY_OPTS["showTimestamp"] = True
+ elif opt in ('-t', '--type'):
+ QUERY_OPTS["showType"] = True
+ elif opt in ('--tree'):
+ QUERY_OPTS["outputTree"] = True
+ elif opt in ('-f', '--filter'):
+ f_split = posarg.split(',')
+ content_filter.extend(x.lstrip('=') for x in f_split)
+ for rule in content_filter:
+ if not rule in FILTER_RULES:
+ pp.print_error("Invalid filter rule '%s'" % rule)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+ QUERY_OPTS["typeFilter"] = content_filter
+
+
+def main(input_args):
+ """Parse input and run the program"""
+
+ short_opts = "hemstf:"
+ long_opts = ('help', 'exact-name', 'md5sum', 'timestamp', 'type', 'tree',
+ 'filter=')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Module %s" % err)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ # Turn off filtering for tree output
+ if QUERY_OPTS["outputTree"]:
+ QUERY_OPTS["typeFilter"] = None
+
+ #
+ # Output files
+ #
+
+ first_run = True
+ for query in queries:
+ if not first_run:
+ print
+
+ matches = do_lookup(query, QUERY_OPTS)
+
+ if not matches:
+ pp.print_error("No matching packages found for %s" % query)
+
+ for pkg in matches:
+ if VERBOSE:
+ pp.print_info(1, " * Contents of %s:" % pp.cpv(pkg.cpv))
+
+ contents = pkg.get_contents()
+ display_files(filter_contents(contents))
+
+ first_run = False
diff --git a/pym/gentoolkit/equery/hasuse.py b/pym/gentoolkit/equery/hasuse.py
new file mode 100644
index 0000000..6580bbf
--- /dev/null
+++ b/pym/gentoolkit/equery/hasuse.py
@@ -0,0 +1,189 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2 or higher
+#
+# $Header: $
+
+"""List all installed packages that have a given USE flag"""
+
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import sys
+from getopt import gnu_getopt, GetoptError
+
+import gentoolkit
+import gentoolkit.pprinter as pp
+from gentoolkit.equery import format_options, format_package_names, \
+ mod_usage, Config
+from gentoolkit.helpers2 import do_lookup, get_installed_cpvs
+from gentoolkit.package import Package
+
+# =======
+# Globals
+# =======
+
+QUERY_OPTS = {
+ "categoryFilter": None,
+ "includeInstalled": False,
+ "includePortTree": False,
+ "includeOverlayTree": False,
+ "includeMasked": True,
+ "isRegex": False, # Necessary for do_lookup, don't change
+ "printMatchInfo": False
+}
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print __doc__.strip()
+ print
+ print mod_usage(mod_name="hasuse", arg="USE-flag")
+ print
+ print pp.command("options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -i, --installed",
+ "include installed packages in search path (default)"),
+ (" -o, --overlay-tree", "include overlays in search path"),
+ (" -p, --portage-tree", "include entire portage tree in search path")
+ ))
+
+
+def parse_module_options(module_opts):
+ """Parse module options and update GLOBAL_OPTS"""
+
+ # Parse module options
+ opts = (x[0] for x in module_opts)
+ for opt in opts:
+ if opt in ('-h', '--help'):
+ print_help()
+ sys.exit(0)
+ elif opt in ('-i', '--installed'):
+ QUERY_OPTS['includeInstalled'] = True
+ elif opt in ('-p', '--portage-tree'):
+ QUERY_OPTS['includePortTree'] = True
+ elif opt in ('-o', '--overlay-tree'):
+ QUERY_OPTS['includeOverlayTree'] = True
+
+
+def print_sequence(seq):
+ """Print every item of a sequence."""
+
+ for item in seq:
+ print item
+
+
+def sort_by_location(query, matches):
+ """Take a list of packages and sort them by location.
+
+ @rtype: tuple
+ @return:
+ installed: list of all packages in matches that are in the vdb
+ overlay: list of all packages in matches that reside in an overlay
+ porttree: list of all packages that are not in the vdb or an overlay
+ """
+
+ all_installed_packages = set()
+ if QUERY_OPTS["includeInstalled"]:
+ all_installed_packages = set(Package(x) for x in get_installed_cpvs())
+
+ # Cache package sets
+ installed = []
+ overlay = []
+ porttree = []
+
+ for pkg in matches:
+ useflags = [f.lstrip("+-") for f in pkg.get_env_var("IUSE").split()]
+ if query not in useflags:
+ continue
+
+ if QUERY_OPTS["includeInstalled"]:
+ if pkg in all_installed_packages:
+ installed.append(pkg)
+ continue
+ if pkg.is_overlay():
+ if QUERY_OPTS["includeOverlayTree"]:
+ overlay.append(pkg)
+ continue
+ if QUERY_OPTS["includePortTree"]:
+ porttree.append(pkg)
+
+ return installed, overlay, porttree
+
+
+def main(input_args):
+ """Parse input and run the program"""
+
+ short_opts = "hiIpo"
+ long_opts = ('help', 'installed', 'exclude-installed', 'portage-tree',
+ 'overlay-tree')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Module %s" % err)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+ elif not (QUERY_OPTS['includeInstalled'] or
+ QUERY_OPTS['includePortTree'] or QUERY_OPTS['includeOverlayTree']):
+ # Got queries but no search path; set a sane default
+ QUERY_OPTS['includeInstalled'] = True
+
+ matches = do_lookup("*", QUERY_OPTS)
+ matches.sort()
+
+ #
+ # Output
+ #
+
+ first_run = True
+ for query in queries:
+ if not first_run:
+ print
+
+ if not Config["piping"]:
+ print " * Searching for USE flag %s ... " % pp.useflag(query)
+
+ installed, overlay, porttree = sort_by_location(query, matches)
+
+ if QUERY_OPTS["includeInstalled"]:
+ print " * installed packages:"
+ if not Config["piping"]:
+ installed = format_package_names(installed, 1)
+ print_sequence(installed)
+
+ if QUERY_OPTS["includePortTree"]:
+ portdir = pp.path(gentoolkit.settings["PORTDIR"])
+ print " * Portage tree (%s):" % portdir
+ if not Config["piping"]:
+ porttree = format_package_names(porttree, 2)
+ print_sequence(porttree)
+
+ if QUERY_OPTS["includeOverlayTree"]:
+ portdir_overlay = pp.path(gentoolkit.settings["PORTDIR_OVERLAY"])
+ print " * overlay tree (%s):" % portdir_overlay
+ if not Config["piping"]:
+ overlay = format_package_names(overlay, 3)
+ print_sequence(overlay)
+
+ first_run = False
diff --git a/pym/gentoolkit/equery/list_.py b/pym/gentoolkit/equery/list_.py
new file mode 100644
index 0000000..20cd376
--- /dev/null
+++ b/pym/gentoolkit/equery/list_.py
@@ -0,0 +1,251 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2 or higher
+#
+# $Header: $
+
+"""List installed packages matching the query pattern"""
+
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import sys
+from getopt import gnu_getopt, GetoptError
+
+import gentoolkit
+import gentoolkit.pprinter as pp
+from gentoolkit.equery import format_options, format_package_names, \
+ mod_usage, Config
+from gentoolkit.helpers2 import do_lookup, get_installed_cpvs
+from gentoolkit.package import Package
+
+# =======
+# Globals
+# =======
+
+QUERY_OPTS = {
+ "categoryFilter": None,
+ "duplicates": False,
+ "includeInstalled": False,
+ "includePortTree": False,
+ "includeOverlayTree": False,
+ "includeMasked": True,
+ "isRegex": False,
+ "printMatchInfo": True
+}
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print __doc__.strip()
+ print
+ # Deprecation warning added 04/09: djanderson
+ pp.print_warn("Default action for this module has changed in Gentoolkit 0.3.")
+ pp.print_warn("-e, --exact-name is now the default behavior.")
+ pp.print_warn("Use globbing to simulate the old behavior (see man equery).")
+ pp.print_warn("Use '*' to check all installed packages.")
+ print
+
+ print mod_usage(mod_name="list")
+ print
+ print pp.command("options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -c, --category CAT", "only search in the category CAT"),
+ (" -d, --duplicates", "list only installed duplicate packages"),
+ (" -f, --full-regex", "query is a regular expression"),
+ (" -i, --installed", "list installed packages matching query"),
+ (" -o, --overlay-tree", "list packages in overlays"),
+ (" -p, --portage-tree", "list packages in the main portage tree")
+ ))
+
+
+def adjust_query_environment(queries):
+ """Make sure the search environment is good to go."""
+
+ if not queries and not (QUERY_OPTS["duplicates"] or
+ QUERY_OPTS["includeInstalled"] or QUERY_OPTS["includePortTree"] or
+ QUERY_OPTS["includeOverlayTree"]):
+ print_help()
+ sys.exit(2)
+ elif queries and not (QUERY_OPTS["duplicates"] or
+ QUERY_OPTS["includeInstalled"] or QUERY_OPTS["includePortTree"] or
+ QUERY_OPTS["includeOverlayTree"]):
+ QUERY_OPTS["includeInstalled"] = True
+ elif not queries and (QUERY_OPTS["duplicates"] or
+ QUERY_OPTS["includeInstalled"] or QUERY_OPTS["includePortTree"] or
+ QUERY_OPTS["includeOverlayTree"]):
+ queries = ["*"]
+
+ # Only search installed packages when listing duplicate packages
+ if QUERY_OPTS["duplicates"]:
+ QUERY_OPTS["includeInstalled"] = True
+ QUERY_OPTS["includePortTree"] = False
+ QUERY_OPTS["includeOverlayTree"] = False
+
+ return queries
+
+
+def get_duplicates(matches):
+ """Return only packages that have more than one version installed."""
+
+ dups = {}
+ result = []
+ for pkg in matches:
+ if pkg.key in dups:
+ dups[pkg.key].append(pkg)
+ else:
+ dups[pkg.key] = [pkg]
+
+ for cpv in dups.values():
+ if len(cpv) > 1:
+ result.extend(cpv)
+
+ return result
+
+
+def parse_module_options(module_opts):
+ """Parse module options and update GLOBAL_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ('-h', '--help'):
+ print_help()
+ sys.exit(0)
+ elif opt in ('-a', '--all'):
+ QUERY_OPTS['listAllPackages'] = True
+ elif opt in ('-c', '--category'):
+ QUERY_OPTS['categoryFilter'] = posarg
+ elif opt in ('-i', '--installed'):
+ QUERY_OPTS['includeInstalled'] = True
+ elif opt in ('-p', '--portage-tree'):
+ QUERY_OPTS['includePortTree'] = True
+ elif opt in ('-o', '--overlay-tree'):
+ QUERY_OPTS['includeOverlayTree'] = True
+ elif opt in ('-f', '--full-regex'):
+ QUERY_OPTS['isRegex'] = True
+ elif opt in ('-e', '--exact-name'):
+ pp.print_warn("-e, --exact-name is now default.")
+ pp.print_warn("Use globbing to simulate the old behavior.")
+ print
+ elif opt in ('-d', '--duplicates'):
+ QUERY_OPTS['duplicates'] = True
+
+
+def print_sequence(seq):
+ """Print every item of a sequence."""
+
+ for item in seq:
+ print item
+
+
+def sort_by_location(matches):
+ """Take a list of packages and sort them by location.
+
+ @rtype: tuple
+ @return:
+ installed: list of all packages in matches that are in the vdb
+ overlay: list of all packages in matches that reside in an overlay
+ porttree: list of all packages that are not in the vdb or an overlay
+ """
+
+ all_installed_packages = set()
+ if QUERY_OPTS["includeInstalled"]:
+ all_installed_packages = set(Package(x) for x in get_installed_cpvs())
+
+ # Cache package sets
+ installed = []
+ overlay = []
+ porttree = []
+
+ for pkg in matches:
+ if QUERY_OPTS["includeInstalled"]:
+ if pkg in all_installed_packages:
+ installed.append(pkg)
+ continue
+ if pkg.is_overlay():
+ if QUERY_OPTS["includeOverlayTree"]:
+ overlay.append(pkg)
+ continue
+ if QUERY_OPTS["includePortTree"]:
+ porttree.append(pkg)
+
+ return installed, overlay, porttree
+
+
+def main(input_args):
+ """Parse input and run the program"""
+
+ short_opts = "hc:defiIop" # -I was used to turn off -i when it was
+ # the default action, -e is now default
+
+ # 04/09: djanderson
+ # --exclude-installed is no longer needed. Kept for compatibility.
+ # --exact-name is no longer needed. Kept for compatibility.
+ long_opts = ('help', 'all', 'category=', 'installed', 'exclude-installed',
+ 'portage-tree', 'overlay-tree', 'full-regex', 'exact-name', 'duplicates')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Module %s" % err)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+ queries = adjust_query_environment(queries)
+
+ first_run = True
+ for query in queries:
+ if not first_run:
+ print
+
+ matches = do_lookup(query, QUERY_OPTS)
+
+ # Find duplicate packages
+ if QUERY_OPTS["duplicates"]:
+ matches = get_duplicates(matches)
+
+ matches.sort()
+
+ installed, overlay, porttree = sort_by_location(matches)
+
+ #
+ # Output
+ #
+
+ if QUERY_OPTS["includeInstalled"]:
+ print " * installed packages:"
+ if not Config["piping"]:
+ installed = format_package_names(installed, 1)
+ print_sequence(installed)
+
+ if QUERY_OPTS["includePortTree"]:
+ portdir = pp.path(gentoolkit.settings["PORTDIR"])
+ print " * Portage tree (%s):" % portdir
+ if not Config["piping"]:
+ porttree = format_package_names(porttree, 2)
+ print_sequence(porttree)
+
+ if QUERY_OPTS["includeOverlayTree"]:
+ portdir_overlay = pp.path(gentoolkit.settings["PORTDIR_OVERLAY"])
+ print " * overlay tree (%s):" % portdir_overlay
+ if not Config["piping"]:
+ overlay = format_package_names(overlay, 3)
+ print_sequence(overlay)
+
+ first_run = False
diff --git a/pym/gentoolkit/equery/meta.py b/pym/gentoolkit/equery/meta.py
new file mode 100644
index 0000000..34dde68
--- /dev/null
+++ b/pym/gentoolkit/equery/meta.py
@@ -0,0 +1,533 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2 or higher
+#
+# $Header: $
+
+"""Display metadata about a given package"""
+
+# Move to Imports section after Python-2.6 is stable
+from __future__ import with_statement
+
+__author__ = "Douglas Anderson"
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import os
+import re
+import sys
+import xml.etree.cElementTree as ET
+from getopt import gnu_getopt, GetoptError
+
+from portage import settings
+
+import gentoolkit.pprinter as pp
+from gentoolkit import errors
+from gentoolkit.equery import format_options, mod_usage, Config
+from gentoolkit.helpers2 import find_packages
+from gentoolkit.textwrap_ import TextWrapper
+
+# =======
+# Globals
+# =======
+
+# E1101: Module 'portage.output' has no $color member
+# portage.output creates color functions dynamically
+# pylint: disable-msg=E1101
+
+QUERY_OPTS = {
+ "current": False,
+ "description": False,
+ "herd": False,
+ "maintainer": False,
+ "useflags": False,
+ "upstream": False,
+ "xml": False
+}
+
+# Get the location of the main Portage tree
+PORTDIR = [settings["PORTDIR"] or os.path.join(os.sep, "usr", "portage")]
+# Check for overlays
+if settings["PORTDIR_OVERLAY"]:
+ PORTDIR.extend(settings["PORTDIR_OVERLAY"].split())
+
+if not Config["piping"] and Config["verbosityLevel"] >= 3:
+ VERBOSE = True
+else:
+ VERBOSE = False
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print __doc__.strip()
+ print
+ print mod_usage(mod_name="meta")
+ print
+ print pp.command("options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -c, --current", "parse metadata.xml in the current directory"),
+ (" -d, --description", "show an extended package description"),
+ (" -H, --herd", "show the herd(s) for the package"),
+ (" -m, --maintainer", "show the maintainer(s) for the package"),
+ (" -u, --useflags", "show per-package USE flag descriptions"),
+ (" -U, --upstream", "show package's upstream information"),
+ (" -x, --xml", "show the plain XML file")
+ ))
+
+
+def call_get_functions(xml_tree, meta, got_opts):
+ """Call information gathering funtions and display the results."""
+
+ if QUERY_OPTS["herd"] or not got_opts:
+ herd = get_herd(xml_tree)
+ if QUERY_OPTS["herd"]:
+ herd = format_list(herd)
+ else:
+ herd = format_list(herd, "Herd: ", " " * 13)
+ print_sequence(herd)
+
+ if QUERY_OPTS["maintainer"] or not got_opts:
+ maint = get_maitainer(xml_tree)
+ if QUERY_OPTS["maintainer"]:
+ maint = format_list(maint)
+ else:
+ maint = format_list(maint, "Maintainer: ", " " * 13)
+ print_sequence(maint)
+
+ if QUERY_OPTS["upstream"] or not got_opts:
+ upstream = get_upstream(xml_tree)
+ if QUERY_OPTS["upstream"]:
+ upstream = format_list(upstream)
+ else:
+ upstream = format_list(upstream, "Upstream: ", " " * 13)
+ print_sequence(upstream)
+
+ if QUERY_OPTS["description"]:
+ desc = get_description(xml_tree)
+ print_sequence(format_list(desc))
+
+ if QUERY_OPTS["useflags"]:
+ useflags = get_useflags(xml_tree)
+ print_sequence(format_list(useflags))
+
+ if QUERY_OPTS["xml"]:
+ print_file(meta)
+
+
+def format_line(line, first="", subsequent="", force_quiet=False):
+ """Wrap a string at word boundaries and optionally indent the first line
+ and/or subsequent lines with custom strings.
+
+ Preserve newlines if the longest line is not longer than
+ Config['termWidth']. To force the preservation of newlines and indents,
+ split the string into a list and feed it to format_line via format_list.
+
+ @see: format_list()
+ @type line: string
+ @param line: text to format
+ @type first: string
+ @param first: text to prepend to the first line
+ @type subsequent: string
+ @param subsequent: text to prepend to subsequent lines
+ @type force_quiet: boolean
+ @rtype: string
+ @return: A wrapped line
+ """
+
+ if line:
+ line = line.expandtabs().strip("\n").splitlines()
+ else:
+ if force_quiet:
+ return
+ else:
+ return first + "None specified"
+
+ if len(first) > len(subsequent):
+ wider_indent = first
+ else:
+ wider_indent = subsequent
+
+ widest_line_len = len(max(line, key=len)) + len(wider_indent)
+
+ if widest_line_len > Config['termWidth']:
+ twrap = TextWrapper(width=Config['termWidth'], expand_tabs=False,
+ initial_indent=first, subsequent_indent=subsequent)
+ line = " ".join(line)
+ line = re.sub("\s+", " ", line)
+ line = line.lstrip()
+ result = twrap.fill(line)
+ else:
+ # line will fit inside Config['termWidth'], so preserve whitespace and
+ # newlines
+ line[0] = first + line[0] # Avoid two newlines if len == 1
+
+ if len(line) > 1:
+ line[0] = line[0] + "\n"
+ for i in range(1, (len(line[1:-1]) + 1)):
+ line[i] = subsequent + line[i] + "\n"
+ line[-1] = subsequent + line[-1] # Avoid two newlines on last line
+
+ if line[-1].isspace():
+ del line[-1] # Avoid trailing blank lines
+
+ result = "".join(line)
+
+ return result.encode("utf-8")
+
+
+def format_list(lst, first="", subsequent="", force_quiet=False):
+ """Feed elements of a list to format_line().
+
+ @see: format_line()
+ @type lst: list
+ @param lst: list to format
+ @type first: string
+ @param first: text to prepend to the first line
+ @type subsequent: string
+ @param subsequent: text to prepend to subsequent lines
+ @rtype: list
+ @return: list with element text wrapped at Config['termWidth']
+ """
+
+ result = []
+ if lst:
+ # Format the first line
+ line = format_line(lst[0], first, subsequent, force_quiet)
+ result.append(line)
+ # Format subsequent lines
+ for elem in lst[1:]:
+ if elem:
+ result.append(format_line(elem, subsequent, subsequent,
+ force_quiet))
+ else:
+ # We don't want to send a blank line to format_line()
+ result.append("")
+ else:
+ if VERBOSE:
+ if force_quiet:
+ result = None
+ else:
+ # Send empty list, we'll get back first + `None specified'
+ result.append(format_line(lst, first, subsequent))
+
+ return result
+
+
+def get_herd(xml_tree):
+ """Return a list of text nodes for <herd>."""
+
+ return [e.text for e in xml_tree.findall("herd")]
+
+
+def get_description(xml_tree):
+ """Return a list of text nodes for <longdescription>.
+
+ @todo: Support the `lang' attribute
+ """
+
+ return [e.text for e in xml_tree.findall("longdescription")]
+
+
+def get_maitainer(xml_tree):
+ """Return a parsable tree of all maintainer elements and sub-elements."""
+
+ first_run = True
+ result = []
+ for node in xml_tree.findall("maintainer"):
+ if not first_run:
+ result.append("")
+ restrict = node.get("restrict")
+ if restrict:
+ result.append("(%s %s)" %
+ (pp.emph("Restrict to"), pp.output.green(restrict)))
+ result.extend(e.text for e in node)
+ first_run = False
+
+ return result
+
+
+def get_overlay_name(p_dir):
+ """Determine the overlay name and return a formatted string."""
+
+ result = []
+ cat_pkg = '/'.join(p_dir.split('/')[-2:])
+ result.append(" * %s" % pp.cpv(cat_pkg))
+ o_dir = '/'.join(p_dir.split('/')[:-2])
+ if o_dir != PORTDIR[0]:
+ # o_dir is an overlay
+ o_name = o_dir.split('/')[-1]
+ o_name = ("[", o_name, "]")
+ result.append(pp.output.turquoise("".join(o_name)))
+
+ return ' '.join(result)
+
+
+def get_package_directory(queries):
+ """Find a package's portage directory."""
+
+ # Find queries' Portage directory and throw error if invalid
+ if not QUERY_OPTS["current"]:
+ # We need at least one program name to run
+ if not queries:
+ print_help()
+ sys.exit(2)
+ else:
+ package_dir = []
+ for query in queries:
+ matches = find_packages(query, include_masked=True)
+ # Prefer a package that's in the Portage tree over one in an
+ # overlay. Start with oldest first.
+ pkg = None
+ while reversed(matches):
+ pkg = matches.pop()
+ if not pkg.is_overlay():
+ break
+ if pkg:
+ package_dir.append(pkg.get_package_path())
+ else:
+ package_dir = [os.getcwd()]
+
+ return package_dir
+
+
+def get_useflags(xml_tree):
+ """Return a list of formatted <useflag> lines, including blank elements
+ where blank lines should be printed."""
+
+ first_run = True
+ result = []
+ for node in xml_tree.getiterator("flag"):
+ if not first_run:
+ result.append("")
+ flagline = pp.useflag(node.get("name"))
+ restrict = node.get("restrict")
+ if restrict:
+ result.append("%s (%s %s)" %
+ (flagline, pp.emph("Restrict to"), pp.output.green(restrict)))
+ else:
+ result.append(flagline)
+ # ElementTree handles nested element text in a funky way.
+ # So we need to dump the raw XML and parse it manually.
+ flagxml = ET.tostring(node)
+ flagxml = re.sub("\s+", " ", flagxml)
+ flagxml = re.sub("\n\t", "", flagxml)
+ flagxml = re.sub("<(pkg|cat)>(.*?)</(pkg|cat)>",
+ pp.cpv(r"\2"), flagxml)
+ flagtext = re.sub("<.*?>", "", flagxml)
+ result.append(flagtext)
+ first_run = False
+
+ return result
+
+
+def _get_upstream_bugtracker(node):
+ """WRITE IT"""
+
+ bt_loc = [e.text for e in node.findall("bugs-to")]
+
+ return format_list(bt_loc, "Bugs to: ", " " * 12, force_quiet=True)
+
+
+def _get_upstream_changelog(node):
+ """WRITE IT"""
+
+ cl_paths = [e.text for e in node.findall("changelog")]
+
+ return format_list(cl_paths, "Changelog: ", " " * 12, force_quiet=True)
+
+
+def _get_upstream_documentation(node):
+ """WRITE IT"""
+
+ doc = []
+ for elem in node.findall("doc"):
+ lang = elem.get("lang")
+ if lang:
+ lang = "(%s)" % pp.output.yellow(lang)
+ else:
+ lang = ""
+ doc.append(" ".join([elem.text, lang]))
+
+ return format_list(doc, "Docs: ", " " * 12, force_quiet=True)
+
+
+def _get_upstream_maintainer(node):
+ """WRITE IT"""
+
+ maintainer = node.findall("maintainer")
+ maint = []
+ for elem in maintainer:
+ name = elem.find("name")
+ email = elem.find("email")
+ if elem.get("status") == "active":
+ status = "(%s)" % pp.output.green("active")
+ elif elem.get("status") == "inactive":
+ status = "(%s)" % pp.output.red("inactive")
+ elif elem.get("status"):
+ status = "(" + elem.get("status") + ")"
+ else:
+ status = ""
+ maint.append(" ".join([name.text, email.text, status]))
+
+ return format_list(maint, "Maintainer: ", " " * 12, force_quiet=True)
+
+
+def _get_upstream_remoteid(node):
+ """WRITE IT"""
+
+ r_id = [e.get("type") + ": " + e.text for e in node.findall("remote-id")]
+
+ return format_list(r_id, "Remote ID: ", " " * 12, force_quiet=True)
+
+
+def get_upstream(xml_tree):
+ """Return a list of formatted <upstream> lines, including blank elements
+ where blank lines should be printed."""
+
+ first_run = True
+ result = []
+ for node in xml_tree.findall("upstream"):
+ if not first_run:
+ result.append("")
+
+ maint = _get_upstream_maintainer(node)
+ if maint:
+ result.append("\n".join(maint))
+
+ changelog = _get_upstream_changelog(node)
+ if changelog:
+ result.append("\n".join(changelog))
+
+ documentation = _get_upstream_documentation(node)
+ if documentation:
+ result.append("\n".join(documentation))
+
+ bugs_to = _get_upstream_bugtracker(node)
+ if bugs_to:
+ result.append("\n".join(bugs_to))
+
+ remote_id = _get_upstream_remoteid(node)
+ if remote_id:
+ result.append("\n".join(remote_id))
+
+ first_run = False
+
+ return result
+
+
+def print_sequence(seq):
+ """Print each element of a sequence."""
+
+ for elem in seq:
+ print elem
+
+
+def uniqify(seq, preserve_order=True):
+ """Return a uniqified list. Optionally preserve order."""
+
+ if preserve_order:
+ seen = set()
+ result = [x for x in seq if x not in seen and not seen.add(x)]
+ else:
+ result = list(set(seq))
+
+ return result
+
+
+def print_file(path):
+ """Display the contents of a file."""
+
+ with open(path) as open_file:
+ lines = open_file.read()
+ print lines.strip()
+
+
+def parse_module_options(module_opts):
+ """Parse module options and update GLOBAL_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ for opt in opts:
+ if opt in ('-h', '--help'):
+ print_help()
+ sys.exit(0)
+ elif opt in ('-c', '--current'):
+ QUERY_OPTS["current"] = True
+ elif opt in ('-d', '--description'):
+ QUERY_OPTS["description"] = True
+ elif opt in ('-H', '--herd'):
+ QUERY_OPTS["herd"] = True
+ elif opt in ('-m', '--maintainer'):
+ QUERY_OPTS["maintainer"] = True
+ elif opt in ('-u', '--useflags'):
+ QUERY_OPTS["useflags"] = True
+ elif opt in ('-U', '--upstream'):
+ QUERY_OPTS["upstream"] = True
+ elif opt in ('-x', '--xml'):
+ QUERY_OPTS["xml"] = True
+
+
+def main(input_args):
+ """Parse input and run the program."""
+
+ short_opts = "hcdHmuUx"
+ long_opts = ('help', 'current', 'description', 'herd', 'maintainer',
+ 'useflags', 'upstream', 'xml')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Module %s" % err)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ package_dir = get_package_directory(queries)
+ if not package_dir:
+ raise errors.GentoolkitNoMatches(queries)
+
+ metadata_path = [os.path.join(d, "metadata.xml") for d in package_dir]
+
+ # --------------------------------
+ # Check options and call functions
+ # --------------------------------
+
+ first_run = True
+ for p_dir, meta in zip(package_dir, metadata_path):
+ if not first_run:
+ print
+
+ if VERBOSE:
+ print get_overlay_name(p_dir)
+
+ try:
+ xml_tree = ET.parse(meta)
+ except IOError:
+ pp.print_error("No metadata available")
+ first_run = False
+ continue
+
+ got_opts = False
+ if (QUERY_OPTS["herd"] or QUERY_OPTS["description"] or
+ QUERY_OPTS["useflags"] or QUERY_OPTS["maintainer"] or
+ QUERY_OPTS["upstream"] or QUERY_OPTS["xml"]):
+ # Specific information requested, less formatting
+ got_opts = True
+
+ call_get_functions(xml_tree, meta, got_opts)
+
+ first_run = False
diff --git a/pym/gentoolkit/equery/size.py b/pym/gentoolkit/equery/size.py
new file mode 100644
index 0000000..59f45d8
--- /dev/null
+++ b/pym/gentoolkit/equery/size.py
@@ -0,0 +1,199 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header: $
+
+"""Print total size of files contained in a given package"""
+
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import sys
+from getopt import gnu_getopt, GetoptError
+
+import gentoolkit.pprinter as pp
+from gentoolkit.equery import format_options, mod_usage, Config
+from gentoolkit.helpers2 import do_lookup
+
+# =======
+# Globals
+# =======
+
+QUERY_OPTS = {
+ "categoryFilter": None,
+ "includeInstalled": False,
+ "includePortTree": False,
+ "includeOverlayTree": False,
+ "includeMasked": True,
+ "isRegex": False,
+ "matchExact": False,
+ "printMatchInfo": False,
+ "sizeInBytes": False
+}
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print __doc__.strip()
+ print
+
+ # Deprecation warning added 04/09: djanderson
+ pp.print_warn("Default action for this module has changed in Gentoolkit 0.3.")
+ pp.print_warn("-e, --exact-name is now the default behavior.")
+ pp.print_warn("Use globbing to simulate the old behavior (see man equery).")
+ pp.print_warn("Use '*' to check all installed packages.")
+ print
+
+ print mod_usage(mod_name="size")
+ print
+ print pp.command("options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -b, --bytes", "report size in bytes"),
+ (" -c, --category CAT", "only search in the category CAT"),
+ (" -f, --full-regex", "query is a regular expression")
+ ))
+
+
+def display_size(match_set):
+ """Display the total size of all accessible files owned by packages.
+
+ @type match_set: list
+ @param match_set: package cat/pkg-ver strings
+ """
+
+ for pkg in match_set:
+ (size, files, uncounted) = pkg.size()
+
+ if Config["piping"]:
+ info = "%s: total(%d), inaccessible(%d), size(%s)"
+ print info % (pkg.cpv, files, uncounted, size)
+ else:
+ print " * %s" % pp.cpv(pkg.cpv)
+ print "Total files : %s".rjust(25) % pp.number(str(files))
+
+ if uncounted:
+ pp.print_info(0, "Inaccessible files : %s".rjust(25) %
+ pp.number(str(uncounted)))
+
+ if QUERY_OPTS["sizeInBytes"]:
+ size_str = pp.number(str(size))
+ else:
+ size_str = "%s %s" % format_bytes(size)
+
+ pp.print_info(0, "Total size : %s".rjust(25) % size_str)
+
+
+def format_bytes(bytes_, precision=2):
+ """Format bytes into human-readable format (IEC naming standard).
+
+ @see: http://mail.python.org/pipermail/python-list/2008-August/503423.html
+ @rtype: tuple
+ @return: (str(num), str(label))
+ """
+
+ labels = (
+ (1<<40L, 'TiB'),
+ (1<<30L, 'GiB'),
+ (1<<20L, 'MiB'),
+ (1<<10L, 'KiB'),
+ (1, 'bytes')
+ )
+
+ if bytes_ == 0:
+ return (pp.number('0'), 'bytes')
+ elif bytes_ == 1:
+ return (pp.number('1'), 'byte')
+
+ for factor, label in labels:
+ if not bytes_ >= factor:
+ continue
+
+ float_split = str(bytes_/float(factor)).split('.')
+ integer = float_split[0]
+ decimal = float_split[1]
+ if int(decimal[0:precision]):
+ float_string = '.'.join([integer, decimal[0:precision]])
+ else:
+ float_string = integer
+
+ return (pp.number(float_string), label)
+
+
+def parse_module_options(module_opts):
+ """Parse module options and update GLOBAL_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ posargs = (x[1] for x in module_opts)
+ for opt, posarg in zip(opts, posargs):
+ if opt in ('-h', '--help'):
+ print_help()
+ sys.exit(0)
+ elif opt in ('-b', '--bytes'):
+ QUERY_OPTS["sizeInBytes"] = True
+ elif opt in ('-c', '--category'):
+ QUERY_OPTS['categoryFilter'] = posarg
+ elif opt in ('-e', '--exact-name'):
+ pp.print_warn("-e, --exact-name is now default.")
+ pp.print_warn("Use globbing to simulate the old behavior.")
+ print
+ elif opt in ('-f', '--full-regex'):
+ QUERY_OPTS['isRegex'] = True
+
+
+def main(input_args):
+ """Parse input and run the program"""
+
+ # -e, --exact-name is no longer needed. Kept for compatibility.
+ # 04/09 djanderson
+ short_opts = "hbc:fe"
+ long_opts = ('help', 'bytes', 'category=', 'full-regex', 'exact-name')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Module %s" % err)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries and not QUERY_OPTS["includeInstalled"]:
+ print_help()
+ sys.exit(2)
+ elif queries and not QUERY_OPTS["includeInstalled"]:
+ QUERY_OPTS["includeInstalled"] = True
+ elif QUERY_OPTS["includeInstalled"]:
+ queries = ["*"]
+
+ #
+ # Output
+ #
+
+ first_run = True
+ for query in queries:
+ if not first_run:
+ print
+
+ matches = do_lookup(query, QUERY_OPTS)
+
+ if not matches:
+ pp.print_error("No package found matching %s" % query)
+
+ display_size(matches)
+
+ first_run = False
diff --git a/pym/gentoolkit/equery/uses.py b/pym/gentoolkit/equery/uses.py
new file mode 100644
index 0000000..2718613
--- /dev/null
+++ b/pym/gentoolkit/equery/uses.py
@@ -0,0 +1,340 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header: $
+
+"""Display USE flags for a given package"""
+
+# Move to imports section when Python 2.6 is stable
+from __future__ import with_statement
+
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import os
+import re
+import sys
+from getopt import gnu_getopt, GetoptError
+from glob import glob
+import xml.etree.cElementTree as ET
+
+from portage.util import unique_array
+
+import gentoolkit
+import gentoolkit.pprinter as pp
+from gentoolkit import errors
+from gentoolkit.equery import format_options, mod_usage, Config
+from gentoolkit.helpers2 import compare_package_strings, find_best_match, \
+ find_packages
+from gentoolkit.textwrap_ import TextWrapper
+
+# =======
+# Globals
+# =======
+
+QUERY_OPTS = {"allVersions" : False}
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print __doc__.strip()
+ print
+ print mod_usage(mod_name=__name__.split('.')[-1])
+ print
+ print pp.command("options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -a, --all", "include all package versions")
+ ))
+
+
+def display_useflags(output):
+ """Print USE flag descriptions and statuses.
+
+ @type output: list
+ @param output: [(inuse, inused, flag, desc, restrict), ...]
+ inuse (int) = 0 or 1; if 1, flag is set in make.conf
+ inused (int) = 0 or 1; if 1, package is installed with flag enabled
+ flag (str) = the name of the USE flag
+ desc (str) = the flag's description
+ restrict (str) = corresponds to the text of restrict in metadata
+ """
+
+ maxflag_len = len(max([t[2] for t in output], key=len))
+
+ twrap = TextWrapper()
+ twrap.width = Config['termWidth']
+ twrap.subsequent_indent = " " * (maxflag_len + 8)
+
+ markers = ("-", "+")
+ color = [pp.useflagoff, pp.useflagon]
+ for in_makeconf, in_installed, flag, desc, restrict in output:
+ if Config["piping"]:
+ pp.print_info(0, markers[in_makeconf] + flag)
+ else:
+ flag_name = ""
+ if in_makeconf != in_installed:
+ flag_name += pp.emph(" %s %s" %
+ (markers[in_makeconf], markers[in_installed]))
+ else:
+ flag_name += (" %s %s" %
+ (markers[in_makeconf], markers[in_installed]))
+
+ flag_name += " " + color[in_makeconf](flag.ljust(maxflag_len))
+ flag_name += " : "
+
+ # print description
+ if restrict:
+ restrict = "(%s %s)" % (pp.emph("Restricted to"),
+ pp.cpv(restrict))
+ twrap.initial_indent = flag_name
+ pp.print_info(0, twrap.fill(restrict))
+ if desc:
+ twrap.initial_indent = twrap.subsequent_indent
+ pp.print_info(0, twrap.fill(desc))
+ else:
+ pp.print_info(0, " : <unknown>")
+ else:
+ if desc:
+ twrap.initial_indent = flag_name
+ desc = twrap.fill(desc)
+ pp.print_info(0, desc)
+ else:
+ twrap.initial_indent = flag_name
+ pp.print_info(0, twrap.fill("<unknown>"))
+
+
+def get_global_useflags():
+ """Get global and expanded USE flag variables from
+ PORTDIR/profiles/use.desc and PORTDIR/profiles/desc/*.desc respectively.
+
+ @rtype: dict
+ @return: {'flag_name': 'flag description', ...}
+ """
+
+ global_usedesc = {}
+ # Get global USE flag descriptions
+ try:
+ path = os.path.join(gentoolkit.settings["PORTDIR"], 'profiles',
+ 'use.desc')
+ with open(path) as open_file:
+ for line in open_file:
+ if line.startswith('#'):
+ continue
+ # Ex. of fields: ['syslog', 'Enables support for syslog\n']
+ fields = line.split(" - ", 1)
+ if len(fields) == 2:
+ global_usedesc[fields[0]] = fields[1].rstrip()
+ except IOError:
+ pp.print_warn("Could not load USE flag descriptions from %s" %
+ pp.path(path))
+
+ del path, open_file
+ # Add USE_EXPANDED variables to usedesc hash -- Bug #238005
+ for path in glob(os.path.join(gentoolkit.settings["PORTDIR"],
+ 'profiles', 'desc', '*.desc')):
+ try:
+ with open(path) as open_file:
+ for line in open_file:
+ if line.startswith('#'):
+ continue
+ fields = [field.strip() for field in line.split(" - ", 1)]
+ if len(fields) == 2:
+ expanded_useflag = "%s_%s" % \
+ (path.split("/")[-1][0:-5], fields[0])
+ global_usedesc[expanded_useflag] = fields[1]
+ except IOError:
+ pp.print_warn("Could not load USE flag descriptions from %s" %
+ path)
+
+ return global_usedesc
+
+
+def get_local_useflags(pkg):
+ """Parse package-specific flag descriptions from a package's metadata.xml.
+
+ @see: http://www.gentoo.org/proj/en/glep/glep-0056.html
+ @type pkg: gentoolkit.package.Package
+ @param pkg: the package to find useflags for
+ @rtype: dict
+ @return: {string: tuple}
+ string = flag's name
+ tuple = (description, restrictions)
+ """
+
+ result = {}
+
+ metadata = os.path.join(pkg.get_package_path(), 'metadata.xml')
+ try:
+ xml_tree = ET.parse(metadata)
+ except IOError:
+ pp.print_error("Could not open %s" % metadata)
+ return result
+
+ for node in xml_tree.getiterator("flag"):
+ name = node.get("name")
+ restrict = node.get("restrict")
+ # ElementTree handles nested element text in a funky way.
+ # So we need to dump the raw XML and parse it manually.
+ flagxml = ET.tostring(node)
+ flagxml = re.sub("\s+", " ", flagxml)
+ flagxml = re.sub("\n\t", "", flagxml)
+ flagxml = re.sub("<(pkg|cat)>([^<]*)</(pkg|cat)>",
+ pp.cpv("%s" % r"\2"), flagxml)
+ flagtext = re.sub("<.*?>", "", flagxml)
+ result[name] = (flagtext, restrict)
+
+ return result
+
+
+def get_matches(query):
+ """Get packages matching query."""
+
+ if not QUERY_OPTS["allVersions"]:
+ matches = [find_best_match(query)]
+ if None in matches:
+ matches = find_packages(query, include_masked=False)
+ if matches:
+ matches = sorted(matches, compare_package_strings)[-1:]
+ else:
+ matches = find_packages(query, include_masked=True)
+
+ if not matches:
+ raise errors.GentoolkitNoMatches(query)
+
+ return matches
+
+
+def get_output_descriptions(pkg, global_usedesc):
+ """Prepare descriptions and usage information for each USE flag."""
+
+ local_usedesc = get_local_useflags(pkg)
+ iuse = pkg.get_env_var("IUSE")
+
+ if iuse:
+ usevar = unique_array([x.lstrip('+-') for x in iuse.split()])
+ usevar.sort()
+ else:
+ usevar = []
+
+ if pkg.is_installed():
+ used_flags = pkg.get_use_flags().split()
+ else:
+ used_flags = gentoolkit.settings["USE"].split()
+
+ # store (inuse, inused, flag, desc, restrict)
+ output = []
+ for flag in usevar:
+ inuse = False
+ inused = False
+ try:
+ desc = local_usedesc[flag][0]
+ except KeyError:
+ try:
+ desc = global_usedesc[flag]
+ except KeyError:
+ desc = ""
+ try:
+ restrict = local_usedesc[flag][1]
+ except KeyError:
+ restrict = ""
+
+ if flag in pkg.get_settings("USE").split():
+ inuse = True
+ if flag in used_flags:
+ inused = True
+
+ output.append((inuse, inused, flag, desc, restrict))
+
+ return output
+
+
+def parse_module_options(module_opts):
+ """Parse module options and update GLOBAL_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ for opt in opts:
+ if opt in ('-h', '--help'):
+ print_help()
+ sys.exit(0)
+ elif opt in ('-a', '--all'):
+ QUERY_OPTS['allVersions'] = True
+
+
+def print_legend(query):
+ """Print a legend to explain the output format."""
+
+ if not Config['piping']:
+ pp.print_info(3, " * Searching for packages matching %s ..." %
+ pp.pkgquery(query))
+ pp.print_info(3, "[ Legend : %s - flag is set in make.conf ]"
+ % pp.emph("U"))
+ pp.print_info(3, "[ : %s - package is installed with flag ]"
+ % pp.emph("I"))
+ pp.print_info(3, "[ Colors : %s, %s ]" %
+ (pp.useflagon("set"), pp.useflagoff("unset")))
+
+
+def main(input_args):
+ """Parse input and run the program"""
+
+ short_opts = "ha"
+ long_opts = ('help', 'all')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Module %s" % err)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ #
+ # Output
+ #
+
+ first_run = True
+ for query in queries:
+ if not first_run:
+ print
+
+ print_legend(query)
+
+ matches = get_matches(query)
+ matches.sort()
+
+ global_usedesc = get_global_useflags()
+ for pkg in matches:
+
+ output = get_output_descriptions(pkg, global_usedesc)
+ if output:
+ if not Config['piping']:
+ pp.print_info(3, "[ Found these USE flags for %s ]" %
+ pp.cpv(pkg.cpv))
+ pp.print_info(3, pp.emph(" U I"))
+ display_useflags(output)
+ else:
+ if not Config['piping']:
+ pp.print_info(3, "[ No USE flags found for %s ]" %
+ pp.cpv(pkg.cpv))
+
+ first_run = False
diff --git a/pym/gentoolkit/equery/which.py b/pym/gentoolkit/equery/which.py
new file mode 100644
index 0000000..4cae712
--- /dev/null
+++ b/pym/gentoolkit/equery/which.py
@@ -0,0 +1,98 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header: $
+
+"""Display the path to the ebuild that would be used by Portage with the current
+configuration
+"""
+
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import os
+import sys
+from getopt import gnu_getopt, GetoptError
+
+import gentoolkit.pprinter as pp
+from gentoolkit import errors
+from gentoolkit.equery import format_options, mod_usage
+from gentoolkit.helpers2 import find_packages
+
+# =======
+# Globals
+# =======
+
+QUERY_OPTS = {"includeMasked": False}
+
+# =========
+# Functions
+# =========
+
+def print_help(with_description=True):
+ """Print description, usage and a detailed help message.
+
+ @type with_description: bool
+ @param with_description: if true, print module's __doc__ string
+ """
+
+ if with_description:
+ print __doc__.strip()
+ print
+ print mod_usage(mod_name="which")
+ print
+ print pp.command("options")
+ print format_options((
+ (" -h, --help", "display this help message"),
+ (" -m, --include-masked", "return highest version ebuild available")
+ ))
+
+
+def parse_module_options(module_opts):
+ """Parse module options and update GLOBAL_OPTS"""
+
+ opts = (x[0] for x in module_opts)
+ for opt in opts:
+ if opt in ('-h', '--help'):
+ print_help()
+ sys.exit(0)
+ elif opt in ('-m', '--include-masked'):
+ QUERY_OPTS['includeMasked'] = True
+
+
+def main(input_args):
+ """Parse input and run the program"""
+
+ short_opts = "hm"
+ long_opts = ('help', 'include-masked')
+
+ try:
+ module_opts, queries = gnu_getopt(input_args, short_opts, long_opts)
+ except GetoptError, err:
+ pp.print_error("Module %s" % err)
+ print
+ print_help(with_description=False)
+ sys.exit(2)
+
+ parse_module_options(module_opts)
+
+ if not queries:
+ print_help()
+ sys.exit(2)
+
+ for query in queries:
+
+ matches = find_packages(query, QUERY_OPTS['includeMasked'])
+ if matches:
+ pkg = sorted(matches).pop()
+ ebuild_path = pkg.get_ebuild_path()
+ if ebuild_path:
+ pp.print_info(0, os.path.normpath(ebuild_path))
+ else:
+ pp.print_warn("No ebuilds to satisfy %s" % pkg.name)
+ else:
+ raise errors.GentoolkitNoMatches(query)
diff --git a/pym/gentoolkit/errors.py b/pym/gentoolkit/errors.py
new file mode 100644
index 0000000..c635192
--- /dev/null
+++ b/pym/gentoolkit/errors.py
@@ -0,0 +1,92 @@
+# Copyright(c) 2004-2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2 or later
+
+"""Exception classes for gentoolkit"""
+
+__all__ = [
+ 'FatalError',
+ 'GentoolkitException',
+ 'GentoolkitInvalidAtom',
+ 'GentoolkitInvalidCategory',
+ 'GentoolkitInvalidPackageName',
+ 'GentoolkitInvalidCPV',
+ 'GentoolkitInvalidRegex',
+ 'GentoolkitNoMatches'
+]
+
+# =======
+# Imports
+# =======
+
+import sys
+
+import gentoolkit.pprinter as pp
+
+# ==========
+# Exceptions
+# ==========
+
+class GentoolkitException(Exception):
+ """Base class for gentoolkit exceptions"""
+ def __init__(self):
+ pass
+
+
+class GentoolkitFatalError(GentoolkitException):
+ """A fatal error occurred. Usually used to catch Portage exceptions."""
+ def __init__(self, err):
+ pp.print_error("Fatal error: %s" % err)
+ sys.exit(2)
+
+
+class GentoolkitInvalidAtom(GentoolkitException):
+ """Got a malformed package atom"""
+ def __init__(self, atom):
+ pp.print_error("Invalid atom: '%s'" % atom)
+ sys.exit(2)
+
+
+class GentoolkitInvalidCategory(GentoolkitException):
+ """The category was not listed in portage.settings.categories"""
+ def __init__(self, category):
+ pp.print_error("Invalid category: '%s'" % category)
+ if not category:
+ pp.print_error("Try --category=cat1,cat2 with no spaces.")
+ sys.exit(2)
+
+
+class GentoolkitInvalidPackageName(GentoolkitException):
+ """Got an unknown package name"""
+ def __init__(self, package):
+ pp.print_error("Invalid package name: '%s'" % package)
+ sys.exit(2)
+
+
+class GentoolkitInvalidCPV(GentoolkitException):
+ """Got an unknown package name"""
+ def __init__(self, cpv):
+ pp.print_error("Invalid CPV: '%s'" % cpv)
+ sys.exit(2)
+
+
+class GentoolkitInvalidRegex(GentoolkitException):
+ """The regex could not be compiled"""
+ def __init__(self, regex):
+ pp.print_error("Invalid regex: '%s'" % regex)
+ sys.exit(2)
+
+
+class GentoolkitNoMatches(GentoolkitException):
+ """No packages were found matching the search query"""
+ def __init__(self, query):
+ pp.print_error("No packages matching '%s'" % query)
+ sys.exit(2)
+
+
+# XXX: Deprecated
+class FatalError:
+ def __init__(self, s):
+ self._message = s
+ def get_message(self):
+ return self._message
diff --git a/pym/gentoolkit/glsa/__init__.py b/pym/gentoolkit/glsa/__init__.py
new file mode 100644
index 0000000..4c8f280
--- /dev/null
+++ b/pym/gentoolkit/glsa/__init__.py
@@ -0,0 +1,644 @@
+# $Header$
+
+# This program is licensed under the GPL, version 2
+
+# WARNING: this code is only tested by a few people and should NOT be used
+# on production systems at this stage. There are possible security holes and probably
+# bugs in this code. If you test it please report ANY success or failure to
+# me (genone@gentoo.org).
+
+# The following planned features are currently on hold:
+# - getting GLSAs from http/ftp servers (not really useful without the fixed ebuilds)
+# - GPG signing/verification (until key policy is clear)
+
+__author__ = "Marius Mauch <genone@gentoo.org>"
+
+import os
+import sys
+import urllib
+import time
+import codecs
+import re
+import xml.dom.minidom
+
+if sys.version_info[0:2] < (2,3):
+ raise NotImplementedError("Python versions below 2.3 have broken XML code " \
+ +"and are not supported")
+
+try:
+ import portage
+except ImportError:
+ sys.path.insert(0, "/usr/lib/portage/pym")
+ import portage
+
+# Note: the space for rgt and rlt is important !!
+opMapping = {"le": "<=", "lt": "<", "eq": "=", "gt": ">", "ge": ">=",
+ "rge": ">=~", "rle": "<=~", "rgt": " >~", "rlt": " <~"}
+NEWLINE_ESCAPE = "!;\\n" # some random string to mark newlines that should be preserved
+SPACE_ESCAPE = "!;_" # some random string to mark spaces that should be preserved
+
+def center(text, width):
+ """
+ Returns a string containing I{text} that is padded with spaces on both
+ sides. If C{len(text) >= width} I{text} is returned unchanged.
+
+ @type text: String
+ @param text: the text to be embedded
+ @type width: Integer
+ @param width: the minimum length of the returned string
+ @rtype: String
+ @return: the expanded string or I{text}
+ """
+ if len(text) >= width:
+ return text
+ margin = (width-len(text))/2
+ rValue = " "*margin
+ rValue += text
+ if 2*margin + len(text) == width:
+ rValue += " "*margin
+ elif 2*margin + len(text) + 1 == width:
+ rValue += " "*(margin+1)
+ return rValue
+
+
+def wrap(text, width, caption=""):
+ """
+ Wraps the given text at column I{width}, optionally indenting
+ it so that no text is under I{caption}. It's possible to encode
+ hard linebreaks in I{text} with L{NEWLINE_ESCAPE}.
+
+ @type text: String
+ @param text: the text to be wrapped
+ @type width: Integer
+ @param width: the column at which the text should be wrapped
+ @type caption: String
+ @param caption: this string is inserted at the beginning of the
+ return value and the paragraph is indented up to
+ C{len(caption)}.
+ @rtype: String
+ @return: the wrapped and indented paragraph
+ """
+ rValue = ""
+ line = caption
+ text = text.replace(2*NEWLINE_ESCAPE, NEWLINE_ESCAPE+" "+NEWLINE_ESCAPE)
+ words = text.split()
+ indentLevel = len(caption)+1
+
+ for w in words:
+ if line[-1] == "\n":
+ rValue += line
+ line = " "*indentLevel
+ if len(line)+len(w.replace(NEWLINE_ESCAPE, ""))+1 > width:
+ rValue += line+"\n"
+ line = " "*indentLevel+w.replace(NEWLINE_ESCAPE, "\n")
+ elif w.find(NEWLINE_ESCAPE) >= 0:
+ if len(line.strip()) > 0:
+ rValue += line+" "+w.replace(NEWLINE_ESCAPE, "\n")
+ else:
+ rValue += line+w.replace(NEWLINE_ESCAPE, "\n")
+ line = " "*indentLevel
+ else:
+ if len(line.strip()) > 0:
+ line += " "+w
+ else:
+ line += w
+ if len(line) > 0:
+ rValue += line.replace(NEWLINE_ESCAPE, "\n")
+ rValue = rValue.replace(SPACE_ESCAPE, " ")
+ return rValue
+
+def checkconfig(myconfig):
+ """
+ takes a portage.config instance and adds GLSA specific keys if
+ they are not present. TO-BE-REMOVED (should end up in make.*)
+ """
+ mysettings = {
+ "GLSA_DIR": portage.settings["PORTDIR"]+"/metadata/glsa/",
+ "GLSA_PREFIX": "glsa-",
+ "GLSA_SUFFIX": ".xml",
+ "CHECKFILE": "/var/cache/edb/glsa",
+ "GLSA_SERVER": "www.gentoo.org/security/en/glsa/", # not completely implemented yet
+ "CHECKMODE": "local", # not completely implemented yet
+ "PRINTWIDTH": "76"
+ }
+ for k in mysettings.keys():
+ if k not in myconfig:
+ myconfig[k] = mysettings[k]
+ return myconfig
+
+def get_glsa_list(repository, myconfig):
+ """
+ Returns a list of all available GLSAs in the given repository
+ by comparing the filelist there with the pattern described in
+ the config.
+
+ @type repository: String
+ @param repository: The directory or an URL that contains GLSA files
+ (Note: not implemented yet)
+ @type myconfig: portage.config
+ @param myconfig: a GLSA aware config instance (see L{checkconfig})
+
+ @rtype: List of Strings
+ @return: a list of GLSA IDs in this repository
+ """
+ # TODO: remote fetch code for listing
+
+ rValue = []
+
+ if not os.access(repository, os.R_OK):
+ return []
+ dirlist = os.listdir(repository)
+ prefix = myconfig["GLSA_PREFIX"]
+ suffix = myconfig["GLSA_SUFFIX"]
+
+ for f in dirlist:
+ try:
+ if f[:len(prefix)] == prefix:
+ rValue.append(f[len(prefix):-1*len(suffix)])
+ except IndexError:
+ pass
+ return rValue
+
+def getListElements(listnode):
+ """
+ Get all <li> elements for a given <ol> or <ul> node.
+
+ @type listnode: xml.dom.Node
+ @param listnode: <ul> or <ol> list to get the elements for
+ @rtype: List of Strings
+ @return: a list that contains the value of the <li> elements
+ """
+ rValue = []
+ if not listnode.nodeName in ["ul", "ol"]:
+ raise GlsaFormatException("Invalid function call: listnode is not <ul> or <ol>")
+ for li in listnode.childNodes:
+ if li.nodeType != xml.dom.Node.ELEMENT_NODE:
+ continue
+ rValue.append(getText(li, format="strip"))
+ return rValue
+
+def getText(node, format):
+ """
+ This is the main parser function. It takes a node and traverses
+ recursive over the subnodes, getting the text of each (and the
+ I{link} attribute for <uri> and <mail>). Depending on the I{format}
+ parameter the text might be formatted by adding/removing newlines,
+ tabs and spaces. This function is only useful for the GLSA DTD,
+ it's not applicable for other DTDs.
+
+ @type node: xml.dom.Node
+ @param node: the root node to start with the parsing
+ @type format: String
+ @param format: this should be either I{strip}, I{keep} or I{xml}
+ I{keep} just gets the text and does no formatting.
+ I{strip} replaces newlines and tabs with spaces and
+ replaces multiple spaces with one space.
+ I{xml} does some more formatting, depending on the
+ type of the encountered nodes.
+ @rtype: String
+ @return: the (formatted) content of the node and its subnodes
+ """
+ rValue = ""
+ if format in ["strip", "keep"]:
+ if node.nodeName in ["uri", "mail"]:
+ rValue += node.childNodes[0].data+": "+node.getAttribute("link")
+ else:
+ for subnode in node.childNodes:
+ if subnode.nodeName == "#text":
+ rValue += subnode.data
+ else:
+ rValue += getText(subnode, format)
+ else:
+ for subnode in node.childNodes:
+ if subnode.nodeName == "p":
+ for p_subnode in subnode.childNodes:
+ if p_subnode.nodeName == "#text":
+ rValue += p_subnode.data.strip()
+ elif p_subnode.nodeName in ["uri", "mail"]:
+ rValue += p_subnode.childNodes[0].data
+ rValue += " ( "+p_subnode.getAttribute("link")+" )"
+ rValue += NEWLINE_ESCAPE
+ elif subnode.nodeName == "ul":
+ for li in getListElements(subnode):
+ rValue += "-"+SPACE_ESCAPE+li+NEWLINE_ESCAPE+" "
+ elif subnode.nodeName == "ol":
+ i = 0
+ for li in getListElements(subnode):
+ i = i+1
+ rValue += str(i)+"."+SPACE_ESCAPE+li+NEWLINE_ESCAPE+" "
+ elif subnode.nodeName == "code":
+ rValue += getText(subnode, format="keep").replace("\n", NEWLINE_ESCAPE)
+ if rValue[-1*len(NEWLINE_ESCAPE):] != NEWLINE_ESCAPE:
+ rValue += NEWLINE_ESCAPE
+ elif subnode.nodeName == "#text":
+ rValue += subnode.data
+ else:
+ raise GlsaFormatException("Invalid Tag found: ", subnode.nodeName)
+ if format == "strip":
+ rValue = rValue.strip(" \n\t")
+ rValue = re.sub("[\s]{2,}", " ", rValue)
+ # Hope that the utf conversion doesn't break anything else
+ return rValue.encode("utf_8")
+
+def getMultiTagsText(rootnode, tagname, format):
+ """
+ Returns a list with the text of all subnodes of type I{tagname}
+ under I{rootnode} (which itself is not parsed) using the given I{format}.
+
+ @type rootnode: xml.dom.Node
+ @param rootnode: the node to search for I{tagname}
+ @type tagname: String
+ @param tagname: the name of the tags to search for
+ @type format: String
+ @param format: see L{getText}
+ @rtype: List of Strings
+ @return: a list containing the text of all I{tagname} childnodes
+ """
+ rValue = []
+ for e in rootnode.getElementsByTagName(tagname):
+ rValue.append(getText(e, format))
+ return rValue
+
+def makeAtom(pkgname, versionNode):
+ """
+ creates from the given package name and information in the
+ I{versionNode} a (syntactical) valid portage atom.
+
+ @type pkgname: String
+ @param pkgname: the name of the package for this atom
+ @type versionNode: xml.dom.Node
+ @param versionNode: a <vulnerable> or <unaffected> Node that
+ contains the version information for this atom
+ @rtype: String
+ @return: the portage atom
+ """
+ rValue = opMapping[versionNode.getAttribute("range")] \
+ + pkgname \
+ + "-" + getText(versionNode, format="strip")
+ return str(rValue)
+
+def makeVersion(versionNode):
+ """
+ creates from the information in the I{versionNode} a
+ version string (format <op><version>).
+
+ @type versionNode: xml.dom.Node
+ @param versionNode: a <vulnerable> or <unaffected> Node that
+ contains the version information for this atom
+ @rtype: String
+ @return: the version string
+ """
+ return opMapping[versionNode.getAttribute("range")] \
+ +getText(versionNode, format="strip")
+
+def match(atom, portdbname, match_type="default"):
+ """
+ wrapper that calls revisionMatch() or portage.dbapi.match() depending on
+ the given atom.
+
+ @type atom: string
+ @param atom: a <~ or >~ atom or a normal portage atom that contains the atom to match against
+ @type portdb: portage.dbapi
+ @param portdb: one of the portage databases to use as information source
+ @type match_type: string
+ @param match_type: if != "default" passed as first argument to dbapi.xmatch
+ to apply the wanted visibility filters
+
+ @rtype: list of strings
+ @return: a list with the matching versions
+ """
+ db = portage.db["/"][portdbname].dbapi
+ if atom[2] == "~":
+ return revisionMatch(atom, db, match_type=match_type)
+ elif match_type == "default" or not hasattr(db, "xmatch"):
+ return db.match(atom)
+ else:
+ return db.xmatch(match_type, atom)
+
+def revisionMatch(revisionAtom, portdb, match_type="default"):
+ """
+ handler for the special >~, >=~, <=~ and <~ atoms that are supposed to behave
+ as > and < except that they are limited to the same version, the range only
+ applies to the revision part.
+
+ @type revisionAtom: string
+ @param revisionAtom: a <~ or >~ atom that contains the atom to match against
+ @type portdb: portage.dbapi
+ @param portdb: one of the portage databases to use as information source
+ @type match_type: string
+ @param match_type: if != "default" passed as first argument to portdb.xmatch
+ to apply the wanted visibility filters
+
+ @rtype: list of strings
+ @return: a list with the matching versions
+ """
+ if match_type == "default" or not hasattr(portdb, "xmatch"):
+ mylist = portdb.match(re.sub("-r[0-9]+$", "", revisionAtom[2:]))
+ else:
+ mylist = portdb.xmatch(match_type, re.sub("-r[0-9]+$", "", revisionAtom[2:]))
+ rValue = []
+ for v in mylist:
+ r1 = portage.pkgsplit(v)[-1][1:]
+ r2 = portage.pkgsplit(revisionAtom[3:])[-1][1:]
+ if eval(r1+" "+revisionAtom[0:2]+" "+r2):
+ rValue.append(v)
+ return rValue
+
+
+def getMinUpgrade(vulnerableList, unaffectedList, minimize=True):
+ """
+ Checks if the systemstate is matching an atom in
+ I{vulnerableList} and returns string describing
+ the lowest version for the package that matches an atom in
+ I{unaffectedList} and is greater than the currently installed
+ version or None if the system is not affected. Both
+ I{vulnerableList} and I{unaffectedList} should have the
+ same base package.
+
+ @type vulnerableList: List of Strings
+ @param vulnerableList: atoms matching vulnerable package versions
+ @type unaffectedList: List of Strings
+ @param unaffectedList: atoms matching unaffected package versions
+ @type minimize: Boolean
+ @param minimize: True for a least-change upgrade, False for emerge-like algorithm
+
+ @rtype: String | None
+ @return: the lowest unaffected version that is greater than
+ the installed version.
+ """
+ rValue = None
+ v_installed = []
+ u_installed = []
+ for v in vulnerableList:
+ v_installed += match(v, "vartree")
+
+ for u in unaffectedList:
+ u_installed += match(u, "vartree")
+
+ install_unaffected = True
+ for i in v_installed:
+ if i not in u_installed:
+ install_unaffected = False
+
+ if install_unaffected:
+ return rValue
+
+ for u in unaffectedList:
+ mylist = match(u, "porttree", match_type="match-all")
+ for c in mylist:
+ c_pv = portage.catpkgsplit(c)
+ i_pv = portage.catpkgsplit(portage.best(v_installed))
+ if portage.pkgcmp(c_pv[1:], i_pv[1:]) > 0 \
+ and (rValue == None \
+ or not match("="+rValue, "porttree") \
+ or (minimize ^ (portage.pkgcmp(c_pv[1:], portage.catpkgsplit(rValue)[1:]) > 0)) \
+ and match("="+c, "porttree")) \
+ and portage.db["/"]["porttree"].dbapi.aux_get(c, ["SLOT"]) == portage.db["/"]["vartree"].dbapi.aux_get(portage.best(v_installed), ["SLOT"]):
+ rValue = c_pv[0]+"/"+c_pv[1]+"-"+c_pv[2]
+ if c_pv[3] != "r0": # we don't like -r0 for display
+ rValue += "-"+c_pv[3]
+ return rValue
+
+
+# simple Exception classes to catch specific errors
+class GlsaTypeException(Exception):
+ def __init__(self, doctype):
+ Exception.__init__(self, "wrong DOCTYPE: %s" % doctype)
+
+class GlsaFormatException(Exception):
+ pass
+
+class GlsaArgumentException(Exception):
+ pass
+
+# GLSA xml data wrapper class
+class Glsa:
+ """
+ This class is a wrapper for the XML data and provides methods to access
+ and display the contained data.
+ """
+ def __init__(self, myid, myconfig):
+ """
+ Simple constructor to set the ID, store the config and gets the
+ XML data by calling C{self.read()}.
+
+ @type myid: String
+ @param myid: String describing the id for the GLSA object (standard
+ GLSAs have an ID of the form YYYYMM-nn) or an existing
+ filename containing a GLSA.
+ @type myconfig: portage.config
+ @param myconfig: the config that should be used for this object.
+ """
+ if re.match(r'\d{6}-\d{2}', myid):
+ self.type = "id"
+ elif os.path.exists(myid):
+ self.type = "file"
+ else:
+ raise GlsaArgumentException("Given ID "+myid+" isn't a valid GLSA ID or filename.")
+ self.nr = myid
+ self.config = myconfig
+ self.read()
+
+ def read(self):
+ """
+ Here we build the filename from the config and the ID and pass
+ it to urllib to fetch it from the filesystem or a remote server.
+
+ @rtype: None
+ @return: None
+ """
+ if self.config["CHECKMODE"] == "local":
+ repository = "file://" + self.config["GLSA_DIR"]
+ else:
+ repository = self.config["GLSA_SERVER"]
+ if self.type == "file":
+ myurl = "file://"+self.nr
+ else:
+ myurl = repository + self.config["GLSA_PREFIX"] + str(self.nr) + self.config["GLSA_SUFFIX"]
+ self.parse(urllib.urlopen(myurl))
+ return None
+
+ def parse(self, myfile):
+ """
+ This method parses the XML file and sets up the internal data
+ structures by calling the different helper functions in this
+ module.
+
+ @type myfile: String
+ @param myfile: Filename to grab the XML data from
+ @rtype: None
+ @returns: None
+ """
+ self.DOM = xml.dom.minidom.parse(myfile)
+ if not self.DOM.doctype:
+ raise GlsaTypeException(None)
+ elif self.DOM.doctype.systemId != "http://www.gentoo.org/dtd/glsa.dtd":
+ raise GlsaTypeException(self.DOM.doctype.systemId)
+ myroot = self.DOM.getElementsByTagName("glsa")[0]
+ if self.type == "id" and myroot.getAttribute("id") != self.nr:
+ raise GlsaFormatException("filename and internal id don't match:" + myroot.getAttribute("id") + " != " + self.nr)
+
+ # the simple (single, required, top-level, #PCDATA) tags first
+ self.title = getText(myroot.getElementsByTagName("title")[0], format="strip")
+ self.synopsis = getText(myroot.getElementsByTagName("synopsis")[0], format="strip")
+ self.announced = getText(myroot.getElementsByTagName("announced")[0], format="strip")
+ self.revised = getText(myroot.getElementsByTagName("revised")[0], format="strip")
+
+ # now the optional and 0-n toplevel, #PCDATA tags and references
+ try:
+ self.access = getText(myroot.getElementsByTagName("access")[0], format="strip")
+ except IndexError:
+ self.access = ""
+ self.bugs = getMultiTagsText(myroot, "bug", format="strip")
+ self.references = getMultiTagsText(myroot.getElementsByTagName("references")[0], "uri", format="keep")
+
+ # and now the formatted text elements
+ self.description = getText(myroot.getElementsByTagName("description")[0], format="xml")
+ self.workaround = getText(myroot.getElementsByTagName("workaround")[0], format="xml")
+ self.resolution = getText(myroot.getElementsByTagName("resolution")[0], format="xml")
+ self.impact_text = getText(myroot.getElementsByTagName("impact")[0], format="xml")
+ self.impact_type = myroot.getElementsByTagName("impact")[0].getAttribute("type")
+ try:
+ self.background = getText(myroot.getElementsByTagName("background")[0], format="xml")
+ except IndexError:
+ self.background = ""
+
+ # finally the interesting tags (product, affected, package)
+ self.glsatype = myroot.getElementsByTagName("product")[0].getAttribute("type")
+ self.product = getText(myroot.getElementsByTagName("product")[0], format="strip")
+ self.affected = myroot.getElementsByTagName("affected")[0]
+ self.packages = {}
+ for p in self.affected.getElementsByTagName("package"):
+ name = p.getAttribute("name")
+ if not self.packages.has_key(name):
+ self.packages[name] = []
+ tmp = {}
+ tmp["arch"] = p.getAttribute("arch")
+ tmp["auto"] = (p.getAttribute("auto") == "yes")
+ tmp["vul_vers"] = [makeVersion(v) for v in p.getElementsByTagName("vulnerable")]
+ tmp["unaff_vers"] = [makeVersion(v) for v in p.getElementsByTagName("unaffected")]
+ tmp["vul_atoms"] = [makeAtom(name, v) for v in p.getElementsByTagName("vulnerable")]
+ tmp["unaff_atoms"] = [makeAtom(name, v) for v in p.getElementsByTagName("unaffected")]
+ self.packages[name].append(tmp)
+ # TODO: services aren't really used yet
+ self.services = self.affected.getElementsByTagName("service")
+ return None
+
+ def dump(self, outstream=sys.stdout):
+ """
+ Dumps a plaintext representation of this GLSA to I{outfile} or
+ B{stdout} if it is ommitted. You can specify an alternate
+ I{encoding} if needed (default is latin1).
+
+ @type outstream: File
+ @param outfile: Stream that should be used for writing
+ (defaults to sys.stdout)
+ """
+ width = int(self.config["PRINTWIDTH"])
+ outstream.write(center("GLSA %s: \n%s" % (self.nr, self.title), width)+"\n")
+ outstream.write((width*"=")+"\n")
+ outstream.write(wrap(self.synopsis, width, caption="Synopsis: ")+"\n")
+ outstream.write("Announced on: %s\n" % self.announced)
+ outstream.write("Last revised on: %s\n\n" % self.revised)
+ if self.glsatype == "ebuild":
+ for k in self.packages.keys():
+ pkg = self.packages[k]
+ for path in pkg:
+ vul_vers = "".join(path["vul_vers"])
+ unaff_vers = "".join(path["unaff_vers"])
+ outstream.write("Affected package: %s\n" % k)
+ outstream.write("Affected archs: ")
+ if path["arch"] == "*":
+ outstream.write("All\n")
+ else:
+ outstream.write("%s\n" % path["arch"])
+ outstream.write("Vulnerable: %s\n" % vul_vers)
+ outstream.write("Unaffected: %s\n\n" % unaff_vers)
+ elif self.glsatype == "infrastructure":
+ pass
+ if len(self.bugs) > 0:
+ outstream.write("\nRelated bugs: ")
+ for i in range(0, len(self.bugs)):
+ outstream.write(self.bugs[i])
+ if i < len(self.bugs)-1:
+ outstream.write(", ")
+ else:
+ outstream.write("\n")
+ if self.background:
+ outstream.write("\n"+wrap(self.background, width, caption="Background: "))
+ outstream.write("\n"+wrap(self.description, width, caption="Description: "))
+ outstream.write("\n"+wrap(self.impact_text, width, caption="Impact: "))
+ outstream.write("\n"+wrap(self.workaround, width, caption="Workaround: "))
+ outstream.write("\n"+wrap(self.resolution, width, caption="Resolution: "))
+ myreferences = ""
+ for r in self.references:
+ myreferences += (r.replace(" ", SPACE_ESCAPE)+NEWLINE_ESCAPE+" ")
+ outstream.write("\n"+wrap(myreferences, width, caption="References: "))
+ outstream.write("\n")
+
+ def isVulnerable(self):
+ """
+ Tests if the system is affected by this GLSA by checking if any
+ vulnerable package versions are installed. Also checks for affected
+ architectures.
+
+ @rtype: Boolean
+ @returns: True if the system is affected, False if not
+ """
+ vList = []
+ rValue = False
+ for k in self.packages.keys():
+ pkg = self.packages[k]
+ for path in pkg:
+ if path["arch"] == "*" or self.config["ARCH"] in path["arch"].split():
+ for v in path["vul_atoms"]:
+ rValue = rValue \
+ or (len(match(v, "vartree")) > 0 \
+ and getMinUpgrade(path["vul_atoms"], path["unaff_atoms"]))
+ return rValue
+
+ def isApplied(self):
+ """
+ Looks if the GLSA IDis in the GLSA checkfile to check if this
+ GLSA was already applied.
+
+ @rtype: Boolean
+ @returns: True if the GLSA was applied, False if not
+ """
+ aList = portage.grabfile(self.config["CHECKFILE"])
+ return (self.nr in aList)
+
+ def inject(self):
+ """
+ Puts the ID of this GLSA into the GLSA checkfile, so it won't
+ show up on future checks. Should be called after a GLSA is
+ applied or on explicit user request.
+
+ @rtype: None
+ @returns: None
+ """
+ if not self.isApplied():
+ checkfile = open(self.config["CHECKFILE"], "a+")
+ checkfile.write(self.nr+"\n")
+ checkfile.close()
+ return None
+
+ def getMergeList(self, least_change=True):
+ """
+ Returns the list of package-versions that have to be merged to
+ apply this GLSA properly. The versions are as low as possible
+ while avoiding downgrades (see L{getMinUpgrade}).
+
+ @type least_change: Boolean
+ @param least_change: True if the smallest possible upgrade should be selected,
+ False for an emerge-like algorithm
+ @rtype: List of Strings
+ @return: list of package-versions that have to be merged
+ """
+ rValue = []
+ for pkg in self.packages.keys():
+ for path in self.packages[pkg]:
+ update = getMinUpgrade(path["vul_atoms"], path["unaff_atoms"], minimize=least_change)
+ if update:
+ rValue.append(update)
+ return rValue
diff --git a/pym/gentoolkit/helpers.py b/pym/gentoolkit/helpers.py
new file mode 100644
index 0000000..69acc1d
--- /dev/null
+++ b/pym/gentoolkit/helpers.py
@@ -0,0 +1,162 @@
+#!/usr/bin/python2
+#
+# Copyright(c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header$
+
+import portage
+from gentoolkit import *
+from package import *
+from pprinter import print_warn
+try:
+ from portage.util import unique_array
+except ImportError:
+ from portage_util import unique_array
+
+def find_packages(search_key, masked=False):
+ """Returns a list of Package objects that matched the search key."""
+ try:
+ if masked:
+ t = portage.db["/"]["porttree"].dbapi.xmatch("match-all", search_key)
+ t += portage.db["/"]["vartree"].dbapi.match(search_key)
+ else:
+ t = portage.db["/"]["porttree"].dbapi.match(search_key)
+ t += portage.db["/"]["vartree"].dbapi.match(search_key)
+ # catch the "amgigous package" Exception
+ except ValueError, e:
+ if isinstance(e[0],list):
+ t = []
+ for cp in e[0]:
+ if masked:
+ t += portage.db["/"]["porttree"].dbapi.xmatch("match-all", cp)
+ t += portage.db["/"]["vartree"].dbapi.match(cp)
+ else:
+ t += portage.db["/"]["porttree"].dbapi.match(cp)
+ t += portage.db["/"]["vartree"].dbapi.match(cp)
+ else:
+ raise ValueError(e)
+ except portage_exception.InvalidAtom, e:
+ print_warn("Invalid Atom: '%s'" % str(e))
+ return []
+ # Make the list of packages unique
+ t = unique_array(t)
+ t.sort()
+ return [Package(x) for x in t]
+
+def find_installed_packages(search_key, masked=False):
+ """Returns a list of Package objects that matched the search key."""
+ try:
+ t = portage.db["/"]["vartree"].dbapi.match(search_key)
+ # catch the "amgigous package" Exception
+ except ValueError, e:
+ if isinstance(e[0],list):
+ t = []
+ for cp in e[0]:
+ t += portage.db["/"]["vartree"].dbapi.match(cp)
+ else:
+ raise ValueError(e)
+ except portage_exception.InvalidAtom, e:
+ print_warn("Invalid Atom: '%s'" % str(e))
+ return []
+ return [Package(x) for x in t]
+
+def find_best_match(search_key):
+ """Returns a Package object for the best available candidate that
+ matched the search key."""
+ t = portage.db["/"]["porttree"].dep_bestmatch(search_key)
+ if t:
+ return Package(t)
+ return None
+
+def find_system_packages(prefilter=None):
+ """Returns a tuple of lists, first list is resolved system packages,
+ second is a list of unresolved packages."""
+ pkglist = settings.packages
+ resolved = []
+ unresolved = []
+ for x in pkglist:
+ cpv = x.strip()
+ if len(cpv) and cpv[0] == "*":
+ pkg = find_best_match(cpv)
+ if pkg:
+ resolved.append(pkg)
+ else:
+ unresolved.append(cpv)
+ return (resolved, unresolved)
+
+def find_world_packages(prefilter=None):
+ """Returns a tuple of lists, first list is resolved world packages,
+ seond is unresolved package names."""
+ f = open(portage.root+portage.WORLD_FILE)
+ pkglist = f.readlines()
+ resolved = []
+ unresolved = []
+ for x in pkglist:
+ cpv = x.strip()
+ if len(cpv) and cpv[0] != "#":
+ pkg = find_best_match(cpv)
+ if pkg:
+ resolved.append(pkg)
+ else:
+ unresolved.append(cpv)
+ return (resolved,unresolved)
+
+def find_all_installed_packages(prefilter=None):
+ """Returns a list of all installed packages, after applying the prefilter
+ function"""
+ t = vartree.dbapi.cpv_all()
+ if prefilter:
+ t = filter(prefilter,t)
+ return [Package(x) for x in t]
+
+def find_all_uninstalled_packages(prefilter=None):
+ """Returns a list of all uninstalled packages, after applying the prefilter
+ function"""
+ alist = find_all_packages(prefilter)
+ return [x for x in alist if not x.is_installed()]
+
+def find_all_packages(prefilter=None):
+ """Returns a list of all known packages, installed or not, after applying
+ the prefilter function"""
+ t = porttree.dbapi.cp_all()
+ t += vartree.dbapi.cp_all()
+ if prefilter:
+ t = filter(prefilter,t)
+ t = unique_array(t)
+ t2 = []
+ for x in t:
+ t2 += porttree.dbapi.cp_list(x)
+ t2 += vartree.dbapi.cp_list(x)
+ t2 = unique_array(t2)
+ return [Package(x) for x in t2]
+
+def split_package_name(name):
+ """Returns a list on the form [category, name, version, revision]. Revision will
+ be 'r0' if none can be inferred. Category and version will be empty, if none can
+ be inferred."""
+ r = portage.catpkgsplit(name)
+ if not r:
+ r = name.split("/")
+ if len(r) == 1:
+ return ["", name, "", "r0"]
+ else:
+ return r + ["", "r0"]
+ else:
+ r = list(r)
+ if r[0] == 'null':
+ r[0] = ''
+ return r
+
+def sort_package_list(pkglist):
+ """Returns the list ordered in the same way portage would do with lowest version
+ at the head of the list."""
+ pkglist.sort(Package.compare_version)
+ return pkglist
+
+if __name__ == "__main__":
+ print "This module is for import only"
+
+
diff --git a/pym/gentoolkit/helpers2.py b/pym/gentoolkit/helpers2.py
new file mode 100644
index 0000000..20d1de0
--- /dev/null
+++ b/pym/gentoolkit/helpers2.py
@@ -0,0 +1,425 @@
+# Copyright(c) 2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2 or higher
+
+"""Improved versions of the original helpers functions.
+
+As a convention, functions ending in '_packages' or '_match{es}' return
+Package objects, while functions ending in 'cpvs' return a sequence of strings.
+Functions starting with 'get_' return a set of packages by default and can be
+filtered, while functions starting with 'find_' return nothing unless the
+query matches one or more packages.
+
+This should be merged into helpers when a clean path is found.
+"""
+
+__all__ = (
+ 'compare_package_strings',
+ 'find_best_match',
+ 'find_installed_packages',
+ 'find_packages',
+ 'get_cpvs',
+ 'get_installed_cpvs',
+ 'get_uninstalled_cpvs',
+ 'uses_globbing',
+ 'do_lookup'
+)
+__author__ = 'Douglas Anderson'
+__docformat__ = 'epytext'
+
+# =======
+# Imports
+# =======
+
+import re
+import fnmatch
+from functools import partial
+
+import portage
+from portage.util import unique_array
+
+import gentoolkit
+import gentoolkit.pprinter as pp
+from gentoolkit import catpkgsplit, Config
+from gentoolkit import errors
+from gentoolkit.package import Package
+
+# =======
+# Globals
+# =======
+
+PORTDB = portage.db[portage.root]["porttree"].dbapi
+VARDB = portage.db[portage.root]["vartree"].dbapi
+
+# =========
+# Functions
+# =========
+
+def compare_package_strings(pkg1, pkg2):
+ """Similar to the builtin cmp, but for package strings. Usually called
+ as: package_list.sort(compare_package_strings)
+
+ An alternative is to use the Package descriptor from gentoolkit.package
+ >>> pkgs = [Package(x) for x in package_list]
+ >>> pkgs.sort()
+
+ @see: >>> help(cmp)
+ """
+
+ pkg1 = catpkgsplit(pkg1)
+ pkg2 = catpkgsplit(pkg2)
+ # Compare categories
+ if pkg1[0] != pkg2[0]:
+ return cmp(pkg1[0], pkg2[0])
+ # Compare names
+ elif pkg1[1] != pkg2[1]:
+ return cmp(pkg1[1], pkg2[1])
+ # Compare versions
+ else:
+ return portage.versions.pkgcmp(pkg1[1:], pkg2[1:])
+
+
+def find_best_match(query):
+ """Return the highest unmasked version of a package matching query.
+
+ @type query: str
+ @param query: can be of the form: pkg, pkg-ver, cat/pkg, cat/pkg-ver, atom
+ @rtype: str or None
+ """
+
+ match = PORTDB.xmatch("bestmatch-visible", query)
+
+ return Package(match) if match else None
+
+
+def find_installed_packages(query):
+ """Return a list of Package objects that matched the search key."""
+
+ try:
+ matches = VARDB.match(query)
+ # catch the ambiguous package Exception
+ except ValueError, err:
+ if isinstance(err[0], list):
+ matches = []
+ for pkgkey in err[0]:
+ matches.append(VARDB.match(pkgkey))
+ else:
+ raise ValueError(err)
+ except portage.exception.InvalidAtom, err:
+ pp.print_warn("Invalid Atom: '%s'" % str(err))
+ return []
+
+ return [Package(x) for x in matches]
+
+
+def uses_globbing(query):
+ """Check the query to see if it is using globbing.
+
+ @rtype: bool
+ @return: True if query uses globbing, else False
+ """
+
+ if set('!*?[]').intersection(set(query)):
+ if portage.dep.get_operator(query):
+ # Query may be an atom such as '=sys-apps/portage-2.2*'
+ pass
+ else:
+ return True
+
+ return False
+
+
+def _do_complex_lookup(query, query_opts):
+ """Find matches for a query which is a regex or includes globbing."""
+
+ result = []
+
+ if query_opts["includeInstalled"]:
+ if query_opts["includePortTree"] or query_opts["includeOverlayTree"]:
+ package_finder = get_cpvs
+ else:
+ package_finder = get_installed_cpvs
+ elif query_opts["includePortTree"] or query_opts["includeOverlayTree"]:
+ package_finder = get_uninstalled_cpvs
+ else:
+ pp.print_error("Not searching in installed, portage tree or overlay." +
+ " Nothing to do.")
+ pp.die(2, "This is an internal error. Please report this.")
+
+ if query_opts["printMatchInfo"] and not Config["piping"]:
+ print_query_info(query, query_opts)
+
+ cats = prepare_categories(query_opts["categoryFilter"])
+ cat = split_query(query)[0]
+
+ pre_filter = []
+ # The "get_" functions can pre-filter against the whole package key,
+ # but since we allow globbing now, we run into issues like:
+ # >>> portage.dep.dep_getkey("sys-apps/portage-*")
+ # 'sys-apps/portage-'
+ # So the only way to guarantee we don't overrun the key is to
+ # prefilter by cat only.
+ if cats:
+ pre_filter = package_finder(predicate=lambda x: x.startswith(cats))
+ if cat:
+ if query_opts["isRegex"]:
+ cat_re = cat
+ else:
+ cat_re = fnmatch.translate(cat)
+ # [::-1] reverses a sequence, so we're emulating an ".rreplace()"
+ # except we have to put our "new" string on backwards
+ cat_re = cat_re[::-1].replace('$', '*./', 1)[::-1]
+ predicate = lambda x: re.match(cat_re, x)
+ if pre_filter:
+ pre_filter = [x for x in pre_filter if predicate(x)]
+ else:
+ pre_filter = package_finder(predicate=predicate)
+
+ # Post-filter
+ if query_opts["isRegex"]:
+ predicate = lambda x: re.match(query, x)
+ else:
+ if cat:
+ query_re = fnmatch.translate(query)
+ else:
+ query_re = fnmatch.translate("*/%s" % query)
+ predicate = lambda x: re.search(query_re, x)
+ if pre_filter:
+ result = [x for x in pre_filter if predicate(x)]
+ else:
+ result = package_finder(predicate=predicate)
+
+ return [Package(x) for x in result]
+
+
+def print_query_info(query, query_opts):
+ """Print info about the query to the screen."""
+
+ cats = prepare_categories(query_opts["categoryFilter"])
+ cat, pkg, ver, rev = split_query(query)
+ del ver, rev
+ if cats:
+ cat_str = "in %s " % ', '.join([pp.emph(x) for x in cats])
+ elif cat and not query_opts["isRegex"]:
+ cat_str = "in %s " % pp.emph(cat)
+ else:
+ cat_str = ""
+
+ if query_opts["isRegex"]:
+ pkg_str = query
+ else:
+ pkg_str = pkg
+
+ print " * Searching for %s %s..." % (pp.emph(pkg_str), cat_str)
+
+
+def _do_simple_lookup(query, query_opts):
+ """Find matches for a query which is an atom or string."""
+
+ result = []
+
+ cats = prepare_categories(query_opts["categoryFilter"])
+ if query_opts["printMatchInfo"] and not Config["piping"]:
+ print_query_info(query, query_opts)
+
+ if query_opts["includePortTree"] or query_opts["includeOverlayTree"]:
+ package_finder = find_packages
+ else:
+ package_finder = find_installed_packages
+
+ result = package_finder(query)
+ if not query_opts["includeInstalled"]:
+ result = [x for x in result if not x.is_installed()]
+
+ if cats:
+ result = [x for x in result if x.cpv.startswith(cats)]
+
+ return result
+
+
+def do_lookup(query, query_opts):
+ """A high-level wrapper around gentoolkit package-finder functions.
+
+ @todo: equery modules to move to do_lookup: c,m,u,w
+
+ @type query: str
+ @param query: pkg, cat/pkg, pkg-ver, cat/pkg-ver, atom or regex
+ @type query_opts: dict
+ @param query_opts: user-configurable options from the calling module
+ Currently supported options are:
+
+ categoryFilter = str or None
+ includeInstalled = bool
+ includePortTree = bool
+ includeOverlayTree = bool
+ isRegex = bool
+ printMatchInfo = bool # Print info about the search
+
+ @rtype: list
+ @return: Package objects matching query
+ """
+
+ is_simple_query = True
+ if query_opts["isRegex"] or uses_globbing(query):
+ is_simple_query = False
+
+ if is_simple_query:
+ matches = _do_simple_lookup(query, query_opts)
+ else:
+ matches = _do_complex_lookup(query, query_opts)
+
+ return matches
+
+
+def find_packages(query, include_masked=False):
+ """Returns a list of Package objects that matched the query.
+
+ @type query: str
+ @param query: can be of the form: pkg, pkg-ver, cat/pkg, cat/pkg-ver, atom
+ @rtype: list
+ @return: matching Package objects
+ """
+
+ if not query:
+ return []
+
+ try:
+ if include_masked:
+ matches = PORTDB.xmatch("match-all", query)
+ else:
+ matches = PORTDB.match(query)
+ matches.extend(VARDB.match(query))
+ # Catch ambiguous packages
+ except ValueError, err:
+ if isinstance(err[0], list):
+ matches = []
+ for pkgkey in err[0]:
+ if include_masked:
+ matches.extend(PORTDB.xmatch("match-all", pkgkey))
+ else:
+ matches.extend(PORTDB.match(pkgkey))
+ matches.extend(VARDB.match(pkgkey))
+ else:
+ raise ValueError(err)
+ except portage.exception.InvalidAtom, err:
+ raise errors.GentoolkitInvalidAtom(str(err))
+
+ return [Package(x) for x in unique_array(matches)]
+
+
+def get_cpvs(predicate=None, include_installed=True):
+ """Get all packages in the Portage tree and overlays. Optionally apply a
+ predicate.
+
+ Example usage:
+ >>> from gentoolkit.helpers2 import get_cpvs
+ >>> len(get_cpvs())
+ 26065
+ >>> fn = lambda x: x.startswith('app-portage')
+ >>> len(get_cpvs(fn, include_installed=False))
+ 112
+
+ @type predicate: function
+ @param predicate: a function to filter the package list with
+ @type include_installed: bool
+ @param include_installed:
+ If True: Return the union of all_cpvs and all_installed_cpvs
+ If False: Return the difference of all_cpvs and all_installed_cpvs
+ @rtype: list
+ @return: ['cat/portdir_pkg-1', 'cat/overlay_pkg-2', ...]
+ """
+
+ if predicate:
+ all_cps = [x for x in PORTDB.cp_all() if predicate(x)]
+ else:
+ all_cps = PORTDB.cp_all()
+
+ all_cpvs = []
+ for pkgkey in all_cps:
+ all_cpvs.extend(PORTDB.cp_list(pkgkey))
+
+ result = set(all_cpvs)
+ all_installed_cpvs = get_installed_cpvs(predicate)
+
+ if include_installed:
+ result.update(all_installed_cpvs)
+ else:
+ result.difference_update(all_installed_cpvs)
+
+ return list(result)
+
+
+# pylint thinks this is a global variable
+# pylint: disable-msg=C0103
+get_uninstalled_cpvs = partial(get_cpvs, include_installed=False)
+
+
+def get_installed_cpvs(predicate=None):
+ """Get all installed packages. Optionally apply a predicate.
+
+ @type predicate: function
+ @param predicate: a function to filter the package list with
+ @rtype: unsorted list
+ @return: ['cat/installed_pkg-1', 'cat/installed_pkg-2', ...]
+ """
+
+ if predicate:
+ all_installed_cps = [x for x in VARDB.cp_all() if predicate(x)]
+ else:
+ all_installed_cps = VARDB.cp_all()
+
+ result = []
+ for pkgkey in all_installed_cps:
+ result.extend(VARDB.cp_list(pkgkey))
+
+ return list(result)
+
+
+def prepare_categories(category_filter):
+ """Return a tuple of validated categories. Expand globs.
+
+ Example usage:
+ >>> prepare_categories('app-portage,sys-apps')
+ ('app-portage', 'sys-apps')
+ """
+
+ if not category_filter:
+ return tuple()
+
+ cats = [x.lstrip('=') for x in category_filter.split(',')]
+ valid_cats = portage.settings.categories
+ good_cats = []
+ for cat in cats:
+ if set('!*?[]').intersection(set(cat)):
+ good_cats.extend(fnmatch.filter(valid_cats, cat))
+ elif cat in valid_cats:
+ good_cats.append(cat)
+ else:
+ raise errors.GentoolkitInvalidCategory(cat)
+
+ return tuple(good_cats)
+
+
+def split_query(query):
+ """Split a query, using either.
+
+ @see: split_atom, gentoolkit.split_package_name
+ @param query: pkg, cat/pkg, pkg-ver, cat/pkg-ver, atom or regex
+ @rtype: tuple
+ @return: (category, pkg_name, version, revision)
+ Each tuple element is a string or empty string ("").
+ """
+
+ cat = name = ver = rev = ""
+
+ try:
+ (cat, name, ver, rev) = gentoolkit.split_package_name(query)
+ except ValueError, err:
+ # FIXME: Not hitting this error anymore... but we should be?
+ if str(err) == 'too many values to unpack':
+ pp.print_error("Too many slashes ('/').")
+ raise errors.GentoolkitInvalidPackageName(query)
+ else:
+ raise ValueError(err)
+
+ return (cat, name, ver, rev)
diff --git a/pym/gentoolkit/package.py b/pym/gentoolkit/package.py
new file mode 100644
index 0000000..65cdb9a
--- /dev/null
+++ b/pym/gentoolkit/package.py
@@ -0,0 +1,582 @@
+#! /usr/bin/python
+#
+# Copyright(c) 2004, Karl Trygve Kalleberg <karltk@gentoo.org>
+# Copyright(c) 2004-2009, Gentoo Foundation
+#
+# Licensed under the GNU General Public License, v2
+#
+# $Header$
+
+# =======
+# Imports
+# =======
+
+import os
+
+import portage
+from portage import catpkgsplit
+from portage.versions import vercmp
+
+from gentoolkit import *
+from gentoolkit import errors
+
+# =======
+# Globals
+# =======
+
+PORTDB = portage.db[portage.root]["porttree"].dbapi
+VARDB = portage.db[portage.root]["vartree"].dbapi
+
+# =======
+# Classes
+# =======
+
+class Package(object):
+ """Package descriptor. Contains convenience functions for querying the
+ state of a package, its contents, name manipulation, ebuild info and
+ similar."""
+
+ def __init__(self, arg):
+
+ self._cpv = arg
+ self.cpv = self._cpv
+
+ if self.cpv[0] in ('<', '>'):
+ if self.cpv[1] == '=':
+ self.operator = self.cpv[:2]
+ self.cpv = self.cpv[2:]
+ else:
+ self.operator = self.cpv[0]
+ self.cpv = self.cpv[1:]
+ elif self.cpv[0] == '=':
+ if self.cpv[-1] == '*':
+ self.operator = '=*'
+ self.cpv = self.cpv[1:-1]
+ else:
+ self.cpv = self.cpv[1:]
+ self.operator = '='
+ elif self.cpv[0] == '~':
+ self.operator = '~'
+ self.cpv = self.cpv[1:]
+ else:
+ self.operator = '='
+ self._cpv = '=%s' % self._cpv
+
+ if not portage.dep.isvalidatom(self._cpv):
+ raise errors.GentoolkitInvalidCPV(self._cpv)
+
+ cpv_split = portage.catpkgsplit(self.cpv)
+
+ try:
+ self.key = "/".join(cpv_split[:2])
+ except TypeError:
+ # catpkgsplit returned None
+ raise errors.GentoolkitInvalidCPV(self._cpv)
+
+ cpv_split = list(cpv_split)
+ if cpv_split[0] == 'null':
+ cpv_split[0] = ''
+ if cpv_split[3] == 'r0':
+ cpv_split[3] = ''
+ self.cpv_split = cpv_split
+ self._scpv = self.cpv_split # XXX: namespace compatability 03/09
+
+ self._db = None
+ self._settings = settings
+ self._settingslock = settingslock
+ self._portdir_path = os.path.realpath(settings["PORTDIR"])
+
+ self.category = self.cpv_split[0]
+ self.name = self.cpv_split[1]
+ self.version = self.cpv_split[2]
+ self.revision = self.cpv_split[3]
+ if not self.revision:
+ self.fullversion = self.version
+ else:
+ self.fullversion = "%s-%s" % (self.version, self.revision)
+
+ def __repr__(self):
+ return "<%s %s @%#8x>" % (self.__class__.__name__, self._cpv, id(self))
+
+ def __cmp__(self, other):
+ # FIXME: __cmp__ functions dissallowed in py3k; need __lt__, __gt__.
+ if not isinstance(other, self.__class__):
+ raise TypeError("other isn't of %s type, is %s" %
+ (self.__class__, other.__class__))
+
+ if self.category != other.category:
+ return cmp(self.category, other.category)
+ elif self.name != other.name:
+ return cmp(self.name, other.name)
+ else:
+ # FIXME: this cmp() hack is for vercmp not using -1,0,1
+ # See bug 266493; this was fixed in portage-2.2_rc31
+ #return portage.vercmp(self.fullversion, other.fullversion)
+ return cmp(portage.vercmp(self.fullversion, other.fullversion), 0)
+
+ def __eq__(self, other):
+ return hash(self) == hash(other)
+
+ def __ne__(self, other):
+ return hash(self) != hash(other)
+
+ def __hash__(self):
+ return hash(self._cpv)
+
+ def __contains__(self, key):
+ return key in self._cpv
+
+ def __str__(self):
+ return self._cpv
+
+ def get_name(self):
+ """Returns base name of package, no category nor version"""
+ return self.name
+
+ def get_version(self):
+ """Returns version of package, with revision number"""
+ return self.fullversion
+
+ def get_category(self):
+ """Returns category of package"""
+ return self.category
+
+ def get_settings(self, key):
+ """Returns the value of the given key for this package (useful
+ for package.* files."""
+ self._settingslock.acquire()
+ self._settings.setcpv(self.cpv)
+ v = self._settings[key]
+ self._settingslock.release()
+ return v
+
+ def get_cpv(self):
+ """Returns full Category/Package-Version string"""
+ return self.cpv
+
+ def get_provide(self):
+ """Return a list of provides, if any"""
+ if not self.is_installed():
+ try:
+ x = [self.get_env_var('PROVIDE')]
+ except KeyError:
+ x = []
+ return x
+ else:
+ return vartree.get_provide(self.cpv)
+
+ def get_dependants(self):
+ """Retrieves a list of CPVs for all packages depending on this one"""
+ raise NotImplementedError("Not implemented yet!")
+
+ def get_runtime_deps(self):
+ """Returns a linearised list of first-level run time dependencies for
+ this package, on the form [(comparator, [use flags], cpv), ...]
+ """
+ # Try to use the portage tree first, since emerge only uses the tree
+ # when calculating dependencies
+ try:
+ cd = self.get_env_var("RDEPEND", porttree).split()
+ except KeyError:
+ cd = self.get_env_var("RDEPEND", vartree).split()
+ r,i = self._parse_deps(cd)
+ return r
+
+ def get_compiletime_deps(self):
+ """Returns a linearised list of first-level compile time dependencies
+ for this package, on the form [(comparator, [use flags], cpv), ...]
+ """
+ # Try to use the portage tree first, since emerge only uses the tree
+ # when calculating dependencies
+ try:
+ rd = self.get_env_var("DEPEND", porttree).split()
+ except KeyError:
+ rd = self.get_env_var("DEPEND", vartree).split()
+ r,i = self._parse_deps(rd)
+ return r
+
+ def get_postmerge_deps(self):
+ """Returns a linearised list of first-level post merge dependencies
+ for this package, on the form [(comparator, [use flags], cpv), ...]
+ """
+ # Try to use the portage tree first, since emerge only uses the tree
+ # when calculating dependencies
+ try:
+ pd = self.get_env_var("PDEPEND", porttree).split()
+ except KeyError:
+ pd = self.get_env_var("PDEPEND", vartree).split()
+ r,i = self._parse_deps(pd)
+ return r
+
+ def intersects(self, other):
+ """Check if a passed in package atom "intersects" this atom.
+
+ Lifted from pkgcore.
+
+ Two atoms "intersect" if a package can be constructed that
+ matches both:
+ - if you query for just "dev-lang/python" it "intersects" both
+ "dev-lang/python" and ">=dev-lang/python-2.4"
+ - if you query for "=dev-lang/python-2.4" it "intersects"
+ ">=dev-lang/python-2.4" and "dev-lang/python" but not
+ "<dev-lang/python-2.3"
+
+ @type other: gentoolkit.package.Package
+ @param other: other package to compare
+ @see: pkgcore.ebuild.atom.py
+ """
+ # Our "key" (cat/pkg) must match exactly:
+ if self.key != other.key:
+ return False
+
+ # If we are both "unbounded" in the same direction we intersect:
+ if (('<' in self.operator and '<' in other.operator) or
+ ('>' in self.operator and '>' in other.operator)):
+ return True
+
+ # If one of us is an exact match we intersect if the other matches it:
+ if self.operator == '=':
+ if other.operator == '=*':
+ return self.fullversion.startswith(other.fullversion)
+ return VersionMatch(frompkg=other).match(self)
+ if other.operator == '=':
+ if self.operator == '=*':
+ return other.fullversion.startswith(self.fullversion)
+ return VersionMatch(frompkg=self).match(other)
+
+ # If we are both ~ matches we match if we are identical:
+ if self.operator == other.operator == '~':
+ return (self.version == other.version and
+ self.revision == other.revision)
+
+ # If we are both glob matches we match if one of us matches the other.
+ if self.operator == other.operator == '=*':
+ return (self.fullver.startswith(other.fullver) or
+ other.fullver.startswith(self.fullver))
+
+ # If one of us is a glob match and the other a ~ we match if the glob
+ # matches the ~ (ignoring a revision on the glob):
+ if self.operator == '=*' and other.operator == '~':
+ return other.fullversion.startswith(self.version)
+ if other.operator == '=*' and self.operator == '~':
+ return self.fullversion.startswith(other.version)
+
+ # If we get here at least one of us is a <, <=, > or >=:
+ if self.operator in ('<', '<=', '>', '>='):
+ ranged, other = self, other
+ else:
+ ranged, other = other, self
+
+ if '<' in other.operator or '>' in other.operator:
+ # We are both ranged, and in the opposite "direction" (or
+ # we would have matched above). We intersect if we both
+ # match the other's endpoint (just checking one endpoint
+ # is not enough, it would give a false positive on <=2 vs >2)
+ return (
+ VersionMatch(frompkg=other).match(ranged) and
+ VersionMatch(frompkg=ranged).match(other))
+
+ if other.operator == '~':
+ # Other definitely matches its own version. If ranged also
+ # does we're done:
+ if VersionMatch(frompkg=ranged).match(other):
+ return True
+ # The only other case where we intersect is if ranged is a
+ # > or >= on other's version and a nonzero revision. In
+ # that case other will match ranged. Be careful not to
+ # give a false positive for ~2 vs <2 here:
+ return ranged.operator in ('>', '>=') and VersionMatch(
+ other.operator, other.version, other.revision).match(ranged)
+
+ if other.operator == '=*':
+ # a glob match definitely matches its own version, so if
+ # ranged does too we're done:
+ if VersionMatch(
+ ranged.operator, ranged.version, ranged.revision).match(other):
+ return True
+ if '<' in ranged.operator:
+ # If other.revision is not defined then other does not
+ # match anything smaller than its own fullver:
+ if not other.revision:
+ return False
+
+ # If other.revision is defined then we can always
+ # construct a package smaller than other.fullver by
+ # tagging e.g. an _alpha1 on.
+ return ranged.fullversion.startswith(other.version)
+ else:
+ # Remaining cases where this intersects: there is a
+ # package greater than ranged.fullver and
+ # other.fullver that they both match.
+ return ranged.fullversion.startswith(other.version)
+
+ # Handled all possible ops.
+ raise NotImplementedError(
+ 'Someone added an operator without adding it to intersects')
+
+
+ def _parse_deps(self,deps,curuse=[],level=0):
+ # store (comparator, [use predicates], cpv)
+ r = []
+ comparators = ["~","<",">","=","<=",">="]
+ end = len(deps)
+ i = 0
+ while i < end:
+ tok = deps[i]
+ if tok == ')':
+ return r,i
+ if tok[-1] == "?":
+ tok = tok.replace("?","")
+ sr,l = self._parse_deps(deps[i+2:],curuse=curuse+[tok],level=level+1)
+ r += sr
+ i += l + 3
+ continue
+ if tok == "||":
+ sr,l = self._parse_deps(deps[i+2:],curuse,level=level+1)
+ r += sr
+ i += l + 3
+ continue
+ # conjunction, like in "|| ( ( foo bar ) baz )" => recurse
+ if tok == "(":
+ sr,l = self._parse_deps(deps[i+1:],curuse,level=level+1)
+ r += sr
+ i += l + 2
+ continue
+ # pkg block "!foo/bar" => ignore it
+ if tok[0] == "!":
+ i += 1
+ continue
+ # pick out comparator, if any
+ cmp = ""
+ for c in comparators:
+ if tok.find(c) == 0:
+ cmp = c
+ tok = tok[len(cmp):]
+ r.append((cmp,curuse,tok))
+ i += 1
+ return r,i
+
+ def is_installed(self):
+ """Returns True if this package is installed (merged)"""
+ return VARDB.cpv_exists(self.cpv)
+
+ def is_overlay(self):
+ """Returns True if the package is in an overlay."""
+ dir,ovl = portage.portdb.findname2(self.cpv)
+ return ovl != self._portdir_path
+
+ def is_masked(self):
+ """Returns true if this package is masked against installation.
+ Note: We blindly assume that the package actually exists on disk
+ somewhere."""
+ unmasked = portage.portdb.xmatch("match-visible", self.cpv)
+ return self.cpv not in unmasked
+
+ def get_ebuild_path(self,in_vartree=0):
+ """Returns the complete path to the .ebuild file"""
+ if in_vartree:
+ return vartree.getebuildpath(self.cpv)
+ else:
+ return portage.portdb.findname(self.cpv)
+
+ def get_package_path(self):
+ """Returns the path to where the ChangeLog, Manifest, .ebuild files
+ reside"""
+ p = self.get_ebuild_path()
+ sp = p.split("/")
+ if sp:
+ # FIXME: use os.path.join
+ return "/".join(sp[:-1])
+
+ def get_env_var(self, var, tree=""):
+ """Returns one of the predefined env vars DEPEND, RDEPEND,
+ SRC_URI,...."""
+ if tree == "":
+ mytree = vartree
+ if not self.is_installed():
+ mytree = porttree
+ else:
+ mytree = tree
+ try:
+ r = mytree.dbapi.aux_get(self.cpv,[var])
+ except KeyError:
+ # aux_get raises KeyError if it encounters a bad digest, etc
+ raise
+ if not r:
+ raise errors.GentoolkitFatalError("Could not find the package tree")
+ if len(r) != 1:
+ raise errors.GentoolkitFatalError("Should only get one element!")
+ return r[0]
+
+ def get_use_flags(self):
+ """Returns the USE flags active at time of installation"""
+ self._initdb()
+ if self.is_installed():
+ return self._db.getfile("USE")
+ return ""
+
+ def get_contents(self):
+ """Returns the full contents, as a dictionary, in the form
+ [ '/bin/foo' : [ 'obj', '1052505381', '45ca8b89751...' ], ... ]"""
+ self._initdb()
+ if self.is_installed():
+ return self._db.getcontents()
+ return {}
+
+ # XXX >
+ def compare_version(self,other):
+ """Compares this package's version to another's CPV; returns -1, 0, 1.
+
+ Deprecated in favor of __cmp__.
+ """
+ v1 = self.cpv_split
+ v2 = catpkgsplit(other.get_cpv())
+ # if category is different
+ if v1[0] != v2[0]:
+ return cmp(v1[0],v2[0])
+ # if name is different
+ elif v1[1] != v2[1]:
+ return cmp(v1[1],v2[1])
+ # Compare versions
+ else:
+ return portage.pkgcmp(v1[1:],v2[1:])
+ # < XXX
+
+ def size(self):
+ """Estimates the installed size of the contents of this package,
+ if possible.
+ Returns [size, number of files in total, number of uncounted files]
+ """
+ contents = self.get_contents()
+ size = 0
+ uncounted = 0
+ files = 0
+ for x in contents:
+ try:
+ size += os.lstat(x).st_size
+ files += 1
+ except OSError:
+ uncounted += 1
+ return [size, files, uncounted]
+
+ def _initdb(self):
+ """Internal helper function; loads package information from disk,
+ when necessary.
+ """
+ if not self._db:
+ self._db = portage.dblink(
+ category,
+ "%s-%s" % (self.name, self.fullversion),
+ settings["ROOT"],
+ settings
+ )
+
+
+class VersionMatch(object):
+ """Package restriction implementing Gentoo ebuild version comparison rules.
+ From pkgcore.ebuild.atom_restricts.
+
+ Any overriding of this class *must* maintain numerical order of
+ self.vals, see intersect for reason why. vals also must be a tuple.
+ """
+ _convert_op2int = {(-1,):"<", (-1, 0): "<=", (0,):"=",
+ (0, 1):">=", (1,):">"}
+
+ _convert_int2op = dict([(v, k) for k, v in _convert_op2int.iteritems()])
+ del k, v
+
+ def __init__(self, **kwargs):
+ """This class will either create a VersionMatch instance out of
+ a Package instance, or from explicitly passed in operator, version,
+ and revision.
+
+ Possible args:
+ frompkg=<gentoolkit.package.Package> instance
+
+ OR
+
+ op=str: version comparison to do,
+ valid operators are ('<', '<=', '=', '>=', '>', '~')
+ ver=str: version to base comparison on
+ rev=str: revision to base comparison on
+ """
+ if 'frompkg' in kwargs and kwargs['frompkg']:
+ self.operator = kwargs['frompkg'].operator
+ self.version = kwargs['frompkg'].version
+ self.revision = kwargs['frompkg'].revision
+ self.fullversion = kwargs['frompkg'].fullversion
+ elif set(('op', 'ver', 'rev')) == set(kwargs):
+ self.operator = kwargs['op']
+ self.version = kwargs['ver']
+ self.revision = kwargs['rev']
+ if not self.revision:
+ self.fullversion = self.version
+ else:
+ self.fullversion = "%s-%s" % (self.version, self.revision)
+ else:
+ raise TypeError('__init__() takes either a Package instance '
+ 'via frompkg= or op=, ver= and rev= all passed in')
+
+ if self.operator != "~" and self.operator not in self._convert_int2op:
+ # FIXME: change error
+ raise errors.InvalidVersion(self.ver, self.rev,
+ "invalid operator, '%s'" % operator)
+
+ if self.operator == "~":
+ if not self.version:
+ raise ValueError(
+ "for ~ op, version must be specified")
+ self.droprevision = True
+ self.values = (0,)
+ else:
+ self.droprevision = False
+ self.values = self._convert_int2op[self.operator]
+
+ def match(self, pkginst):
+ if self.droprevision:
+ ver1, ver2 = self.version, pkginst.version
+ else:
+ ver1, ver2 = self.fullversion, pkginst.fullversion
+
+ #print "== VersionMatch.match DEBUG START =="
+ #print "ver1:", ver1
+ #print "ver2:", ver2
+ #print "vercmp(ver2, ver1):", vercmp(ver2, ver1)
+ #print "self.values:", self.values
+ #print "vercmp(ver2, ver1) in values?",
+ #print "vercmp(ver2, ver1) in self.values"
+ #print "== VersionMatch.match DEBUG END =="
+
+ return vercmp(ver2, ver1) in self.values
+
+ def __str__(self):
+ s = self._convert_op2int[self.values]
+
+ if self.droprevision or not self.revision:
+ return "ver %s %s" % (s, self.version)
+ return "ver-rev %s %s-%s" % (s, self.version, self.revision)
+
+ def __repr__(self):
+ return "<%s %s @%#8x>" % (self.__class__.__name__, str(self), id(self))
+
+ @staticmethod
+ def _convert_ops(inst):
+ if inst.droprevision:
+ return inst.values
+ return tuple(sorted(set((-1, 0, 1)).difference(inst.values)))
+
+ def __eq__(self, other):
+ if self is other:
+ return True
+ if isinstance(other, self.__class__):
+ if (self.droprevsion != other.droprevsion or
+ self.version != other.version or
+ self.revision != other.revision):
+ return False
+ return self._convert_ops(self) == self._convert_ops(other)
+
+ return False
+
+ def __hash__(self):
+ return hash((self.droprevision, self.version, self.revision,
+ self.values))
diff --git a/trunk/src/gentoolkit/pprinter.py b/pym/gentoolkit/pprinter.py
index ff92a26..ff92a26 100644
--- a/trunk/src/gentoolkit/pprinter.py
+++ b/pym/gentoolkit/pprinter.py
diff --git a/pym/gentoolkit/tests/equery/test_init.py b/pym/gentoolkit/tests/equery/test_init.py
new file mode 100644
index 0000000..9756aba
--- /dev/null
+++ b/pym/gentoolkit/tests/equery/test_init.py
@@ -0,0 +1,43 @@
+import unittest
+from test import test_support
+
+from gentoolkit import equery
+
+class TestEqueryInit(unittest.TestCase):
+
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def test_expand_module_name(self):
+ # Test that module names are properly expanded
+ name_map = {
+ 'b': 'belongs',
+ 'c': 'changes',
+ 'k': 'check',
+ 'd': 'depends',
+ 'g': 'depgraph',
+ 'f': 'files',
+ 'h': 'hasuse',
+ 'l': 'list_',
+ 'm': 'meta',
+ 's': 'size',
+ 'u': 'uses',
+ 'w': 'which'
+ }
+ for short_name, long_name in zip(name_map, name_map.values()):
+ self.failUnlessEqual(equery.expand_module_name(short_name),
+ long_name)
+ self.failUnlessEqual(equery.expand_module_name(long_name),
+ long_name)
+ unused_keys = set(map(chr, range(0, 256))).difference(name_map.keys())
+ for key in unused_keys:
+ self.failUnlessRaises(KeyError, equery.expand_module_name, key)
+
+def test_main():
+ test_support.run_unittest(TestEqueryInit)
+
+if __name__ == '__main__':
+ test_main()
diff --git a/pym/gentoolkit/tests/test_helpers2.py b/pym/gentoolkit/tests/test_helpers2.py
new file mode 100644
index 0000000..615cfa1
--- /dev/null
+++ b/pym/gentoolkit/tests/test_helpers2.py
@@ -0,0 +1,39 @@
+import unittest
+from test import test_support
+
+from gentoolkit import helpers2
+
+class TestGentoolkitHelpers2(unittest.TestCase):
+
+ def test_compare_package_strings(self):
+ # Test ordering of package strings, Portage has test for vercmp,
+ # so just do the rest
+ version_tests = [
+ # different categories
+ ('sys-apps/portage-2.1.6.8', 'sys-auth/pambase-20080318'),
+ # different package names
+ ('sys-apps/pkgcore-0.4.7.15-r1', 'sys-apps/portage-2.1.6.8'),
+ # different package versions
+ ('sys-apps/portage-2.1.6.8', 'sys-apps/portage-2.2_rc25')
+ ]
+ # Check less than
+ for vt in version_tests:
+ self.failUnless(
+ helpers2.compare_package_strings(vt[0], vt[1]) == -1
+ )
+ # Check greater than
+ for vt in version_tests:
+ self.failUnless(
+ helpers2.compare_package_strings(vt[1], vt[0]) == 1
+ )
+ # Check equal
+ vt = ('sys-auth/pambase-20080318', 'sys-auth/pambase-20080318')
+ self.failUnless(
+ helpers2.compare_package_strings(vt[0], vt[1]) == 0
+ )
+
+def test_main():
+ test_support.run_unittest(TestGentoolkitHelpers2)
+
+if __name__ == '__main__':
+ test_main()
diff --git a/pym/gentoolkit/tests/test_template.py b/pym/gentoolkit/tests/test_template.py
new file mode 100644
index 0000000..84e8432
--- /dev/null
+++ b/pym/gentoolkit/tests/test_template.py
@@ -0,0 +1,38 @@
+import unittest
+from test import test_support
+
+class MyTestCase1(unittest.TestCase):
+
+ # Only use setUp() and tearDown() if necessary
+
+ def setUp(self):
+ ... code to execute in preparation for tests ...
+
+ def tearDown(self):
+ ... code to execute to clean up after tests ...
+
+ def test_feature_one(self):
+ # Test feature one.
+ ... testing code ...
+
+ def test_feature_two(self):
+ # Test feature two.
+ ... testing code ...
+
+ ... more test methods ...
+
+class MyTestCase2(unittest.TestCase):
+ ... same structure as MyTestCase1 ...
+
+... more test classes ...
+
+def test_main():
+ test_support.run_unittest(
+ MyTestCase1,
+ MyTestCase2,
+ ... list other tests ...
+ )
+
+if __name__ == '__main__':
+ test_main()
+
diff --git a/pym/gentoolkit/textwrap_.py b/pym/gentoolkit/textwrap_.py
new file mode 100644
index 0000000..6851402
--- /dev/null
+++ b/pym/gentoolkit/textwrap_.py
@@ -0,0 +1,97 @@
+"""This modification of textwrap allows it to wrap ANSI colorized text as if
+it weren't colorized. It also uses a much simpler word splitting regex to
+prevent the splitting of ANSI colors as well as package names and versions."""
+
+import re
+import textwrap
+
+class TextWrapper(textwrap.TextWrapper):
+ """Ignore ANSI escape codes while wrapping text"""
+
+ def _split(self, text):
+ """_split(text : string) -> [string]
+
+ Split the text to wrap into indivisible chunks.
+ """
+ # Only split on whitespace to avoid mangling ANSI escape codes or
+ # package names.
+ wordsep_re = re.compile(r'(\s+)')
+ chunks = wordsep_re.split(text)
+ chunks = filter(None, chunks)
+ return chunks
+
+ def _wrap_chunks(self, chunks):
+ """_wrap_chunks(chunks : [string]) -> [string]
+
+ Wrap a sequence of text chunks and return a list of lines of
+ length 'self.width' or less. (If 'break_long_words' is false,
+ some lines may be longer than this.) Chunks correspond roughly
+ to words and the whitespace between them: each chunk is
+ indivisible (modulo 'break_long_words'), but a line break can
+ come between any two chunks. Chunks should not have internal
+ whitespace; ie. a chunk is either all whitespace or a "word".
+ Whitespace chunks will be removed from the beginning and end of
+ lines, but apart from that whitespace is preserved.
+ """
+ lines = []
+ if self.width <= 0:
+ raise ValueError("invalid width %r (must be > 0)" % self.width)
+
+ # Arrange in reverse order so items can be efficiently popped
+ # from a stack of chunks.
+ chunks.reverse()
+
+ # Regex to strip ANSI escape codes. It's only used for the
+ # length calculations of indent and each chuck.
+ ansi_re = re.compile('\x1b\[[0-9;]*m')
+
+ while chunks:
+
+ # Start the list of chunks that will make up the current line.
+ # cur_len is just the length of all the chunks in cur_line.
+ cur_line = []
+ cur_len = 0
+
+ # Figure out which static string will prefix this line.
+ if lines:
+ indent = self.subsequent_indent
+ else:
+ indent = self.initial_indent
+
+ # Maximum width for this line. Ingore ANSI escape codes.
+ width = self.width - len(re.sub(ansi_re, '', indent))
+
+ # First chunk on line is whitespace -- drop it, unless this
+ # is the very beginning of the text (ie. no lines started yet).
+ if chunks[-1].strip() == '' and lines:
+ del chunks[-1]
+
+ while chunks:
+ # Ignore ANSI escape codes.
+ l = len(re.sub(ansi_re, '', chunks[-1]))
+
+ # Can at least squeeze this chunk onto the current line.
+ if cur_len + l <= width:
+ cur_line.append(chunks.pop())
+ cur_len += l
+
+ # Nope, this line is full.
+ else:
+ break
+
+ # The current line is full, and the next chunk is too big to
+ # fit on *any* line (not just this one).
+ # Ignore ANSI escape codes.
+ if chunks and len(re.sub(ansi_re, '', chunks[-1])) > width:
+ self._handle_long_word(chunks, cur_line, cur_len, width)
+
+ # If the last chunk on this line is all whitespace, drop it.
+ if cur_line and cur_line[-1].strip() == '':
+ del cur_line[-1]
+
+ # Convert current line back to a string and store it in list
+ # of all lines (return value).
+ if cur_line:
+ lines.append(indent + ''.join(cur_line))
+
+ return lines
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..c7fb76c
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+from distutils.core import setup
+
+VER = '0.3.0_rc1'
+
+setup(
+ name='gentoolkit',
+ version=VER,
+ description='Set of tools that work with and enhance portage.',
+ author='',
+ author_email='',
+ maintainer='Gentoo Portage Tools Team',
+ maintainer_email='tools-portage@gentoo.org',
+ url='http://www.gentoo.org/proj/en/portage/tools/index.xml',
+ download_url='http://genscripts.googlecode.com/files/gentoolkit-%s.tar.gz'\
+ % VER,
+ package_dir={'': 'pym'},
+ packages=(
+ 'gentoolkit',
+ 'gentoolkit.equery',
+ 'gentoolkit.glsa'
+ ),
+ scripts=(
+ 'bin/eclean',
+ 'bin/epkginfo',
+ 'bin/equery',
+ 'bin/eread',
+ 'bin/euse',
+ 'bin/glsa-check',
+ 'bin/revdep-rebuild'
+ ),
+ data_files=(
+ ('/etc/env.d', ['data/99gentoolkit-env']),
+ ('/etc/revdep-rebuild', ['data/revdep-rebuild/99revdep-rebuild']),
+ ('/etc/eclean', [
+ 'data/eclean/distfiles.exclude',
+ 'data/eclean/packages.exclude'
+ ]),
+ ('/usr/share/man/man1', [
+ 'man/eclean.1',
+ 'man/epkginfo.1',
+ 'man/equery.1',
+ 'man/eread.1',
+ 'man/euse.1',
+ 'man/glsa-check.1',
+ 'man/revdep-rebuild.1'
+ ])
+ )
+)
diff --git a/trunk/src/eclean/AUTHORS b/src/eclean/AUTHORS
index 9263cbb..9263cbb 100644
--- a/trunk/src/eclean/AUTHORS
+++ b/src/eclean/AUTHORS
diff --git a/trunk/src/eclean/ChangeLog b/src/eclean/ChangeLog
index 36d9a28..36d9a28 100644
--- a/trunk/src/eclean/ChangeLog
+++ b/src/eclean/ChangeLog
diff --git a/trunk/src/eclean/Makefile b/src/eclean/Makefile
index 79c5895..79c5895 100644
--- a/trunk/src/eclean/Makefile
+++ b/src/eclean/Makefile
diff --git a/trunk/src/eclean/THANKS b/src/eclean/THANKS
index 6b8dc2e..6b8dc2e 100644
--- a/trunk/src/eclean/THANKS
+++ b/src/eclean/THANKS
diff --git a/trunk/src/eclean/TODO b/src/eclean/TODO
index 04e64ca..04e64ca 100644
--- a/trunk/src/eclean/TODO
+++ b/src/eclean/TODO
diff --git a/src/eclean/distfiles.exclude b/src/eclean/distfiles.exclude
new file mode 100644
index 0000000..a31be55
--- /dev/null
+++ b/src/eclean/distfiles.exclude
@@ -0,0 +1,5 @@
+# /etc/eclean/distfiles.exclude
+# In this file you can list some categories or cat/pkg-name for which you want
+# to protect distfiles from "ecleaning". You can also name some specific files.
+# See `man eclean` for syntax details.
+metadata.dtd
diff --git a/trunk/src/eclean/eclean b/src/eclean/eclean
index 55cc2a7..55cc2a7 100644
--- a/trunk/src/eclean/eclean
+++ b/src/eclean/eclean
diff --git a/src/eclean/eclean.1 b/src/eclean/eclean.1
new file mode 100644
index 0000000..7d785af
--- /dev/null
+++ b/src/eclean/eclean.1
@@ -0,0 +1,176 @@
+.TH "eclean" "1" "0.4.1" "gentoolkit"
+.SH "NAME"
+eclean \- A cleaning tool for Gentoo distfiles and binary packages.
+.SH "SYNOPSIS"
+.LP
+.B eclean \fR[\fIglobal\-options\fR] ... <\fIactions\fR> \fR[\fIaction\-options\fR] ...
+.LP
+.B eclean\-dist \fR[\fIglobal\-options, distfiles\-options\fR] ...
+.LP
+.B eclean\-pkg \fR[\fIglobal\-options, packages\-options\fR] ...
+.LP
+.B eclean(-dist,-pkg) \fR[\fI\-\-help, \-\-version\fR]
+.SH "DESCRIPTION"
+\fBeclean\fP is small tool to remove obsolete portage sources files and binary packages.
+Used on a regular basis, it prevents your DISTDIR and PKGDIR directories to
+infinitely grow, while not deleting files which may still be useful.
+.PP
+By default, eclean will protect all distfiles or binary packages corresponding to some
+ebuilds available in the Portage tree. This is the safest mode, since it will protect
+whatever may still be useful, for instance to downgrade a package without downloading
+its sources for the second time, or to reinstall a package you unmerge by mistake
+without recompiling it. Sure, it's also a mode in which your DISTDIR and PKGDIR will
+stay rather big (although still not growing infinitely). For the 'distfiles', this
+mode is also quit slow mode because it requiries some access to the whole Portage tree.
+.PP
+If you use the \-\-destructive option, eclean will only protect files corresponding to
+some currently installed package (taking their exact version into account). It will
+save much more space, while still preserving sources files around for minor revision
+bumps, and binaries for reinstallation of corrupted packages. But it won't keep files
+for less usual operations like downgrading or reinstalling an unmerged package. This
+is also the fastest execution mode (big difference for distfiles), and the one used by
+most other cleaning scripts around like yacleaner (at least in its version 0.3).
+.PP
+Somewhere in the middle, adding the \-\-package\-names option when using \-\-destructive
+will protect files corresponding to all existing versions of installed packages. It will
+allow easy downgrading without recompilation or redownloading in case of trouble, but
+won't protect you against package uninstallation.
+.PP
+In addition to this main modes, some options allow to declare a few special cases file
+protection rules:
+.IP o
+\-\-time-limit is useful to protect files which are more recent than a given amount of time.
+.IP o
+\-\-size-limit (for distfiles only) is useful if you want to protect files bigger than a given size.
+.IP o
+\-\-fetch-restricted (for distfiles only) is useful to protect manually downloaded files.
+But it's also very slow (again, it's a reading of the whole Portage tree data)...
+.IP o
+Finally, you can list some categories or package names to protect in exclusion files (see
+\fBEXCLUSION FILES\fP below).
+.SH "PARAMETERS"
+.SS "Global options"
+.TP
+\fB\-C, \-\-nocolor\fP turn off colors on output
+.TP
+\fB\-d, \-\-destructive\fP only keep the minimum for a reinstallation
+.TP
+\fB\-e, \-\-exclude\-file=<path>\fP path to the exclusion file
+\fB<path>\fP is the absolute path to the exclusion file you want to use.
+When this option is not used, default paths are /etc/eclean/{packages,distfiles}.exclude
+(if they exist). Use /dev/null if you have such a file at it standard location and
+you want to temporary ignore it.
+.TP
+\fB\-i, \-\-interactive\fP ask confirmation before deleting
+.TP
+\fB\-n, \-\-package\-names\fP protect all versions (\-\-destructive only)
+.TP
+\fB\-p, \-\-pretend\fP only display what would be cleaned
+.TP
+\fB\-q, \-\-quiet\fP be as quiet as possible, only display errors
+.TP
+\fB\-t, \-\-time-limit=<time>\fP don't delete files modified since <time>
+\fB<time>\fP is an amount of time: "1y" is "one year", "2w" is "two weeks", etc.
+.br
+Units are: y (years), m (months), w (weeks), d (days) and h (hours).
+.TP
+\fB\-h, \-\-help\fP display the help screen
+.TP
+\fB\-V, \-\-version\fP display version informations
+.SS "Actions"
+.TP
+\fBdistfiles\fR
+Clean files from /usr/portage/distfiles (or whatever else is your DISTDIR in /etc/make.conf).
+This action should be useful to almost any Gentoo user, we all have to big DISTDIRs sometime...
+.br
+\fBeclean\-dist\fP is a shortcut to call eclean with the "distfiles" action, for simplified
+command\-line.
+.TP
+\fBpackages\fR
+Clean files from /usr/portage/packages (or whatever else is your PKGDIR in /etc/make.conf).
+This action is in particular useful for people who use the "buildpkg" or "buildsyspkg"
+FEATURES flags.
+.br
+\fBeclean\-pkg\fP is a shortcut to call eclean with the "packages" action, for simplified
+command\-line.
+.SS "Options for the 'distfiles' action"
+.TP
+\fB\-f, \-\-fetch-restricted\fP protect fetch-restricted files (\-\-destructive only)
+.TP
+\fB\-s, \-\-size-limit=<size>\fP don't delete distfiles bigger than <size>
+<size> is a size specification: "10M" is "ten megabytes", "200K" is "two hundreds kilobytes",
+etc.
+.br
+Units are: G, M, K and B.
+.SS "Options for the 'packages' action"
+.TP
+There is no specific option for this action.
+.SH "EXCLUSION FILES"
+Exclusions files are lists of packages names or categories you want to protect
+in particular. This may be useful to protect more binary packages for some system
+related packages for instance. Syntax is the following:
+.IP o
+blank lines and lines starting with a "#" (comments) are ignored.
+.IP o
+only one entry per line is allowed.
+.IP o
+if a line contains a category name, like "sys\-apps", then all packages from this
+category will be protected. "sys\-apps/*" is also allowed for aesthetic reasons, but
+that does NOT mean that wildcard are supported in any way for any other usage.
+.IP o
+if a line contains a package name ("app\-shells/bash"), then this package will be
+protected. Versioned atoms like ">=app\-shells/bash\-3" are NOT supported. Also, the
+full package name (with category) is mandatory.
+.IP o
+if a line contains a package name with an exclamation mark in front ("!sys\-apps/portage"),
+then this package will be excluded from protection. This is only useful if the category
+itself was protected.
+.IP o
+for distfiles protection, a line can also a filename to protect. This is useful if you have
+there some files which are not registered by the ebuilds, like OpenOffice.org i18n files
+("helpcontent_33_unix.tgz" for instance).
+.LP
+By default, if it exists, /etc/eclean/packages.exclude (resp. distfiles.exclude) will be use
+when action is "packages" (resp. "distfiles"). This can be overide with the \-\-exclude\-file
+option.
+.SH "EXAMPLES"
+.LP
+Clean distfiles only, with per file confirmation prompt:
+.br
+.B # eclean \-i distfiles
+.LP
+Check which binary packages could be removed, with a no-color display:
+.br
+.B # eclean \-Cp packages
+.LP
+Clean binary packages of uninstalled packages, but keep all versions of installed ones:
+.br
+.B # eclean-pkg \-d \-n
+.LP
+Clean all distfiles except for installed packages (exact version), those which
+are less than one month old, bigger than 50MB, or fetch-restricted:
+.br
+.B # eclean-dist \-d \-t1m -s50M -f
+.LP
+From a crontab, silently clean packages in the safest mode, and then distfiles in destructive
+mode but protecting files less than a week old, every sunday at 1am:
+.br
+.B 0 1 * * sun \ \ eclean \-C \-q packages ; eclean \-C \-q \-d \-t1w distfiles
+.".SH "BUGS"
+.".TP
+."The policy used to decide wether a distfile can be removed or not relies on the SRC_URI variables ."of ebuilds. It means that if an ebuild uses files that are not part of its SRC_URI, eclean will ."probably remove them. This are ebuilds bugs, please report them as such on ."http://bugs.gentoo.org.
+.".TP
+."In safest mode (default, without the \-\-destructive option), this script can be very slow. There
+."is not much to do about it without hacking outside of the portage API.
+.SH "SEE ALSO"
+.TP
+The Gentoo forum thread that gave birth to eclean:
+.B http://forums.gentoo.org/viewtopic.php?t=3011
+.TP
+The bug report requesting eclean inclusion in gentoolkit:
+.B http://bugs.gentoo.org/show_bug.cgi?id=33877
+.TP
+Yacleaner, one of the other similar tools:
+.B http://blog.tacvbo.net/data/files/yacleaner/
+.SH "AUTHORS"
+Thomas de Grenier de Latour (tgl) <degrenier@easyconnect.fr>
diff --git a/src/eclean/packages.exclude b/src/eclean/packages.exclude
new file mode 100644
index 0000000..8277155
--- /dev/null
+++ b/src/eclean/packages.exclude
@@ -0,0 +1,4 @@
+# /etc/eclean/packages.exclude
+# In this file you can list some categories or cat/pkg-name for which you want
+# to protect binary packages from "ecleaning".
+# See `man eclean` for syntax details.
diff --git a/trunk/src/epkginfo/Makefile b/src/epkginfo/Makefile
index 6a8de9a..6a8de9a 100644
--- a/trunk/src/epkginfo/Makefile
+++ b/src/epkginfo/Makefile
diff --git a/trunk/src/epkginfo/epkginfo b/src/epkginfo/epkginfo
index 637deff..637deff 100755
--- a/trunk/src/epkginfo/epkginfo
+++ b/src/epkginfo/epkginfo
diff --git a/src/epkginfo/epkginfo.1 b/src/epkginfo/epkginfo.1
new file mode 100644
index 0000000..cefe602
--- /dev/null
+++ b/src/epkginfo/epkginfo.1
@@ -0,0 +1,34 @@
+.TH "epkginfo" "1" "0.4.1" "Ned Ludd" "gentoolkit"
+.SH "NAME"
+.LP
+epkginfo \- Displays metadata information from packages in portage
+.SH "SYNTAX"
+.LP
+epkginfo [\fIpackage\-cat/\fP]package
+.SH "EXAMPLES"
+$ epkginfo app\-portage/gentoolkit
+.br
+\fBPackage:\fR app\-portage/gentoolkit
+.br
+\fBHerd:\fR tools\-portage
+.br
+\fBMaintainer:\fR tools\-portage
+.br
+\fBLocation:\fR /usr/portage/app\-portage/gentoolkit
+.br
+\fBKeywords:\fR gentoolkit\-0.2.2:
+.br
+\fBKeywords:\fR gentoolkit\-0.2.3: mips
+.br
+\fBKeywords:\fR gentoolkit\-0.2.3\-r1: ppc ppc64 alpha arm s390 amd64 hppa x86 sparc ia64 m68k sh
+.br
+\fBKeywords:\fR gentoolkit\-0.2.4_pre3:
+.br
+\fBKeywords:\fR gentoolkit\-0.2.4_pre4:
+.br
+\fBKeywords:\fR gentoolkit\-0.2.4_pre5: ~arm ~hppa ~x86 ~m68k ~amd64 ~ppc ~sh ~x86\-fbsd ~ia64 ~alpha ~sparc ~ppc64 ~sparc\-fbsd ~mips ~s390
+.SH "AUTHORS"
+.LP
+Ned Ludd <solar@gentoo.org>
+.SH "BUGS"
+Please report any bugs to http://bugs.gentoo.org
diff --git a/trunk/src/equery/AUTHORS b/src/equery/AUTHORS
index 9935ef7..9935ef7 100644
--- a/trunk/src/equery/AUTHORS
+++ b/src/equery/AUTHORS
diff --git a/trunk/src/equery/Makefile b/src/equery/Makefile
index 177427d..177427d 100644
--- a/trunk/src/equery/Makefile
+++ b/src/equery/Makefile
diff --git a/trunk/src/equery/README b/src/equery/README
index e69de29..e69de29 100644
--- a/trunk/src/equery/README
+++ b/src/equery/README
diff --git a/trunk/src/equery/TODO b/src/equery/TODO
index 5f38e60..5f38e60 100644
--- a/trunk/src/equery/TODO
+++ b/src/equery/TODO
diff --git a/trunk/src/equery/equery b/src/equery/equery
index fd8fa4f..fd8fa4f 100755
--- a/trunk/src/equery/equery
+++ b/src/equery/equery
diff --git a/src/equery/equery.1 b/src/equery/equery.1
new file mode 100644
index 0000000..27b8078
--- /dev/null
+++ b/src/equery/equery.1
@@ -0,0 +1,278 @@
+.TH "equery" "1" "Oct 2005" "gentoolkit" ""
+.SH "NAME"
+equery \- Gentoo: Package Query Tool
+.SH "SYNOPSIS"
+.B equery
+.I [global\-opts] command [local\-opts]
+.PP
+
+.SH "DESCRIPTION"
+equery is a flexible utility which may display various information about
+packages, such as the files they own, their USE flags, the md5sum
+of each file owned by a given package, and many other things.
+
+.SH "OPTIONS"
+The 'command' is the only mandatory option to equery. Most commands require
+a 'pkgspec' option, which is described by <cat/>packagename<\-version>;
+namely, the package name is mandatory, while the category and version are
+optional.
+
+[global\-opts] may be one of:
+
+.B \-q, \-\-quiet
+causes minimal output to be emitted
+.PP
+.B \-C, \-\-nocolor
+turns off colours
+.PP
+.B \-h, \-\-help
+displays a help summary
+.PP
+.B \-V, \-\-version
+displays the equery version
+.PP
+.B \-N, \-\-no\-pipe
+turns off pipe detection
+.PP
+
+Only one command will actually be run, at most. The possible commands are:
+.TP
+.B belongs <local\-opts> file
+This command lists all packages owning the specified file.
+.br
+Note: Normally, only one package will own a file. If multiple packages own the
+same file, it usually consitutes a problem, and should be reported (http://bugs.gentoo.org).
+.br
+.IP
+<local\-opts> is either or both of:
+.br
+.B \-c, \-\-category cat
+only search in category cat
+.br
+.B \-f, \-\-full\-regex
+supplied query is a regex
+.br
+.B \-e, \-\-earlyout
+stop when first match found
+
+.PP
+.B check pkgspec
+This command checks the files of the specified package against recorded MD5
+sums and timestamps.
+.PP
+.TP
+.B depends <local\-opts> pkgspec
+This command displays all dependencies matching pkgspec.
+.br
+<local\-opts> is either or both of:
+.br
+.B \-a, \-\-all\-packages
+search in all available packages (slow)
+.br
+.B \-d, \-\-direct
+search direct dependencies only (default)
+.br
+.B \-D, \-\-indirect
+search indirect dependencies (very slow)
+.br
+.B \-\-depth=n
+Limit depth of indirect dependency tree to n levels. Setting \-\-depth=0 is the same as not specifing \-\-indirect.
+.PP
+.TP
+.B depgraph <local\-opts> pkgspec
+This command display a dependency tree for pkgspec, by default indented to reflect
+how dependancies relate to each other.
+.br
+.IP
+<local\-opts> is either or both of:
+.br
+.B \-U, \-\-no\-useflags
+do not show USE flags.
+.br
+.B \-l, \-\-linear
+do not use fancy formatting
+.br
+.B \-\-depth=n
+Limit depth of dependency graph to n levels.
+.PP
+.TP
+.B files <local\-opts> pkgspec
+This lists files owned by a particular package, optionally with extra
+information specified by <local\-opts>
+.br
+
+<local\-opts> is any combination of:
+.br
+.B \-\-timestamp
+output the timestamp of each file
+.br
+.B \-\-md5sum
+output the md5sum of each file
+.br
+.B \-\-type
+output the type of each file
+.br
+.B \-\-tree
+display results in a tree (turns off all other options)
+.br
+.B \-\-filter=<rules>
+filter output based on files type or path
+.br
+.B \t<rules>
+is a comma separated list of filtering rules. Available rules are:
+.br
+.B \t\tdir\
+regular directories
+.br
+.B \t\tobj\
+regular files
+.br
+.B \t\tsym\
+symbolic links
+.br
+.B \t\tdev\
+device nodes
+.br
+.B \t\tfifo
+named pipes
+.br
+.B \t\tpath
+shortest paths where some files where installed
+.br
+.B \t\tconf
+configuration files (based on $CONFIG_PROTECT)
+.br
+.B \t\tcmd\
+user commands (based on $PATH)
+.br
+.B \t\tdoc\
+documentation files (from /usr/share/doc)
+.br
+.B \t\tman\
+manpages (from /usr/share/man)
+.br
+.B \t\tinfo
+info pages (from /usr/share/info)
+.PP
+.TP
+.B hasuse <local\-opts> useflag
+This command lists packages matching a particular USE flag in a user\-specified combination
+of installed packages, packages which are not installed, the portage tree, and
+the portage overlay tree.
+
+<local\-opts> must not include only \-I;
+if \-I is used, \-p and/or \-o must be also be present. By default, only installed
+packages are searched. \-o searches only the overlay tree [and possibly
+installed packages],
+.I not
+the main portage tree.
+
+.B \-i, \-\-installed
+search installed packages (default)
+.br
+.B \-I, \-\-exclude\-installed
+do not search installed packages
+.br
+.B \-p, \-\-portage\-tree
+also search in portage tree (/usr/portage)
+.br
+.B \-o, \-\-overlay\-tree
+also search in overlay tree (/usr/local/portage)
+.PP
+.TP
+.B list <local\-opts> pkgspec
+This command lists packages matching pkgspec in a user\-specified combination
+of installed packages, packages which are not installed, the portage tree, and
+the portage overlay tree. By default the list command searches for partial name matches.
+
+<local\-opts> \-I cannot be used by itself;
+if \-I is used, \-p and/or \-o must be also be present. By default, only installed
+packages are searched. \-o searches only the overlay tree [and possibly
+installed packages],
+\fInot\fR the main portage tree.
+
+.B \-i, \-\-installed
+search installed packages (default)
+.br
+.B \-I, \-\-exclude\-installed
+do not search installed packages
+.br
+.B \-p, \-\-portage\-tree
+also search in portage tree (/usr/portage)
+.br
+.B \-o, \-\-overlay\-tree
+also search in overlay tree (/usr/local/portage)
+.br
+.B \-f, \-\-full\-regex
+query is a regular expression
+.br
+.B \-e, \-\-exact\-name
+list only those packages that exactly match
+.br
+.B \-d, \-\-duplicates
+only list installed duplicate packages
+.br
+
+\fBOutput:\fR
+
+.br
+The list command searches packages for the name given. If found, the following info will be displayed: the package location between the first square brackets (I for Installed packages, P for Portage, O for Overlay), the possible masks between the second (~ by keyword, - by arch or M hard masked), then the category and complete name and last of all, the slot in which the package is stored.
+
+\fBExamples:\fR
+
+equery list zilla \- list all installed versions of packages containing the string 'zilla'
+
+equery list \-\-exact\-name x11\-libs/gtk+ \- list all installed versions of x11\-libs/gtk+
+
+equery list \-\-full\-regex '(mozilla\-firefox|mozilla\-thunderbird)' \- list all installed versions of mozilla\-firefox and mozilla\-thunderbird
+
+equery list \-\-duplicates \- list all installed slotted packages
+.PP
+.TP
+.B size <local\-opts> pkgspec
+This command outputs the number of files in the specified package, as well as
+their total size in an appropriate unit.
+
+The possible values for <local\-opts>, if specified, are:
+.br
+.B \-b, \-\-bytes
+report size in bytes
+.br
+.B \-f, \-\-full\-regex
+query is a regular expression
+.br
+.B \-e, \-\-exact\-name
+list only those packages that exactly match
+.PP
+.TP
+.B uses <local\-opts> pkgspec
+display USE flags for pkgspec.
+
+The only possible value for <local\-opts>, if specified, is:
+.br
+.B \-a, \-\-all
+include all package versions
+.PP
+.B which pkgspec
+print full path to ebuild for package pkgspec
+.PP
+
+.SH "Unimplemented Options"
+.PP
+.B changes
+.PP
+.B glsa \fR \- use glsa\-check for the time being.
+.PP
+.B stats
+
+
+
+.SH "BUGS"
+Many options aren't implemented. Command\-line parsing could use some work.
+.br
+Submit bug reports to http://bugs.gentoo.org
+.SH "AUTHORS"
+equery, original man page: Karl Trygve Kalleberg <karltk@gentoo.org>, 2003.
+.br
+Massive man page updates: Katerina Barone\-Adesi <katerinab@gmail.com>, 2004.
+
diff --git a/trunk/src/equery/tests/common-functions.sh b/src/equery/tests/common-functions.sh
index f065a0a..f065a0a 100644
--- a/trunk/src/equery/tests/common-functions.sh
+++ b/src/equery/tests/common-functions.sh
diff --git a/trunk/src/equery/tests/run-all-tests.sh b/src/equery/tests/run-all-tests.sh
index 4fe2dfe..4fe2dfe 100755
--- a/trunk/src/equery/tests/run-all-tests.sh
+++ b/src/equery/tests/run-all-tests.sh
diff --git a/trunk/src/equery/tests/test-belongs-help.out b/src/equery/tests/test-belongs-help.out
index 0d2f583..0d2f583 100644
--- a/trunk/src/equery/tests/test-belongs-help.out
+++ b/src/equery/tests/test-belongs-help.out
diff --git a/trunk/src/equery/tests/test-belongs.sh b/src/equery/tests/test-belongs.sh
index bd0eac4..bd0eac4 100755
--- a/trunk/src/equery/tests/test-belongs.sh
+++ b/src/equery/tests/test-belongs.sh
diff --git a/trunk/src/equery/tests/test-changes-help.out b/src/equery/tests/test-changes-help.out
index e69de29..e69de29 100644
--- a/trunk/src/equery/tests/test-changes-help.out
+++ b/src/equery/tests/test-changes-help.out
diff --git a/trunk/src/equery/tests/test-check-help.out b/src/equery/tests/test-check-help.out
index 1e6afcf..1e6afcf 100644
--- a/trunk/src/equery/tests/test-check-help.out
+++ b/src/equery/tests/test-check-help.out
diff --git a/trunk/src/equery/tests/test-check.sh b/src/equery/tests/test-check.sh
index 803299f..803299f 100755
--- a/trunk/src/equery/tests/test-check.sh
+++ b/src/equery/tests/test-check.sh
diff --git a/trunk/src/equery/tests/test-depends-help.out b/src/equery/tests/test-depends-help.out
index 356cd53..356cd53 100644
--- a/trunk/src/equery/tests/test-depends-help.out
+++ b/src/equery/tests/test-depends-help.out
diff --git a/trunk/src/equery/tests/test-depends.sh b/src/equery/tests/test-depends.sh
index e46d614..e46d614 100755
--- a/trunk/src/equery/tests/test-depends.sh
+++ b/src/equery/tests/test-depends.sh
diff --git a/trunk/src/equery/tests/test-depgraph-help.out b/src/equery/tests/test-depgraph-help.out
index 5b9fd22..5b9fd22 100644
--- a/trunk/src/equery/tests/test-depgraph-help.out
+++ b/src/equery/tests/test-depgraph-help.out
diff --git a/trunk/src/equery/tests/test-depgraph.sh b/src/equery/tests/test-depgraph.sh
index 016bb37..016bb37 100755
--- a/trunk/src/equery/tests/test-depgraph.sh
+++ b/src/equery/tests/test-depgraph.sh
diff --git a/trunk/src/equery/tests/test-files-help.out b/src/equery/tests/test-files-help.out
index 846151f..846151f 100644
--- a/trunk/src/equery/tests/test-files-help.out
+++ b/src/equery/tests/test-files-help.out
diff --git a/trunk/src/equery/tests/test-files.sh b/src/equery/tests/test-files.sh
index ad0a5ea..ad0a5ea 100755
--- a/trunk/src/equery/tests/test-files.sh
+++ b/src/equery/tests/test-files.sh
diff --git a/trunk/src/equery/tests/test-glsa-help.out b/src/equery/tests/test-glsa-help.out
index e69de29..e69de29 100644
--- a/trunk/src/equery/tests/test-glsa-help.out
+++ b/src/equery/tests/test-glsa-help.out
diff --git a/trunk/src/equery/tests/test-hasuses-help.out b/src/equery/tests/test-hasuses-help.out
index 1a05645..1a05645 100644
--- a/trunk/src/equery/tests/test-hasuses-help.out
+++ b/src/equery/tests/test-hasuses-help.out
diff --git a/trunk/src/equery/tests/test-help.out b/src/equery/tests/test-help.out
index 26517f4..26517f4 100644
--- a/trunk/src/equery/tests/test-help.out
+++ b/src/equery/tests/test-help.out
diff --git a/trunk/src/equery/tests/test-help.sh b/src/equery/tests/test-help.sh
index 618aac1..618aac1 100755
--- a/trunk/src/equery/tests/test-help.sh
+++ b/src/equery/tests/test-help.sh
diff --git a/trunk/src/equery/tests/test-list-help.out b/src/equery/tests/test-list-help.out
index 82d1fb0..82d1fb0 100644
--- a/trunk/src/equery/tests/test-list-help.out
+++ b/src/equery/tests/test-list-help.out
diff --git a/trunk/src/equery/tests/test-list.sh b/src/equery/tests/test-list.sh
index a43048b..a43048b 100755
--- a/trunk/src/equery/tests/test-list.sh
+++ b/src/equery/tests/test-list.sh
diff --git a/trunk/src/equery/tests/test-size-help.out b/src/equery/tests/test-size-help.out
index c0c63a4..c0c63a4 100644
--- a/trunk/src/equery/tests/test-size-help.out
+++ b/src/equery/tests/test-size-help.out
diff --git a/trunk/src/equery/tests/test-size.sh b/src/equery/tests/test-size.sh
index 126a5db..126a5db 100755
--- a/trunk/src/equery/tests/test-size.sh
+++ b/src/equery/tests/test-size.sh
diff --git a/trunk/src/equery/tests/test-stats-help.out b/src/equery/tests/test-stats-help.out
index e69de29..e69de29 100644
--- a/trunk/src/equery/tests/test-stats-help.out
+++ b/src/equery/tests/test-stats-help.out
diff --git a/trunk/src/equery/tests/test-uses-help.out b/src/equery/tests/test-uses-help.out
index d350e00..d350e00 100644
--- a/trunk/src/equery/tests/test-uses-help.out
+++ b/src/equery/tests/test-uses-help.out
diff --git a/trunk/src/equery/tests/test-uses.sh b/src/equery/tests/test-uses.sh
index d694483..d694483 100755
--- a/trunk/src/equery/tests/test-uses.sh
+++ b/src/equery/tests/test-uses.sh
diff --git a/trunk/src/equery/tests/test-which-help.out b/src/equery/tests/test-which-help.out
index 8bf337e..8bf337e 100644
--- a/trunk/src/equery/tests/test-which-help.out
+++ b/src/equery/tests/test-which-help.out
diff --git a/trunk/src/equery/tests/test-which.sh b/src/equery/tests/test-which.sh
index 491868f..491868f 100755
--- a/trunk/src/equery/tests/test-which.sh
+++ b/src/equery/tests/test-which.sh
diff --git a/trunk/src/eread/AUTHORS b/src/eread/AUTHORS
index 68064ce..68064ce 100644
--- a/trunk/src/eread/AUTHORS
+++ b/src/eread/AUTHORS
diff --git a/trunk/src/eread/Makefile b/src/eread/Makefile
index 1d9b284..1d9b284 100644
--- a/trunk/src/eread/Makefile
+++ b/src/eread/Makefile
diff --git a/src/eread/eread b/src/eread/eread
new file mode 100755
index 0000000..c6d4de1
--- /dev/null
+++ b/src/eread/eread
@@ -0,0 +1,94 @@
+#!/bin/bash
+
+# This is a script to read portage log items from einfo, ewarn etc, new in the
+# portage-2.1 series.
+#
+# Author: Donnie Berkholz <spyderous@gentoo.org>
+# Updated by: Uwe Klosa <uwe.klosa@gmail.com>
+
+# set decent PATH for bug 172969
+
+PATH=/usr/bin:/bin:${PATH}
+
+# Set ELOGDIR
+PORT_LOGDIR="$(portageq envvar PORT_LOGDIR)"
+[ "$PORT_LOGDIR" = "" ] && PORT_LOGDIR="/var/log/portage"
+ELOGDIR="$PORT_LOGDIR/elog"
+
+# Verify that ELOGDIR exists
+if [ ! -d "$ELOGDIR" ]; then
+ echo "ELOG directory: $ELOGDIR does not exist!"
+ exit 1
+fi
+
+# Use the pager from the users environment
+[ -z "$PAGER" ] && PAGER="less"
+
+# Set up select prompt
+PS3="Choice? "
+
+select_loop() {
+ ANY_FILES=$(find . -type f)
+ ANY_FILES=$(echo ${ANY_FILES} | sed -e "s:\./::g")
+
+ if [[ -z ${ANY_FILES} ]]; then
+ echo "No log items to read"
+ break
+ fi
+
+ echo
+ echo "This is a list of portage log items. Choose a number to view that file or type q to quit."
+ echo
+
+ # Pick which file to read
+ select FILE in ${ANY_FILES}; do
+ case ${REPLY} in
+ q)
+ echo "Quitting"
+ QUIT="yes"
+ break
+ ;;
+ *)
+ if [ -f "$FILE" ]; then
+ ${PAGER} ${FILE}
+ read -p "Delete file? [y/N] " DELETE
+ case ${DELETE} in
+ q)
+ echo "Quitting"
+ QUIT="yes"
+ break
+ ;;
+ y|Y)
+ rm -f ${FILE}
+ SUCCESS=$?
+ if [[ ${SUCCESS} = 0 ]]; then
+ echo "Deleted ${FILE}"
+ else
+ echo "Unable to delete ${FILE}"
+ fi
+ ;;
+ # Empty string defaults to N (save file)
+ n|N|"")
+ echo "Saving ${FILE}"
+ ;;
+ *)
+ echo "Invalid response. Saving ${FILE}"
+ ;;
+ esac
+ else
+ echo
+ echo "Invalid response."
+ fi
+ ;;
+ esac
+ break
+ done
+}
+
+pushd ${ELOGDIR} > /dev/null
+
+until [[ -n ${QUIT} ]]; do
+ select_loop
+done
+
+popd > /dev/null
diff --git a/src/eread/eread.1 b/src/eread/eread.1
new file mode 100644
index 0000000..5e18214
--- /dev/null
+++ b/src/eread/eread.1
@@ -0,0 +1,12 @@
+.TH "eread" "1" "1.0" "Donnie Berkholz" "gentoolkit"
+.SH "NAME"
+.LP
+eread \- Gentoo: Tool to display and manage ELOG files from portage
+.SH "SYNTAX"
+.LP
+eread
+.SH "DESCRIPTION"
+.LP
+This tool is used to display and manage ELOG files produced by portage version 2.1 and higher.
+.SH "ENVIRONMENT VARIABLES"
+The eread utility uses the PAGER environment variable to display the ELOG files. If the variable is not set, it defaults to /usr/bin/less.
diff --git a/trunk/src/euse/AUTHORS b/src/euse/AUTHORS
index 12e6db7..12e6db7 100644
--- a/trunk/src/euse/AUTHORS
+++ b/src/euse/AUTHORS
diff --git a/trunk/src/euse/ChangeLog b/src/euse/ChangeLog
index cb50dbb..cb50dbb 100644
--- a/trunk/src/euse/ChangeLog
+++ b/src/euse/ChangeLog
diff --git a/trunk/src/euse/Makefile b/src/euse/Makefile
index d1ad804..d1ad804 100644
--- a/trunk/src/euse/Makefile
+++ b/src/euse/Makefile
diff --git a/trunk/src/euse/euse b/src/euse/euse
index f9fd2fd..f9fd2fd 100755
--- a/trunk/src/euse/euse
+++ b/src/euse/euse
diff --git a/src/euse/euse.1 b/src/euse/euse.1
new file mode 100644
index 0000000..b5148fd
--- /dev/null
+++ b/src/euse/euse.1
@@ -0,0 +1,102 @@
+.TH "EUSE" "1" "2004-10-17" "Gentoo Linux" "Gentoo Toolkit"
+.SH "NAME"
+euse \- Gentoo: command line USE flag editor
+.SH "SYNOPSIS"
+.B euse
+\fI<option> [suboption] [useflaglist]\fB
+.SH "DESCRIPTION"
+.PP
+.I euse
+is used to set(disable/enable) USE flags in /etc/make.conf without having to edit
+the file directly. It is also used to get detail information about use flags
+like description, status of flags(enabled/disabled), type of flag(global/local)
+etc.
+.SH "OPTIONS "
+.TP
+\fB\-E, \-\-enable\fI
+Enables USE flag(s) in make.conf. It accepts one or more space seperated
+USE flags as parameters.
+.TP
+\fB\-D, \-\-disable\fI
+Disables USE flag(s) in make.conf. Puts a '\-' sign in front of the USE flag
+and appends it to the USE setting in make.conf. It accepts one or more
+space seperated USE flags as parameters.
+.TP
+\fB\-P, \-\-prune\fI
+Removes USE flag(s) in make.conf. Removes all positive and negative references to
+the given USE flags from make.conf.
+.TP
+\fB\-i, \-\-info\fI
+Prints detail information about the USE flag(s). If no arguments are given then
+it assumes you want information for all USE flags. If one or more
+arguments are given (space separated) then only information for those flags is
+printed.
+.TP
+\fB\-I, \-\-info\-installed\fI
+Same as \-\-info, except that it will also list the currently installed packages that are utilizing the flag.
+.sp
+.RS
+The output is in the following format:
+.br
+\fB[\- cD ]\fI alpha \- indicates that architecture ...
+.br
+\fB[\- ]\fI moznocompose (net\-www/mozilla):
+.br
+Disable building of mozilla's web page composer
+.br
+The indicators in the first column are:
+.IP is_active
++ if the flag is seen as active by portage, \- if not
+.IP is_in_env
+E if the flag is enabled in the environment, e if it is
+disabled in the environment, nothing if it's not affected
+by the environment
+.IP is_in_make_conf
+C if the flag is enabled in make.conf, c if it is
+disabled in make.conf, nothing if it's not affected
+by make.conf
+.IP is_in_make_defaults
+D if the flag is enabled in make.defaults, d if it is
+disabled in make.defaults, nothing if it's not affected
+by make.defaults
+.IP is_in_make_globals
+G if the flag is enabled in make.globals, g if it is
+disabled in make.globals, nothing if it's not affected
+by make.globals
+.br
+Then follows the name of the flag, for local flags the
+package name and then the description (on a new line for
+local flags).
+.TP
+\fB\-a, \-\-active\fI
+Shows all currently active USE flags and where they are activated (see
+description for \fB\-\-info\fI).
+.TP
+\fB\-h, \-\-help\fI
+Show the help message listing all the available flags and a short description
+.TP
+\fB\-v, \-\-version\fI
+Show the version information
+.SH "FILES"
+/etc/make.conf
+.br
+/etc/make.profile/make.defaults
+.br
+/etc/make.globals
+.br
+$PORTDIR/profiles/use.desc
+.br
+$PORTDIR/profiles/use.local.desc
+.br
+
+.SH "AUTHOR"
+Original version by Arun Bhanu <codebear@gentoo.org>
+.br
+Updated for rewritten euse by Marius Mauch <genone@gentoo.org>
+.SH "BUGS"
+euse doesn't handle USE flags enabled or disabled by use.defaults, use.mask
+or package.use yet. It also doesn't completely understand the \-* flag.
+.SH "SEE ALSO"
+.BR ufed(8),
+.TP
+The \fI/usr/bin/euse\fR script.
diff --git a/trunk/src/gentoolkit/AUTHORS b/src/gentoolkit/AUTHORS
index 0dfa694..0dfa694 100644
--- a/trunk/src/gentoolkit/AUTHORS
+++ b/src/gentoolkit/AUTHORS
diff --git a/trunk/src/gentoolkit/Makefile b/src/gentoolkit/Makefile
index 831bcfd..831bcfd 100644
--- a/trunk/src/gentoolkit/Makefile
+++ b/src/gentoolkit/Makefile
diff --git a/trunk/src/gentoolkit/README b/src/gentoolkit/README
index 916dc81..916dc81 100644
--- a/trunk/src/gentoolkit/README
+++ b/src/gentoolkit/README
diff --git a/trunk/src/distfiles-clean/TODO b/src/gentoolkit/TODO
index e69de29..e69de29 100644
--- a/trunk/src/distfiles-clean/TODO
+++ b/src/gentoolkit/TODO
diff --git a/trunk/src/gentoolkit/__init__.py b/src/gentoolkit/__init__.py
index 28b56be..28b56be 100644
--- a/trunk/src/gentoolkit/__init__.py
+++ b/src/gentoolkit/__init__.py
diff --git a/trunk/src/gentoolkit/errors.py b/src/gentoolkit/errors.py
index db81721..db81721 100644
--- a/trunk/src/gentoolkit/errors.py
+++ b/src/gentoolkit/errors.py
diff --git a/trunk/src/gentoolkit/helpers.py b/src/gentoolkit/helpers.py
index 4652b2d..4652b2d 100644
--- a/trunk/src/gentoolkit/helpers.py
+++ b/src/gentoolkit/helpers.py
diff --git a/trunk/src/gentoolkit/package.py b/src/gentoolkit/package.py
index 4f28671..4f28671 100644
--- a/trunk/src/gentoolkit/package.py
+++ b/src/gentoolkit/package.py
diff --git a/src/gentoolkit/pprinter.py b/src/gentoolkit/pprinter.py
new file mode 100644
index 0000000..ff92a26
--- /dev/null
+++ b/src/gentoolkit/pprinter.py
@@ -0,0 +1,116 @@
+#!/usr/bin/python
+#
+# Copyright 2004 Karl Trygve Kalleberg <karltk@gentoo.org>
+# Copyright 2004 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+#
+# $Header$
+
+import sys
+import gentoolkit
+
+try:
+ import portage.output as output
+except ImportError:
+ import output
+
+
+def print_error(s):
+ """Prints an error string to stderr."""
+ sys.stderr.write(output.red("!!! ") + s + "\n")
+
+def print_info(lv, s, line_break = True):
+ """Prints an informational string to stdout."""
+ if gentoolkit.Config["verbosityLevel"] >= lv:
+ sys.stdout.write(s)
+ if line_break:
+ sys.stdout.write("\n")
+
+def print_warn(s):
+ """Print a warning string to stderr."""
+ sys.stderr.write("!!! " + s + "\n")
+
+def die(err, s):
+ """Print an error string and die with an error code."""
+ print_error(s)
+ sys.exit(err)
+
+# Colour settings
+
+def cpv(s):
+ """Print a category/package-<version> string."""
+ return output.green(s)
+
+def slot(s):
+ """Print a slot string"""
+ return output.bold(s)
+
+def useflag(s):
+ """Print a USE flag strign"""
+ return output.blue(s)
+
+def useflagon(s):
+ """Print an enabled USE flag string"""
+ # FIXME: Collapse into useflag with parameter
+ return output.red(s)
+
+def useflagoff(s):
+ """Print a disabled USE flag string"""
+ # FIXME: Collapse into useflag with parameter
+ return output.blue(s)
+
+def maskflag(s):
+ """Print a masking flag string"""
+ return output.red(s)
+
+def installedflag(s):
+ """Print an installed flag string"""
+ return output.bold(s)
+
+def number(s):
+ """Print a number string"""
+ return output.turquoise(s)
+
+def pkgquery(s):
+ """Print a package query string."""
+ return output.bold(s)
+
+def regexpquery(s):
+ """Print a regular expression string"""
+ return output.bold(s)
+
+def path(s):
+ """Print a file or directory path string"""
+ return output.bold(s)
+
+def path_symlink(s):
+ """Print a symlink string."""
+ return output.turquoise(s)
+
+def productname(s):
+ """Print a product name string, i.e. the program name."""
+ return output.turquoise(s)
+
+def globaloption(s):
+ """Print a global option string, i.e. the program global options."""
+ return output.yellow(s)
+
+def localoption(s):
+ """Print a local option string, i.e. the program local options."""
+ return output.green(s)
+
+def command(s):
+ """Print a program command string."""
+ return output.green(s)
+
+def section(s):
+ """Print a string as a section header."""
+ return output.turquoise(s)
+
+def subsection(s):
+ """Print a string as a subsection header."""
+ return output.turquoise(s)
+
+def emph(s):
+ """Print a string as emphasized."""
+ return output.bold(s)
diff --git a/trunk/src/glsa-check/Makefile b/src/glsa-check/Makefile
index 9ad5717..9ad5717 100644
--- a/trunk/src/glsa-check/Makefile
+++ b/src/glsa-check/Makefile
diff --git a/trunk/src/glsa-check/glsa-check b/src/glsa-check/glsa-check
index fe38331..fe38331 100755
--- a/trunk/src/glsa-check/glsa-check
+++ b/src/glsa-check/glsa-check
diff --git a/trunk/src/glsa-check/glsa-check.1 b/src/glsa-check/glsa-check.1
index 8e0df42..8e0df42 100644
--- a/trunk/src/glsa-check/glsa-check.1
+++ b/src/glsa-check/glsa-check.1
diff --git a/trunk/src/glsa-check/glsa.py b/src/glsa-check/glsa.py
index dfd9acd..dfd9acd 100644
--- a/trunk/src/glsa-check/glsa.py
+++ b/src/glsa-check/glsa.py
diff --git a/src/revdep-rebuild/99revdep-rebuild b/src/revdep-rebuild/99revdep-rebuild
new file mode 100644
index 0000000..bdaecc7
--- /dev/null
+++ b/src/revdep-rebuild/99revdep-rebuild
@@ -0,0 +1,21 @@
+# Default revdep-rebuild configuration file
+#
+# revdep-rebuild no longer uses hardcoded paths. To change the default
+# behavior the following variables can be changed:
+#
+# LD_LIBRARY_MASK - Mask of specially evaluated libraries
+#
+# SEARCH_DIRS - List of directories to search for executables and libraries
+# Use this for directories that are not included in PATH or ld.so.conf.
+# An application should normally not have to set this variable
+#
+# SEARCH_DIRS_MASK - List of directories to not search
+# Use this for directories that should not be searched by revdep-rebuild
+# This is normally used by binary packages such as openoffice-bin
+#
+# Note: This file is sourced using bash by the revdep-rebuild script
+
+LD_LIBRARY_MASK="libodbcinst.so libodbc.so libjava.so libjvm.so"
+SEARCH_DIRS="/bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*"
+SEARCH_DIRS_MASK="/lib*/modules"
+
diff --git a/trunk/src/revdep-rebuild/AUTHORS b/src/revdep-rebuild/AUTHORS
index b3d9b32..b3d9b32 100644
--- a/trunk/src/revdep-rebuild/AUTHORS
+++ b/src/revdep-rebuild/AUTHORS
diff --git a/trunk/src/revdep-rebuild/ChangeLog b/src/revdep-rebuild/ChangeLog
index 9060781..9060781 100644
--- a/trunk/src/revdep-rebuild/ChangeLog
+++ b/src/revdep-rebuild/ChangeLog
diff --git a/trunk/src/revdep-rebuild/Makefile b/src/revdep-rebuild/Makefile
index d509681..d509681 100644
--- a/trunk/src/revdep-rebuild/Makefile
+++ b/src/revdep-rebuild/Makefile
diff --git a/trunk/src/revdep-rebuild/README b/src/revdep-rebuild/README
index 3a51d9f..3a51d9f 100644
--- a/trunk/src/revdep-rebuild/README
+++ b/src/revdep-rebuild/README
diff --git a/trunk/src/revdep-rebuild/TODO b/src/revdep-rebuild/TODO
index d9f6350..d9f6350 100644
--- a/trunk/src/revdep-rebuild/TODO
+++ b/src/revdep-rebuild/TODO
diff --git a/trunk/src/revdep-rebuild/find_pkgs.py b/src/revdep-rebuild/find_pkgs.py
index 7013813..7013813 100755
--- a/trunk/src/revdep-rebuild/find_pkgs.py
+++ b/src/revdep-rebuild/find_pkgs.py
diff --git a/trunk/src/revdep-rebuild/revdep-rebuild b/src/revdep-rebuild/revdep-rebuild
index 72efba0..72efba0 100755
--- a/trunk/src/revdep-rebuild/revdep-rebuild
+++ b/src/revdep-rebuild/revdep-rebuild
diff --git a/trunk/src/revdep-rebuild/revdep-rebuild-old b/src/revdep-rebuild/revdep-rebuild-old
index 52d6d19..52d6d19 100755
--- a/trunk/src/revdep-rebuild/revdep-rebuild-old
+++ b/src/revdep-rebuild/revdep-rebuild-old
diff --git a/trunk/src/revdep-rebuild/revdep-rebuild-sh b/src/revdep-rebuild/revdep-rebuild-sh
index c7acdc6..c7acdc6 100755
--- a/trunk/src/revdep-rebuild/revdep-rebuild-sh
+++ b/src/revdep-rebuild/revdep-rebuild-sh
diff --git a/trunk/src/revdep-rebuild/revdep-rebuild.1 b/src/revdep-rebuild/revdep-rebuild.1
index bcf1e26..bcf1e26 100644
--- a/trunk/src/revdep-rebuild/revdep-rebuild.1
+++ b/src/revdep-rebuild/revdep-rebuild.1
diff --git a/trunk/AUTHORS b/trunk/AUTHORS
deleted file mode 100644
index fdfccf3..0000000
--- a/trunk/AUTHORS
+++ /dev/null
@@ -1,6 +0,0 @@
-Karl Trygve Kalleberg <karltk@gentoo.org>
- * Maintenance
-
-See the AUTHOR file in the various src/<foo> subdirectories for a full
-log of who's done what with whome and when.
-
diff --git a/trunk/Makefile b/trunk/Makefile
deleted file mode 100644
index 834b050..0000000
--- a/trunk/Makefile
+++ /dev/null
@@ -1,88 +0,0 @@
-# Copyright 2003-2004 Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright 2003-2004 Gentoo Technologies, Inc.
-# Distributed under the terms of the GNU General Public License v2
-#
-# $Header$
-
-include makedefs.mak
-
-
-all:
- echo "YARMOUTH (vb.) To shout at foreigners in the belief that the louder you speak, the better they'll understand you."
- echo $(PYVERSION)
- echo $(VERSION)
- echo $(docdir)
- echo $(bindir)
- echo $(sbindir)
- echo $(mandir)
-
-test:
- make -C src/echangelog test
-
-clean:
- rm -rf release/*
-
-dist:
- echo "Error: Must use either dist-gentoolkit or dist-gentoolkit-dev"
- exit 1
-
-dist-gentoolkit-dev:
- mkdir -p release/gentoolkit-dev-$(VERSION)$(RELEASE_TAG)
- for x in ekeyword echangelog ego ebump gensync eviewcvs ; do \
- ( cd src/$$x ; $(MAKE) distdir=release/gentoolkit-dev-$(VERSION)$(RELEASE_TAG) dist ) \
- done
- cp Makefile AUTHORS README README.Developer TODO COPYING NEWS ChangeLog release/gentoolkit-dev-$(VERSION)$(RELEASE_TAG)/
- cat makedefs.mak | \
- sed "s/^VERSION=.*/VERSION=$(VERSION)/" | \
- sed "s/^RELEASE_TAG=.*/RELEASE_TAG=$(RELEASE_TAG)/" | \
- sed "s:^docdir=.*:docdir=\$$(DESTDIR)/usr/share/doc/gentoolkit-dev-\$$(VERSION)\$$(RELEASE_TAG):" \
- > release/gentoolkit-dev-$(VERSION)$(RELEASE_TAG)/makedefs.mak
- ( cd release ; tar zcf gentoolkit-dev-$(VERSION)$(RELEASE_TAG).tar.gz gentoolkit-dev-$(VERSION)$(RELEASE_TAG)/ )
-
-dist-gentoolkit:
- mkdir -p release/gentoolkit-$(VERSION)$(RELEASE_TAG)
- rm -rf release/gentoolkit-$(VERSION)$(RELEASE_TAG)/
- for x in eclean equery eread euse gentoolkit revdep-rebuild glsa-check epkginfo; do \
- ( cd src/$$x ; $(MAKE) distdir=release/gentoolkit-$(VERSION)$(RELEASE_TAG) dist ) \
- done
- cp Makefile AUTHORS README TODO COPYING NEWS ChangeLog release/gentoolkit-$(VERSION)$(RELEASE_TAG)/
- cp src/99gentoolkit-env release/gentoolkit-$(VERSION)$(RELEASE_TAG)/src/
- cat makedefs.mak | \
- sed "s/^VERSION=.*/VERSION=$(VERSION)/" | \
- sed "s/^RELEASE_TAG=.*/RELEASE_TAG=$(RELEASE_TAG)/" \
- > release/gentoolkit-$(VERSION)$(RELEASE_TAG)/makedefs.mak
- ( cd release ; tar zcf gentoolkit-$(VERSION)$(RELEASE_TAG).tar.gz gentoolkit-$(VERSION)$(RELEASE_TAG)/ )
-
-install:
- echo "Error: Must use either install-gentoolkit or install-gentoolkit-dev"
- exit 1
-
-install-gentoolkit:
-
- install -d $(docdir)
- install -d $(bindir)
- install -d $(sbindir)
- install -d $(mandir)
- install -d $(sysconfdir)/env.d
-
- install -m 0644 AUTHORS ChangeLog COPYING NEWS README TODO $(docdir)/
- install -m 0644 src/99gentoolkit-env $(sysconfdir)/env.d/
-
- for x in eclean equery eread euse gentoolkit revdep-rebuild glsa-check epkginfo; do \
- ( cd src/$$x ; $(MAKE) DESTDIR=$(DESTDIR) install ) \
- done
-
-
-# FIXME: If run from the CVS tree, the documentation will be installed in
-# $(DESTDIR)/usr/share/doc/gentoolkit-$(VERSION), not gentoolkit-dev-$(VERSION)
-install-gentoolkit-dev:
-
- install -d $(docdir)
- install -d $(bindir)
- install -d $(mandir)
-
- install -m 0644 AUTHORS ChangeLog COPYING NEWS README README.Developer TODO $(docdir)/
-
- for x in ekeyword echangelog ego ebump eviewcvs ; do \
- ( cd src/$$x ; $(MAKE) DESTDIR=$(DESTDIR) install ) \
- done
diff --git a/trunk/README.Developer b/trunk/README.Developer
deleted file mode 100644
index 6c48c84..0000000
--- a/trunk/README.Developer
+++ /dev/null
@@ -1,65 +0,0 @@
-
-OVERVIEW
-
-The SVN module 'gentoolkit' contains all the scripts and stuff for both the
-gentoolkit and the gentoolkit-dev package. The gentoolkit-dev package is
-an optional add-on, that is only intented for the Gentoo developers.
-
-STYLE POLICY
-
-If you're touching any of the python scripts please don't change the indentation
-style (if it's using tabs, you should use tabs too). Especially don't mix
-spaces and tabs as that makes the code completely unreadable.
-
-MAKING A RELEASE
-
-Releases should only be made by members of the tools-portage team. See
-http://www.gentoo.org/proj/en/metastructure/herds/herds.xml?select=tools-portage
-for who to contact on IRC, or shuffle over a bug report to us, or send
-us a mail at tools-portage@gentoo.org if you need an immediate release.
-
-The release manager (big words;) will then do
-
-1) make VERSION=major.minor.patch RELEASE_TAG=<optional> dist-gentoolkit
-2) copy release/gentoolkit-${VERSION}-${RELEASE_TAG}.tar.gz to
- dev.gentoo.org/space/distfiles-local/
-3) make a new ebuild, app-portage/gentoolkit/gentoolkit-${VERSION}.ebuild
- with a SRC_URI that points to
- mirror://gentoo/gentoolkit-${VERSION}-${RELEASE_TAG}.tar.gz
- (just use one of the previous ebuilds)
-
-The process is similar for gentoolkit-dev:
-
-1) make dist-gentoolkit-dev
-2) copy dist/gentoolkit-dev-${VERSION}-${RELEASE_TAG}.tar.gz to emu
-3) update app-portage/gentoolkit-dev
-
-Important!
-1) _ALWAYS_ make sure you don't "overwrite" a previous release. Your
- new VERSION must be newer than any previous released version. If you
- mess up a release, don't overwrite with the same release number, iterate
- the patch version and try again (and again, and again until you get
- it right;)
-
-
-MAKING A RELEASE WITH release.sh
-
-If you have added your system details at the top of the release.sh script,
-you can make a release in the following fashion:
-
-(NOTE! This only works for -dev at the moment)
-
-1) Add a notice in the ChangeLog about the release you are making.
-2) Do VERSION="x.y.z" ./release.sh dev
-3) Test the package: ACCEPT_KEYWORDS="~arch" emerge gentoolkit-dev
-4) Do a repoman ci -m "Released x.y.z" in your
- CVS/app-portage/gentoolkit-dev directory.
-
-
-Currently, the following people have "release access":
-
- - genone@gentoo.org
- - fuzzyray@gentoo.org
-
-If you want a new release, ping either of us. If you want to get
-"release access", talk to fuzzyray@gentoo.org
diff --git a/trunk/makedefs.mak b/trunk/makedefs.mak
deleted file mode 100644
index efbc8ce..0000000
--- a/trunk/makedefs.mak
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2003 Karl Trygve Kalleberg <karltk@gentoo.org>
-# Copyright 2003 Gentoo Technologies, Inc.
-# Distributed under the terms of the GNU General Public License v2
-#
-# $Header$
-
-# Override this on command line when making a release, ie 'dist'
-
-VERSION=9.9.9
-RELEASE_TAG=
-# python-config is not installed on all arches Bug #113386
-#PYVERSION="`python-config | sed 's/-l//' | sed 's/ -lm.*//'`"
-PYVERSION="`LC_COLLATE=C; python -V 2>&1 | tr '[:upper:]' '[:lower:]' | sed -e 's/ //g;s/\([0-9]\.[0-9]\)\.[0-9]/\1/'`"
-DESTDIR=
-
-docdir=$(DESTDIR)/usr/share/doc/gentoolkit-$(VERSION)$(RELEASE_TAG)
-bindir=$(DESTDIR)/usr/bin
-sbindir=$(DESTDIR)/usr/sbin
-mandir=$(DESTDIR)/usr/share/man/man1
-sysconfdir=$(DESTDIR)/etc
diff --git a/trunk/release.sh b/trunk/release.sh
deleted file mode 100755
index 22313b4..0000000
--- a/trunk/release.sh
+++ /dev/null
@@ -1,89 +0,0 @@
-#! /bin/bash
-
-case $(whoami) in
- karltk)
- publish_path=dev.gentoo.org:public_html/projects/gentoolkit/releases
- publish_public_path="http://dev.gentoo.org/~karltk/projects/gentoolkit/releases"
- portdir=/home/karltk/source/oss/gentoo/gentoo-x86/
- export ECHANGELOG_USER="Karl Trygve Kalleberg <karltk@gentoo.org>"
- ;;
-
- port001)
- publish_path=dev.gentoo.org:public_html/distfiles/gentoolkit/releases
- publish_public_path="http://dev.gentoo.org/~port001/distfiles/gentoolkit/releases"
- portdir=/home/port001/Gentoo/gentoo-x86/
- export ECHANGELOG_USER="Ian Leitch <port001@gentoo.org>"
- ;;
-
- genone)
- publish_path=dev:public_html/distfiles/
- publish_public_path="http://dev.gentoo.org/~genone/distfiles/"
- portdir=/home/gentoo/cvs/gentoo-x86/
- export ECHANGELOG_USER="Marius Mauch <genone@gentoo.org>"
- ;;
-
- agriffis)
- publish_path=gentoo:public_html/dist/
- publish_public_path="http://dev.gentoo.org/~agriffis/dist/"
- portdir=/home/agriffis/portage/
- ;;
-
- *)
- echo "!!! Don't know who $(whoami) is, can't release"
- exit 1
- ;;
-esac
-
-function most-recent-ebuild() {
- # FIXME: actually pick the most recent one
- ls gentoolkit-dev-*.ebuild | tail -n 1
-}
-
-function release-dev() {
-
- echo "* Building .tar.bz"
- make VERSION=${VERSION} RELEASE_TAG=${RELEASE_TAG} dist-gentoolkit-dev > /dev/null || exit
-
- echo "* Uploading .tar.bz"
- scp release/gentoolkit-dev-${VERSION}${RELEASE_TAG}.tar.gz ${publish_path} || exit
-
-
- echo "* Generating new ebuild"
-
- local ebuild="gentoolkit-dev-${VERSION}${RELEASE_TAG}.ebuild"
-
- cd ${portdir}/app-portage/gentoolkit-dev || exit
- cp $(most-recent-ebuild) ${ebuild}
- ekeyword ~all ${ebuild}
- sed -i -e "s|SRC_URI=.*|SRC_URI=\"${publish_public_path}/\$\{\P\}.tar.gz\"|" ${ebuild}
-
- echo "* Generating digest"
- ebuild ${ebuild} digest || exit
- cvs add ${ebuild} || exit
- echangelog "New upstream release"
- echo '* Everything ready. You should:'
- echo ' 1) ACCEPT_KEYWORDS="~x86" sudo emerge =gentoolkit-dev-${VERSION}${RELEASE_TAG}'
- echo ' 2) repoman ci -m "New upstream release" from `pwd`'
-}
-
-
-if [ -z "${VERSION}" ] ; then
- echo "!!! You must set the VERSION env var"
- exit 1
-fi
-
-if [ -z "${RELEASE_TAG}" ] ; then
- echo "No RELEASE_TAG found, presumably okay"
-fi
-
-
-if [ "$1" == "dev" ] ; then
- release-dev
-elif [ "$1" == "main" ] ; then
- echo "!!! Unsupported atm, feel free to add code;)"
- exit 1
-else
- echo "!!! You must select to release either 'dev' or 'main', as parameter to release.sh"
- exit 1
-fi
-
diff --git a/trunk/src/change/AUTHORS b/trunk/src/change/AUTHORS
deleted file mode 100644
index 4b3873a..0000000
--- a/trunk/src/change/AUTHORS
+++ /dev/null
@@ -1,5 +0,0 @@
-Dan Armak <danarmak@gentoo.org>
- * Basic idea
- * Initial version
-Karl Trygve Kalleberg <karltk@gentoo.org>
- * Gentoolkit-specific changes
diff --git a/trunk/src/change/ChangeLog b/trunk/src/change/ChangeLog
deleted file mode 100644
index bd7d5dd..0000000
--- a/trunk/src/change/ChangeLog
+++ /dev/null
@@ -1,7 +0,0 @@
-2002-08-11 Dan Armak <danarmak@gentoo.org>:
- * Fix two bugs which are long to describe, so I won't do so here.
- They caused malformed or incomplete changelog files to be created.
-
-2002-08-09 Karl Trygve Kalleberg <karltk@gentoo.org>:
- * Reformatted usage to work with 80 columns
- * Now loads ~/.gentoo/gentool-env instead of ~/.change
diff --git a/trunk/src/change/README b/trunk/src/change/README
deleted file mode 100644
index bda1842..0000000
--- a/trunk/src/change/README
+++ /dev/null
@@ -1,20 +0,0 @@
-Package : change
-Version : 0.2.4
-Author : See AUTHORS
-
-MOTIVATION
-
-Maintaing Gentoo's ChangeLog files in the Portage Tree is a tedious affair.
-Many of the details are well-defined enough for a tool to do. change is this
-tool.
-
-MECHANICS
-
-change can create a ChangeLog, add entries to the ChangeLog file, scan for
-updated files.
-
-
-IMPROVEMENTS
-
-For improvements, send a mail to karltk@gentoo.org or make out a bug at
-bugs.gentoo.org and assign it to me.
diff --git a/trunk/src/change/change b/trunk/src/change/change
deleted file mode 100644
index 094573b..0000000
--- a/trunk/src/change/change
+++ /dev/null
@@ -1,343 +0,0 @@
-#! /bin/bash
-
-# Copyright 1999-2002 Gentoo Technologies, Inc.
-# Distributed under the terms of the GNU General Public License v2
-# Author: Dan Armak <danarmak@gentoo.org>
-# $Header: /space/gentoo/cvsroot/gentoolkit/src/change/change,v 1.2 2002/08/11 13:32:12 karltk Exp $
-
-eval `grep PORTDIR= /etc/make.globals`
-eval `grep PORTDIR= /etc/make.conf`
-[ -z "$PORTDIR" ] && PORTDIR="/usr/portage"
-
-# register temp files (we delete them in the end)
-TMPMESSAGE=`tempfile -p change` || cleanup 1
-TMPHEADER=`tempfile -p change` || cleanup 1
-TMPENTRY=`tempfile -p change` || cleanup 1
-TMPOLDLOG=`tempfile -p change` || cleanup 1
-TMPCHANGELOG=`tempfile -p change` || cleanup 1
-
-# get user info from config file - $AUTHORNAME and $AUTHOREMAIL
-init() {
- . ~/.gentoo/gentool-env || return 1
-}
-
-print_about() {
-
- echo "change v 0.2.4 - A Gentoo ChangeLog editor."
- echo "Author Dan Armak <danarmak@gentoo.org>"
-}
-
-print_usage() {
-
- echo "Usage:
-change <package list> [-shv] [-m|--message msg] [-f|--message-file file]
- [-a|--authorname name] [-l|--authormail mail]
- [-n|--new-version ver] [-o|--output dest]
-
-<package list>: List of packages whose changelogs are to be edited. All
-changelogs edited in one run will be added the same log message.
-
-Acceptable formats: Example:
-category/package kde-base/kdebase
-path to package dir kdebase || ../../kdebase
-path to changelog file portage/kde-base/kdebase/ChangeLog
-
-Note that you must use -g for changelog files outside $PORTDIR.
-
--m, --message \"msg\" Use log message \"msg\", do not open editor.
--f, --message-file <file> Use contents of <file> as log message, do not open
- editor.
--a, --authorname \"name\" Use \"name\" (e.g. Dan Armak) in log.
--l, --authormail \"email\" Use \"email\" (e.g. danarmak@gentoo.org) in log.
--n, --new-version \"ver\" Add a line about a new version number \"ver\" to
- the log.
--g, --generate Create a new changelog file if one does not exist.
- This option must come before the list of affected
- changelog files. Incidentally, this option also
- enables you to work with a changelog file outside
- $PORTDIR.
- You must use it every time you edit such a file.
- However, change won't be able to figure out the
- category and package names of your changelog file
- and those parts will be missing. (FIXME!)
--o, --output \"file\" Save new changelog in file \"file\".
- Default is the the same file we're changing (i.e.
- no backup).
--s, --stdout Print new changelog to stdout (disables saving to
- file). This suppresses the usual info messages.
--c, --changed-files List of changed files (goes into entry header).
- Default is to simply say \"ChangeLog :\". Multiple
- -c options can be given.
--h, --help Print this usage information.
--v, --version Print a short about line and the version number and
- exit.
-
-See also the mandatory config file ~/.gentoo/gentool-env (the gentool-env man
-page contains a template).
-"
-
-}
-
-# parse command line parameters
-# this function should be called before all others (e.g. before init())
-# or else it might stomp on some settings
-parse_params() {
-
- # at least one parameter required - changelog to process
- if [ -z "$1" ]; then
- echo "At least one parameter is required."
- print_about
- print_usage
- cleanup 1
- fi
-
- while [ -n "$1" ]; do
-
- # note: with parameters that come in two pieces (i.e. -m foo)
- # we identify the first one, grab the second one from $2 and
- # shift an extra time
- case "$1" in
-
- # optional log message, if defined then we won't launch $EDITOR
- # comes in explicit string and file reference variations
- -m | --message)
- MESSAGE="$2"
- shift
- ;;
- -f | --message-file)
- cp $2 $TMPMESSAGE
- shift
- ;;
-
- # general settings (usually set in .change)
- -a | --authorname)
- AUTHORNAME="$2"
- shift
- ;;
- -l | --authormail)
- AUTHOREMAIL="$2"
- shift
- ;;
-
- # add a line about a new version (starting with *) to the changelog
- # to add the line but no changelog info, call with -n -m ""
- -n | --new-version)
- NEWVERSION="$2"
- shift
- ;;
-
- # create a new changelog file
- -g | --generate)
- GENERATE=true
- ;;
-
- # output redirection. default (if $OUTPUT isn't set) is to change the
- # specified changelog file.
- # illegal if more than one changelog file/package is specified.
- -o | --output)
- OUTPUT="$2"
- shift
- ;;
- # redirect output to stdout - can be combined with -o
- -s | --stdout)
- STDOUT="true"
- OUTPUT="/dev/null"
- ;;
-
- # list of files changed (second part inclosed in quotes!)
- -c | --changed-files)
- CHANGED="$CHANGED $2"
- shift
- ;;
-
- # request for version/usage information etc
- -h | --help)
- print_about
- print_usage
- cleanup 0
- ;;
- -v | --version)
- print_about
- cleanup 0
- ;;
-
- # everything else we couldn't identify. most of it is packages/files to work on.
- *)
- for x in "$MYPORTDIR/$1/ChangeLog" "$PORTDIR/$1/ChangeLog" "$PWD/$1/ChangeLog" "$PWD/$1"; do
- if [ -f "$x" ]; then
- FILES="$FILES $x"
- shift # because by calling continue we skip the shift at the end of the case block
- continue 2 # next while iteration
- fi
- done
- # if we haveb't detected a changelog file, maybe we need to create one
- if [ -n "$GENERATE" ]; then
- for x in "$PWD/$1" "$1" "$MYPORTDIR/$1" "$PORTDIR/$1"; do
- if [ -d "$x" ]; then
- touch $x/ChangeLog
- FILES="$FILES $x/ChangeLog"
- shift # because by calling continue we skip the shift at the end of the case block
- continue 2 # next while iteration
- fi
- done
- fi
-
- echo "!!! Error: unrecognized option: $1"
- echo
- print_usage
- cleanup 1
-
- ;;
-
- esac
-
- shift
- done
-
- if [ -z "$FILES" ]; then
- echo "No changelog path or package name passed, mandatory parameter missing."
- echo
- print_usage
- cleanup 1
- fi
-
-}
-
-# get the log message
-get_msg() {
-
- if [ -n "`cat $TMPMESSAGE`" ]; then
- echo "Using message-on-file."
- elif [ -n "$MESSAGE" ]; then
- echo "$MESSAGE" > $TMPMESSAGE
- else # [ -z "$MESSAGE" ]
-
- echo > $TMPMESSAGE
- echo "Please enter changelog. You can leave this line, it will be automatically removed." >> $TMPMESSAGE
- $EDITOR $TMPMESSAGE
- cp $TMPMESSAGE ${TMPMESSAGE}2
- sed -e '/Please enter changelog. You can leave this line, it will be automatically removed./ D' \
- ${TMPMESSAGE}2 > $TMPMESSAGE
- rm ${TMPMESSAGE}2
-
- fi
-
- # break up into 80-character columns (actually 78 chars because we'll
- # add two spaces to every line)
- cp $TMPMESSAGE ${TMPMESSAGE}2
- fmt -s -w 78 ${TMPMESSAGE}2 > $TMPMESSAGE
- rm ${TMPMESSAGE}2
-
- # add two spaces to the beginning of every line of the message.
- # do this separately from the sed in the else section above
- # because it should be executed for the if and elif sections too.
- cp $TMPMESSAGE ${TMPMESSAGE}2
- sed -e 's:^: :g' ${TMPMESSAGE}2 > $TMPMESSAGE
- rm ${TMPMESSAGE}2
-
-}
-
-# get list of files and wrap it in the following manner:
-# 1 item on the first list and upto 80 chars on every other.
-# also adds 2 spaces to the beginning of every line but the first.
-wrap_list() {
-
- echo -n $1
- shift
-
- while [ -n "$1" ]; do
- if [ -n "$LIST" ]; then
- LIST="$LIST, $1"
- else
- echo ,
- LIST="$1"
- fi
- shift
- done
- LIST="$LIST :"
-
- echo $LIST | fmt -s -w 78 | sed -e 's:^: :g' -
-
-}
-
-# do the actual work on te changelog file passed as $1
-process() {
- # figure out category and package names
- name=${1//${PORTDIR}}
- name=${name//${MYPORTDIR}}
- name=${name//\/ChangeLog}
-
- OLDIFS="$IFS"
- IFS="/"
- for x in $name; do
- if [ -z "$CATEGORY" ]; then
- CATEGORY="$x"
- else
- PACKAGE="$x"
- fi
- done
- IFS="$OLDIFS"
-
- # create header
- echo \
-"# ChangeLog for $CATEGORY/$PACKAGE
-# Copyright 2002 Gentoo Technologies, Inc.; Distributed under the GPL v2
-# \$Header: \$
-" > $TMPHEADER
-
- # create entry line
- if [ -n "$NEWVERSION" ]; then
- echo "*$PACKAGE-$NEWVERSION (`date '+%d %b %Y'`)" > $TMPENTRY
- echo >> $TMPENTRY
- fi
-
- echo -n " `date "+%d %b %Y"`; ${AUTHORNAME} <${AUTHOREMAIL}> " >> $TMPENTRY
- [ -z "$CHANGED" ] && CHANGED="ChangeLog "
- wrap_list $CHANGED >> $TMPENTRY
-
- echo >> $TMPENTRY
-
- # get the original changelog, minus the old header
- sed -e '/^# ChangeLog for/ D
- /^# Copyright 2002 Gentoo Technologies/ D
- /^# \$Header:/ D' $1 > $TMPOLDLOG
-
- # join everything together
- cat $TMPHEADER $TMPENTRY $TMPMESSAGE $TMPOLDLOG > $TMPCHANGELOG
-
- # various output options
- if [ -n "$OUTPUT" ]; then
- cp $TMPCHANGELOG $OUTPUT
- [ -z "$STDOUT" ] && echo "New changelog saved in $OUTPUT."
- else
- cp $TMPCHANGELOG $1
- [ -z "$STDOUT" ] && echo "Original changelog $1 replaced."
- fi
-
- if [ -n "$STDOUT" ]; then
- cat $TMPCHANGELOG
- fi
-
-}
-
-# pass exit code to this function
-cleanup() {
-
- rm -f $TMPMESSAGE $TMPHEADER $TMPENTRY $TMPCHANGELOG $TMPOLDLOG
-
- exit $1
-
-}
-
-parse_params "${@}"
-
-init
-
-get_msg
-
-for x in $FILES; do
- process $x
-done
-
-cleanup 0
-
diff --git a/trunk/src/change/change.1 b/trunk/src/change/change.1
deleted file mode 100644
index e69de29..0000000
--- a/trunk/src/change/change.1
+++ /dev/null
diff --git a/trunk/src/dep-clean/AUTHORS b/trunk/src/dep-clean/AUTHORS
deleted file mode 100644
index 2fa030f..0000000
--- a/trunk/src/dep-clean/AUTHORS
+++ /dev/null
@@ -1,9 +0,0 @@
-Maintainer:
-Karl Trygve Kalleberg <karltk@gentoo.org>
-
-Authors:
-Karl Trygve Kalleberg <karltk@gentoo.org> (dep-clean, man page)
-Jerry Haltom <ssrit@larvalstage.net> (dep-clean)
-Brandon Low <lostlogic@gentoo.org> (dep-clean)
-Paul Belt <gaarde@users.sourceforge.net> (man page)
-Brandon Low <lostlogic@gentoo.org> (dep-clean)
diff --git a/trunk/src/dep-clean/ChangeLog b/trunk/src/dep-clean/ChangeLog
deleted file mode 100644
index dc6980e..0000000
--- a/trunk/src/dep-clean/ChangeLog
+++ /dev/null
@@ -1,13 +0,0 @@
- 04 Oct 2003: Karl Trygve Kalleberg <karltk@gentoo.org> dep-clean, dep-clean.1:
- * Rewrote to Python
- * Uses gentoolkit
- * Changed the switches to be proper toggles
-
- 25 Feb 2003; Brandon Low <lostlogic@gentoo.org> dep-clean, dep-clean.1:
- * Update to work with current everything
- * Add -q and change the default behaviour and the verbose behavior
- * Make a lot faster by rewriting most everything
- * Make script much more readable
- * Make pay attention to PORTDIR_OVERLAY
- * Bring back from the dead as it give more info
- than the depclean action in portage.
diff --git a/trunk/src/dep-clean/README b/trunk/src/dep-clean/README
deleted file mode 100644
index 6521aef..0000000
--- a/trunk/src/dep-clean/README
+++ /dev/null
@@ -1,4 +0,0 @@
-See man dep-clean or just run dep-clean --help.
-
-QuickStart:
-dep-clean displays missing, extra, and removed packages on your system.
diff --git a/trunk/src/dep-clean/dep-clean b/trunk/src/dep-clean/dep-clean
deleted file mode 100644
index 2f2bde0..0000000
--- a/trunk/src/dep-clean/dep-clean
+++ /dev/null
@@ -1,164 +0,0 @@
-#!/usr/bin/python
-#
-# Terminology:
-#
-# portdir = /usr/portage + /usr/local/portage
-# vardir = /var/db/pkg
-
-import sys
-import gentoolkit
-try:
- from portage.output import *
-except ImportError:
- from output import *
-
-__author__ = "Karl Trygve Kalleberg, Brandon Low, Jerry Haltom"
-__email__ = "karltk@gentoo.org, lostlogic@gentoo.org, ssrit@larvalstage"
-__version__ = "0.2.0"
-__productname__ = "dep-clean"
-__description__ = "Portage auxiliary dependency checker"
-
-class Config:
- pass
-
-def defaultConfig():
- Config.displayUnneeded = 1
- Config.displayNeeded = 1
- Config.displayRemoved = 1
- Config.color = -1
- Config.verbosity = 2
- Config.prefixes = { "R" : "",
- "U" : "",
- "N" : "" }
-def asCPVs(pkgs):
- return map(lambda x: x.get_cpv(), pkgs)
-
-def asCPs(pkgs):
- return map(lambda x: x.get_cp(), pkgs)
-
-def toCP(cpvs):
- def _(x):
- (c,p,v,r) = gentoolkit.split_package_name(x)
- return c + "/" + p
- return map(_, cpvs)
-
-def checkDeps():
- if Config.verbosity > 1:
- print "Scanning packages, please be patient..."
-
- unmerged = asCPVs(gentoolkit.find_all_uninstalled_packages())
- unmerged_cp = toCP(unmerged)
-
- merged = asCPVs(gentoolkit.find_all_installed_packages())
- merged_cp = toCP(merged)
-
- (system, unres_system) = gentoolkit.find_system_packages()
- system = asCPVs(system)
-
- (world, unres_world) = gentoolkit.find_world_packages()
- world = asCPVs(world)
-
- desired = system + world
-
- unneeded = filter(lambda x: x not in desired, merged)
- needed = filter(lambda x: x not in merged, desired)
- old = filter(lambda x: x not in unmerged_cp, merged_cp)
-
- if len(needed):
- print "Packages required, but not by world and system:"
- for x in needed: print " " + x
- raise "Internal error, please report."
-
- if len(unres_system) and Config.displayNeeded:
- if Config.verbosity > 0:
- print white("Packages in system but not installed:")
- for x in unres_system:
- print " " + Config.prefixes["N"] + red(x)
-
- if len(unres_world) and Config.displayNeeded:
- if Config.verbosity > 0:
- print white("Packages in world but not installed:")
- for x in unres_world:
- print " " + Config.prefixes["N"] + red(x)
-
- if len(old) and Config.displayRemoved:
- if Config.verbosity > 0:
- print white("Packages installed, but no longer available:")
- for x in old:
- print " " + Config.prefixes["R"] + yellow(x)
-
- if len(unneeded) and Config.displayUnneeded:
- if Config.verbosity > 0:
- print white("Packages installed, but not required by system or world:")
- for x in unneeded:
- print " " + Config.prefixes["U"] + green(x)
-
-def main():
-
- defaultConfig()
-
- for x in sys.argv:
- if 0:
- pass
- elif x in ["-h","--help"]:
- printUsage()
- sys.exit(0)
- elif x in ["-V","--version"]:
- printVersion()
- sys.exit(0)
-
- elif x in ["-n","--needed","--needed=yes"]:
- Config.displayNeeded = 1
- elif x in ["-N","--needed=no"]:
- Config.displayNeeded = 0
-
- elif x in ["-u","--unneeded","--unneeded=yes"]:
- Config.displayUnneeded = 1
- elif x in ["-U","--unneeded=no"]:
- Config.displayUnneeded = 0
-
- elif x in ["-r","--removed","--removed=yes"]:
- Config.displayRemoved = 1
- elif x in ["-R","--removed","--removed=no"]:
- Config.displayRemoved = 0
- elif x in ["-c","--color=yes"]:
- Config.color = 1
- elif x in ["-C","--color=no"]:
- Config.color = 0
-
- elif x in ["-v", "--verbose"]:
- Config.verbosity += 1
- elif x in ["-q", "--quiet"]:
- Config.verbosity = 0
-
- # Set up colour output correctly
- if (Config.color == -1 and \
- ((not sys.stdout.isatty()) or \
- (gentoolkit.settings["NOCOLOR"] in ["yes","true"]))) \
- or \
- Config.color == 0:
- nocolor()
- Config.prefixes = { "R": "R ", "N": "N ", "U": "U " }
-
- checkDeps()
-
-def printVersion():
- print __productname__ + "(" + __version__ + ") - " + \
- __description__
- print "Authors: " + __author__
-
-def printUsage():
- print white("Usage: ") + turquoise(__productname__) + \
- " [" + turquoise("options") + "]"
- print "Where " + turquoise("options") + " is one of:"
- print white("Display:")
- print " -N,--needed needed packages that are not installed."
- print " -R,--removed installed packages not in portage."
- print " -U,--unneeded potentially unneeded packages that are installed."
- print white("Other:")
- print " -C,--nocolor output without color. Categories will be denoted by P,N,U."
- print " -h,--help print this help"
- print " -v,--version print version information"
-
-if __name__ == "__main__":
- main()
diff --git a/trunk/src/dep-clean/dep-clean.1 b/trunk/src/dep-clean/dep-clean.1
deleted file mode 100644
index 9e42019..0000000
--- a/trunk/src/dep-clean/dep-clean.1
+++ /dev/null
@@ -1,194 +0,0 @@
-.\" Automatically generated by Pod::Man version 1.15
-.\" Thu Jul 18 15:59:55 2002
-.\"
-.\" 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 Ip \" List item
-.br
-.ie \\n(.$>=3 .ne \\$3
-.el .ne 3
-.IP "\\$1" \\$2
-..
-.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. | will give a
-.\" real vertical bar. \*(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-|\(bv\*(Tr
-.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\}
-.\"
-.\" 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.
-.if \nF \{\
-. de IX
-. tm Index:\\$1\t\\n%\t"\\$2"
-..
-. nr % 0
-. rr F
-.\}
-.\"
-.\" For nroff, turn off justification. Always turn off hyphenation; it
-.\" makes way too many mistakes in technical documents.
-.hy 0
-.if n .na
-.\"
-.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
-.\" Fear. Run. Save yourself. No user-serviceable parts.
-.bd B 3
-. \" 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 "DEP-CLEAN 1"
-.TH DEP-CLEAN 1 "Copyright 2002 Gentoo Technologies, Inc." "2002-07-18" "GenToolKit's Dependency Checker!"
-.UC
-.SH "NAME"
-dep-clean \- Shows unrequired packages and missing dependencies.
-.SH "SYNOPSIS"
-.IX Header "SYNOPSIS"
-.Vb 1
-\& dep-clean [-RUNICv]
-.Ve
-.SH "DESCRIPTION"
-.IX Header "DESCRIPTION"
-dep-clean displays extraneous, missing or extra packages. Extra packages are those in which are not a part of the portage tree (/usr/portage). It does \s-1NOT\s0 modify the system in any way.
-.SH "OPTIONS"
-.IX Header "OPTIONS"
-.Ip "\-n, \-\-needed" 4
-.Ip "\-N, \-\-needed=no" 4
-.IX Item "-n, --needed"
-Toggle display of needed packages that are not installed. (red) (default=yes)
-.Ip "\-r, \-\-removed" 4
-.Ip "\-R, \-\-removed=no" 4
-.IX Item "-R, --removed"
-Toggle display of installed packages not in portage. (yellow) (default=yes)
-.Ip "\-u, \-\-unneeded" 4
-.Ip "\-U, \-\-unneeded=no" 4
-.IX Item "-U, --unneeded"
-Toggle display of unneeded packages that are installed. (green) (default=yes)
-.Ip "\-c, \-\-color" 4
-.Ip "\-C, \-\-color=no" 4
-.IX Item "-c, --color"
-Toggle output of color. Without color, package types will be noted with R, U and N.
-Default is use whatever Portage is set for.
-.Ip "\-v, \-\-verbose" 4
-.IX Item "-v, --verbose"
-Be more verbose.
-.Ip "\-q, \-\-quiet" 4
-.IX Item "-q, --quiet"
-Be quiet (display only packages).
-.SH "NOTES"
-.IX Header "NOTES"
-.Ip "" 4
-If this script is run on a system that is not up-to-date or which hasn't been cleaned (with 'emerge \-c') recently, the output may be deceptive.
-.Ip "" 4
-If the same package name appears in all three categories, then it is definitely time to update that package and then run 'emerge \-c'.
-.Ip "" 4
-The \-U, \-N and \-R options may be combined, default is \-UNR
-.SH "AUTHORS"
-.IX Header "AUTHORS"
-Jerry Haltom <ssrit at larvalstage dot net> (dep-clean)
-.br
-Brandon Low <lostlogic at gentoo dot org> (dep-clean)
-.PP
-Paul Belt <gaarde at users dot sourceforge dot net> (man page)
-.br
-Karl Trygve Kalleberg <karltk at gentoo dot org> (dep-clean, man page)
diff --git a/trunk/src/dev-scripts/README b/trunk/src/dev-scripts/README
deleted file mode 100644
index 990a2ab..0000000
--- a/trunk/src/dev-scripts/README
+++ /dev/null
@@ -1,2 +0,0 @@
-This directory is intended to be used for small developer oriented scripts used in gentoolkit-dev.
-If a script develops into a full fledged tool, it will be moved into its own subdirectory.
diff --git a/trunk/src/dev-scripts/included_headers.sh b/trunk/src/dev-scripts/included_headers.sh
deleted file mode 100755
index 915628b..0000000
--- a/trunk/src/dev-scripts/included_headers.sh
+++ /dev/null
@@ -1,159 +0,0 @@
-#!/bin/bash
-
-# CHANGES
-#
-# 20051211: Add qfile use from portage-utils, prefer over equery. Create new
-# function track_headers() to handle package manager queries for both
-# relative and absolute headers. Split relative and absolute queries into two
-# separate places, since relative aren't quite as reliable. Prefer headers
-# found in the tarball over those in /usr/include. Also, note which headers
-# weren't considered in the calculation and the reasons why not.
-
-location=${1}
-
-usage() {
- echo "${0##*/} [ -d ] source_location"
- echo " Returns owners of all include files used. ${0##*/} defaults to"
- echo " files in /usr/include, so if a file with the same name within the"
- echo " source is the actual one used, false dependencies may be printed."
- echo
- echo " -d"
- echo " Show debug output: Print files not found"
- exit 1
-}
-
-decho() {
- if [[ -n "${DEBUG}" ]]; then
- echo "${1}"
- fi
-}
-
-if [[ $# -le 0 ]] || [[ $# -ge 3 ]]; then
- usage
-fi
-
-# Handle command-line options
-while getopts d options; do
- case ${options} in
- d) DEBUG=1
- ;;
- *) usage
- ;;
- esac
-done
-# Reset post-option stuff to positional parameters
-shift $((OPTIND - 1))
-
-get_absolute_includes() {
- grep '^#[[:space:]]*include' -r ${1} | grep '.*.[ch]' | grep -e '<' -e '>' \
- | cut -d':' -f2 | cut -d'<' -f2 | cut -d'>' -f1 | grep '.*.[ch]' \
- | sort | uniq
-}
-
-get_relative_includes() {
- grep '^#[[:space:]]*include' -r ${1} | grep '.*.[ch]' | grep -e '"' -e '"' \
- | cut -d':' -f2 | cut -d'"' -f2 | cut -d'"' -f1 | grep '.*.[ch]' \
- | sort | uniq
-}
-
-track_headers() {
- if [[ -x $(which qfile 2> /dev/null) ]]; then
- qfile ${@} | cut -d'(' -f1 | sort | uniq
- elif [[ -x $(which equery 2> /dev/null) ]]; then
- equery -q belongs ${@} | cut -d'(' -f1
- elif [[ -x $(which rpm 2> /dev/null) ]]; then
- rpm -qf ${@}
- else
- echo "Couldn't find package query tool! Printing headerpaths instead."
- echo
- for header in ${@}; do
- echo ${header}
- done
- fi
-}
-
-echo "Analyzing source ... "
-absolute_headers="$(get_absolute_includes ${1})"
-relative_headers="$(get_relative_includes ${1})"
-
-echo "Looking for absolute headers ... "
-echo
-for header in ${absolute_headers}; do
- absheader="/usr/include/${header}"
- if [[ -e ${absheader} ]]; then
- abs_headerpaths="${abs_headerpaths} ${absheader}"
- echo " Looking for ${absheader} ... OK"
- else
- # Try as a relative header in case people use -I with <>
- relative_headers="${relative_headers} ${header}"
- decho " Looking for ${absheader} ... Not found!"
- fi
-done
-
-echo
-echo "Looking for relative headers ... "
-echo
-for header in ${relative_headers}; do
- fullheader=${header}
- header=${header##*/}
- # Prefer headers in tarball over /usr/include
- header_options=$(find ${location} -name ${header} | grep ${fullheader})
- if [[ -z ${header_options} ]]; then
- header_options="$(find /usr/include -name ${header} | grep ${fullheader})"
- header_loc="/usr/include"
- else
- decho " Local header ${header} ... Not considering."
- local_headers="${local_headers} ${header}"
- continue
- fi
- count="0"
- for found in ${header_options}; do
- (( count++ ))
- done
- if [[ ${count} -ge 2 ]]; then
- echo " Looking for ${header} ... "
- echo " More than one option found for ${header} in ${header_loc}."
- echo " Not considering ${header}."
- duplicate_headers="${duplicate_headers} ${header}"
- continue
- elif [[ ${count} -le 0 ]]; then
- decho " Looking for ${header} ... Not found!"
- unfound_headers="${unfound_headers} ${header}"
- continue
- fi
- header=${header_options}
- if [[ -e ${header} ]] && [[ ${header_loc} = /usr/include ]]; then
- rel_headerpaths="${rel_headerpaths} ${header}"
- echo " Looking for ${header} ... OK"
- else
- decho " Looking for ${header} ... Not found!"
- fi
-done
-
-echo "Tracing headers back to packages ..."
-echo
-echo "Headers ignored because they exist in the tarball:"
-echo
-for header in ${local_headers}; do
- echo "${header}"
-done
-echo
-echo "Headers ignored because of duplicates in /usr/include:"
-echo
-for header in ${duplicate_headers}; do
- echo "${header}"
-done
-echo
-echo "Headers ignored because they weren't found:"
-echo
-for header in ${unfound_headers}; do
- echo "${header}"
-done
-echo
-echo "Absolute headers:"
-echo
-track_headers ${abs_headerpaths}
-echo
-echo "Relative headers:"
-echo
-track_headers ${rel_headerpaths}
diff --git a/trunk/src/dev-scripts/linking_libs.sh b/trunk/src/dev-scripts/linking_libs.sh
deleted file mode 100755
index a249305..0000000
--- a/trunk/src/dev-scripts/linking_libs.sh
+++ /dev/null
@@ -1,204 +0,0 @@
-#!/bin/bash
-
-# CHANGES
-#
-# 20051211: Move most of the logic to check for bad links into get_libnames()
-# seds, so we don't wrongly sed out whole link lines. Seems to catch more
-# problems, such as ' or ` or -- in a link.
-# 20051210: Prefer qfile from portage-utils over equery if it's available.
-# Check for ... in "link" lines because configure checks are not links.
-# Change get_link_generic() to handle whole lines at a time instead of single
-# words, so get_linklines() works.
-# 20051210: Rework get_libnames() to use a new style of grep, because the old
-# way was broken on some packages from the \b. Also optimize the "Looking for
-# libraries" section to only grep the log file once for links and cache it;
-# also only grep the link lines ones for a given library, then parse the
-# output for static or shared. Should speed things up considerably for large
-# packages. I get 5 seconds in Analyzing log and 15 in Looking for libs on an
-# xorg-x11-6.8.99.15 log on second run.
-# Create get_link_generic() that both sections call with different options.
-
-usage() {
- echo "${0##*/} compilation_log"
- echo " Checks for -lfoo link commands and finds the library owners."
- exit 1
-}
-
-if [[ $# -lt 1 || $1 == -h || $1 == --help ]]; then
- usage
-fi
-
-
-# Finds all lines in a file that involve linking
-# get_link_generic(char *grep_opts, char *filename)
-get_link_generic() {
- egrep ${1} '\-l\w[^[:space:]]*' ${2} \
- | while read linker; do
- # -linker is passed through to ld and doesn't mean the inker lib.
- # The new -w in grep makes sure they're separate "words", but its
- # "word" characters only include alnum and underscore, so -- gets
- # through.
- # Some configure lines with ... match, so we drop them
- # Some of the configure options match, so we get rid of = for that.
- if \
- [[ "${linker}" != *...* ]] \
- && [[ "${linker}" != -lib ]] \
- && [[ "${linker}" != -libs ]]; then
- echo ${linker}
- fi
- done
-}
-
-# Note the lack of -o, as compared to get_libnames() egrep
-get_linklines() {
- get_link_generic "-w" ${1} | sort | uniq
-}
-
-get_libnames() {
- for x; do
- get_link_generic "-o -w" ${x} \
- | sed \
- -e "/^-link/d" \
- -e "/^-lib/d" \
- -e "s:^-l::g" \
- -e "/=/d" \
- -e "/'/d" \
- -e "/^-/d" \
- -e "s:\.*$::g" \
- -e "s:|::g" \
- -e "s:\"::g" \
- -e "/^-link/d" \
- -e "/^-lib/d"
- done | sort | uniq
-}
-
-get_libdirs() {
- cat /etc/ld.so.conf | sed -e "/^#/d"
-}
-
-check_exists() {
- if [[ -n ${1// } ]]; then
- return 0
- fi
-
- return 1
-}
-
-trace_to_packages() {
- local paths=$1
-
- check_exists "${paths}"
- local ret=$?
- if [[ $ret -ne 0 ]]; then
- return 1
- fi
-
- if [[ -x $(which qfile 2> /dev/null) ]]; then
- qfile -q ${paths} | sort | uniq
- elif [[ -x $(which equery 2> /dev/null) ]]; then
- equery -q belongs ${paths} | cut -d'(' -f1
- elif [[ -x $(which rpm 2> /dev/null) ]]; then
- rpm -qf ${paths}
- else
- echo "Couldn't find package query tool! Printing paths instead."
- echo
- for path in ${paths}; do
- echo ${path}
- done
- fi
-}
-
-# *64 needs to be first, as *lib is a symlink to it so equery screws up
-libdirs="/lib64 /usr/lib64 /lib /usr/lib $(get_libdirs)"
-
-echo "Analyzing log ..."
-libnames=$(get_libnames "$@")
-
-#echo libnames=$libnames
-
-echo "Looking for libraries ..."
-linker_lines=$(get_linklines ${1})
-
-#echo linker_lines=$linker_lines
-
-for libname in ${libnames}; do
- static=0
- shared=0
- line=$(echo ${linker_lines} | grep "\b-l${libname}\b")
- if echo ${line} | grep -q '\b-static\b'; then
- static=1
- fi
- if ! echo ${line} | grep -q '\b-static\b'; then
- shared=1
- fi
- staticlibname="lib${libname}.a"
- sharedlibname="lib${libname}.so"
- if [[ ${static} -eq 1 ]]; then
- echo -n " Looking for ${staticlibname} ... "
- for libdir in ${libdirs}; do
- found=0
- if [[ -e ${libdir}/${staticlibname} ]]; then
- libpaths="${libpaths} ${libdir}/${staticlibname}"
- found=1
- echo "OK"
- break
- fi
- done
- if [[ ${found} -ne 1 ]]; then
- echo "Not found!"
- fi
- fi
- if [[ ${shared} -eq 1 ]]; then
- echo -n " Looking for ${sharedlibname} ... "
- for libdir in ${libdirs}; do
- found=0
- if [[ -e ${libdir}/${sharedlibname} ]]; then
- libpaths="${libpaths} ${libdir}/${sharedlibname}"
- found=1
- echo "OK"
- break
- fi
- done
- if [[ ${found} -ne 1 ]]; then
- echo "Not found!"
- fi
- fi
-done
-
-# Add backslashes in front of any + symbols
-libpaths=${libpaths//+/\\+}
-
-echo "Looking for build tools (imake, etc) ..."
-BUILD_PKGS=$(egrep -h "$@" \
- -e '^(/usr/(X11R6/)?bin/)?rman' \
- -e '^(/usr/(X11R6/)?bin/)?gccmakedep' \
- -e '^(/usr/(X11R6/)?bin/)?makedepend' \
- -e '^(/usr/(X11R6/)?bin/)?imake' \
- -e '^(/usr/(X11R6/)?bin/)?rman' \
- -e '^(/usr/(X11R6/)?bin/)?lndir' \
- -e '^(/usr/(X11R6/)?bin/)?xmkmf' \
- | awk '{ print $1 }' \
- | sort \
- | uniq)
-
-for PKG in ${BUILD_PKGS}; do
- PKG=$(basename ${PKG})
- echo -n " Looking for ${PKG} ... "
- if [[ -e /usr/bin/${PKG} ]]; then
- echo "OK"
- buildpaths="${buildpaths} ${PKG}"
- else
- echo "Not found!"
- fi
-done
-
-echo
-echo "Tracing libraries back to packages ..."
-echo
-trace_to_packages "${libpaths}"
-
-echo
-echo "Tracing build tools back to packages ..."
-echo
-
-trace_to_packages "${buildpaths}"
diff --git a/trunk/src/distfiles-clean/AUTHORS b/trunk/src/distfiles-clean/AUTHORS
deleted file mode 100644
index d913891..0000000
--- a/trunk/src/distfiles-clean/AUTHORS
+++ /dev/null
@@ -1,6 +0,0 @@
-Josť Fonseca <j_r_fonseca@yahoo.co.uk>
- * Wrote the script
-
-Karl Trygve Kalleberg <karltk@gentoo.org>
- * Wrote the man page.
-
diff --git a/trunk/src/distfiles-clean/ChangeLog b/trunk/src/distfiles-clean/ChangeLog
deleted file mode 100644
index dfe6aa8..0000000
--- a/trunk/src/distfiles-clean/ChangeLog
+++ /dev/null
@@ -1,2 +0,0 @@
-2002-15-11: Karl Trygve Kalleberg <karltk@gentoo.org>
- * Imported newest contributions from #10647.
diff --git a/trunk/src/distfiles-clean/distfiles-clean b/trunk/src/distfiles-clean/distfiles-clean
deleted file mode 100644
index 23af32b..0000000
--- a/trunk/src/distfiles-clean/distfiles-clean
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/bin/sh
-#
-# distfiles-clean
-#
-# Cleans unused files from Portage's distfiles directory.
-#
-# Josť Fonseca <j_r_fonseca@yahoo.co.uk>
-
-PROGRAM=`basename "$0"`
-
-while [ ${#} -gt 0 ]
-do
- case "$1" in
- -h|--help)
- USAGE=y
- break
- ;;
- -i|--ignore)
- IGNORE="$IGNORE $2"
- shift 2
- ;;
- -I|--ignore-file)
- IGNORE="$IGNORE `cat "$2"`"
- shift 2
- ;;
- -p|--pretend)
- PRETEND=y
- shift
- ;;
- *)
- echo "$PROGRAM: Invalid option \'$1\'" 1>&2
- USAGE=y
- break
- ;;
- esac
-done
-
-# For PORTDIR and DISTDIR
-. /etc/make.globals
-. /etc/make.conf
-
-if [ "$USAGE" ]
-then
- echo "Usage: $PROGRAM [-h|--help] [-i|--ignore <glob>] [-I|--ignore-file <globfile>] [-p|--pretend]"
- echo "Cleans unused files from $DISTDIR directory."
- exit
-fi
-
-DBDIR=/var/db/pkg
-CACHEDIR=/var/cache/edb/dep
-
-for DIR in "$PORTDIR" "$DISTDIR" "$DBDIR" "$CACHEDIR"
-do
- if [ ! -d "$DIR" ]
- then
- echo "$PROGRAM: \'$DIR\' not found."
- exit
- fi
-done
-
-TMPFILE=`mktemp /tmp/$PROGRAM.XXXXXX`
-
-cd "$DISTDIR"
-
-{
- echo "cvs-src"
- [ "$IGNORE" ] && ls -1d $IGNORE
- find "$DBDIR" -name '*.ebuild' | sed -n -e "s:^$DBDIR/\([^/]*\)/\([^/]*\)/\([^/]*\)\.ebuild$:$CACHEDIR/\1/\3:p" | xargs sed -s -e '4!d;/^$/d;s/[[:alnum:]]\+?\|(\|)//g;s/\<[^[:space:]]\+\/\<//g;s/^[[:space:]]\+//g;s/[[:space:]]\+$//g;s/[[:space:]]\+/\n/g'
-} | sort -u > "$TMPFILE" && ls -1 | comm -23 - "$TMPFILE" | {
- if [ "$PRETEND" ]
- then
- cat
- else
- xargs rm -f
- fi
-}
-
-rm "$TMPFILE"
diff --git a/trunk/src/ebump/AUTHORS b/trunk/src/ebump/AUTHORS
deleted file mode 100644
index 2432e06..0000000
--- a/trunk/src/ebump/AUTHORS
+++ /dev/null
@@ -1,5 +0,0 @@
-Maintainer:
-Karl Trygve Kalleberg <karltk@gentoo.org>
-
-Original author:
-Karl Trygve Kalleberg <karltk@gentoo.org>
diff --git a/trunk/src/ebump/ChangeLog b/trunk/src/ebump/ChangeLog
deleted file mode 100644
index 4434b94..0000000
--- a/trunk/src/ebump/ChangeLog
+++ /dev/null
@@ -1,8 +0,0 @@
-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/trunk/src/ebump/Makefile b/trunk/src/ebump/Makefile
deleted file mode 100644
index aa1d347..0000000
--- a/trunk/src/ebump/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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/trunk/src/ebump/README b/trunk/src/ebump/README
deleted file mode 100644
index c81835c..0000000
--- a/trunk/src/ebump/README
+++ /dev/null
@@ -1,18 +0,0 @@
-
-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/trunk/src/ebump/TODO b/trunk/src/ebump/TODO
deleted file mode 100644
index e69de29..0000000
--- a/trunk/src/ebump/TODO
+++ /dev/null
diff --git a/trunk/src/ebump/ebump b/trunk/src/ebump/ebump
deleted file mode 100755
index 2623a28..0000000
--- a/trunk/src/ebump/ebump
+++ /dev/null
@@ -1,356 +0,0 @@
-#! /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 2 ] ; 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-cvs do not add to CVS"
- echo " -m|--message append message to ChangeLog"
- echo " -d|--delete-old delete previous revision from CVS (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
-}
-
-#
-# 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() {
- ebuild_arg=${1}
-
- # Files to add to CVS
- addfiles=""
- # Files to remove from CVS
- 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"
-
- cp ${PF}.ebuild ${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}
- 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 ChangeLog entry
- #
-
- if [ "${opt_add_changelog}" == "y" ] &&
- [ -f ChangeLog ] ; then
-
- # Add ChangeLog entry
-
- curdate=$(LC_TIME="us" date +"%02d %b %Y")
- cp ChangeLog ChangeLog.old
- (
- # Use header (four first lines) of the old ChangeLog
- head -n 4 ChangeLog.old
-
- # Write new entry
-
- echo "*${newPF} (${curdate})"
- echo
- echo " ${curdate}; ${AUTHORNAME} <${AUTHOREMAIL}> ${filelist}"
-
- # If we don't have a commit message, add comment
- if [ -z "${opt_commitmessage}" ] ; then
- echo " # INSERT ENTRY HERE"
- if [ "${opt_delete_old}" == "y" ] && [ ! -z "${delfiles}" ] ; then
- echo " Removed ${delfiles}."
- fi
- echo
- else
- echo " ${opt_commitmessage}"
- echo
- fi
-
- # Write tail of old ChangeLog
- nl=$(wc -l ChangeLog.old | sed -r "s/^([0-9]+).*/\1/")
- tail -n $[nl - 4] ChangeLog.old
- ) > ChangeLog
- rm ChangeLog.old
-
- einfo "Added ChangeLog entry"
- fi
-
- #
- # (Optional) Add CVS entry for all new files
- #
-
- if [ "${opt_add_cvs}" == "y" ] ; then
-
- # Add all new files to CVS
- for x in ${addfiles} ; do
- if [ -d ${x} ] ; then
- find ${x} | xargs echo cvs add
- else
- cvs add ${x}
- fi
- done
- einfo "Added ${addfiles} to CVS"
- fi
-
-
- #
- # (Optional) Delete previous entry
- #
-
- if [ "${opt_delete_old}" == "y" ] ; then
-
- for x in ${delfiles} ; do
- cvs remove -f ${x}
- done
- einfo "Removed ${delfiles} from CVS"
- fi
-
-}
-
-original_params=${#}
-
-#
-# Global options
-#
-opt_verbosity=1
-opt_warn_on_delete=y
-opt_add_changelog=y
-opt_add_cvs=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-cvs)
- opt_add_cvs=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
-
-process_ebuild ${ebuild_arg}
-
-# TODO:
-# - put cli parser into separate functions
diff --git a/trunk/src/ebump/ebump.1 b/trunk/src/ebump/ebump.1
deleted file mode 100644
index 6a64a0a..0000000
--- a/trunk/src/ebump/ebump.1
+++ /dev/null
@@ -1,110 +0,0 @@
-.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 CVS, and a
-dummy ChangeLog entry will be made.
-
-.LP
-You must stand in the directory of the ebuild to be bumped.
-
-.SH "OPTIONS"
-.LP
-\fB\-C\fR
-.br
-\fB--no-cvs\fB
-.IP
-Do not add new files to CVS.
-
-.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 CVS. 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_cvs\fR (default \fIy\fR) - add new files to CVS
-.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~/.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\fR and \fIego\fR.
-
-.SH "AUTHORS"
-.LP
-Karl Trygve Kalleberg <karltk@gentoo.org>
-
diff --git a/trunk/src/echangelog/AUTHORS b/trunk/src/echangelog/AUTHORS
deleted file mode 100644
index 36d5bfd..0000000
--- a/trunk/src/echangelog/AUTHORS
+++ /dev/null
@@ -1 +0,0 @@
-Aron Griffis <agriffis@gentoo.org>
diff --git a/trunk/src/echangelog/ChangeLog b/trunk/src/echangelog/ChangeLog
deleted file mode 100644
index c1c5885..0000000
--- a/trunk/src/echangelog/ChangeLog
+++ /dev/null
@@ -1,84 +0,0 @@
-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/trunk/src/echangelog/Makefile b/trunk/src/echangelog/Makefile
deleted file mode 100644
index 4825683..0000000
--- a/trunk/src/echangelog/Makefile
+++ /dev/null
@@ -1,26 +0,0 @@
-# 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; sh 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/trunk/src/echangelog/README b/trunk/src/echangelog/README
deleted file mode 100644
index 77a7930..0000000
--- a/trunk/src/echangelog/README
+++ /dev/null
@@ -1,11 +0,0 @@
-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/trunk/src/echangelog/TODO b/trunk/src/echangelog/TODO
deleted file mode 100644
index e69de29..0000000
--- a/trunk/src/echangelog/TODO
+++ /dev/null
diff --git a/trunk/src/echangelog/echangelog b/trunk/src/echangelog/echangelog
deleted file mode 100755
index 551d9b9..0000000
--- a/trunk/src/echangelog/echangelog
+++ /dev/null
@@ -1,711 +0,0 @@
-#!/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::Find;
-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, $year, $vcs);
-my ($opt_help, $opt_strict, $opt_version);
-
-$opt_help = 0;
-$opt_strict = 0;
-$opt_version = 0;
-
-my %vcs = (
- cvs => {
- diff => "cvs -f diff -U0",
- status => "cvs -fn up",
- add => "cvs -f add",
- skip => 6,
- regex => qr/^Index: (([^\/]*?)\.ebuild)\s*$/
- },
- svn => {
- diff => "svn diff -N",
- status => "svn status",
- add => "svn add",
- skip => 4,
- regex => qr/^Index: (([^\/]*?)\.ebuild)\s*$/
- },
- 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)/
- },
-);
-
-sub usage {
- (my $usage = <<" EOF") =~ s/^\t//gm;
- Usage: echangelog [options] <changelog message>
-
- Options:
- --help err, this screen ...
- --strict abort on trivial/no changes
- --version show version info
- 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);
-}
-
-GetOptions(
- 'help' => \$opt_help,
- 'strict' => \$opt_strict,
- 'version' => \$opt_version,
-);
-
-usage() if $opt_help;
-version() if $opt_version;
-
-# Figure out what kind of repo we are in.
-if ( -d "CVS" ) {
- $vcs = "cvs";
-} elsif ( -d '.svn' ) {
- $vcs = "svn";
-} else {
- # Respect $PATH while looking for git
- if (getenv("PATH")) {
- foreach my $path ( split(":", getenv("PATH")) ) {
- if ( -X "$path/git" ) {
- open(GIT, '-|', "git rev-parse --git-dir 2>/dev/null");
- $vcs = "git" if defined(<GIT>);
- close(GIT);
- last;
- }
- }
- }
-
- if ( ! $vcs ) {
- die "No CVS, .git, .svn directories found, what kind of repo is this?";
- }
-}
-
-# 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 envvar PORTDIR |" or die "Can't find PORTDIR";
- my ($new) = <C>;
- close C;
-
- $new =~ s/\s+$//;
- open I, "< $new/skel.ChangeLog"
- or die "Can't open $new/skel.ChangeLog for input: $!\n";
- { local $/ = undef; $text = <I>; }
- close I;
- $text =~ s/^\*.*//ms; # don't need the fake entry
- } 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>) {
- if (/^C\s+(\S+)/) {
- if($vcs eq "git") {
- my $filename = $2;
- $filename =~ /\S*\/(\S*)/;
-
- if( -d $1 ) {
- next;
- }
-
- push @conflicts, $1;
- next;
- }
-
- push @conflicts, $1;
- next;
- } elsif (/^\?\s+(\S+)/) {
- if($vcs eq "git") {
- my $filename = $2;
- $filename =~ /\S*\/(\S*)/;
-
- if( -d $1 ) {
- next;
- }
-
- push @unknown, $1;
- next;
- } else {
- 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>;
- $prefix = substr($prefix, 0, -1);
- close P;
-
- if ($filename =~ /$prefix(\S*)/) {
- $filename = $1 ;
- }
- else {
- next;
- }
- }
-
- if( -d $filename ) {
- next;
- }
-
- push @files, $filename;
- ($actions{$filename} = $status) =~ tr/DARM/-+-/d;
- }
-}
-
-# git only shows files already added so we need to check for unknown files
-# separately here.
-if($vcs eq "git") {
- find(\&git_unknown_objects, "./");
-}
-
-sub git_unknown_objects {
- my $object = $_;
- my ($dev,$ino,$mode,$nlink,$uid,$gid);
-
- # Ignore empty directories - git doesn't version them and cvs removes them.
- if ( (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) && ! -d _ ) {
- open C, $vcs." status $_ 2>&1 1>/dev/null |";
-
- while (<C>) {
- $_ = <C>;
- push @unknown, $object;
- };
-
- close C;
- };
-}
-
-# Separate out the trivial files for now
-@files = grep {
- !/files.digest|Manifest|ChangeLog/ or do { push @trivial, $_; 0; }
-} @files;
-
-@unknown = grep {
- !/files.digest|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;
-}
-
-# Just to ensure we don't get duplicate entries.
-sub mypush(\@@) {
- my $aref = shift;
-
- foreach my $value (@_) {
- push(@{$aref}, $value) if !grep(/^$value$/, @{$aref});
- }
-}
-
-# 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 $f = $1;
-
- if ($vcs eq "git") {
- my $version = $2;
-
- while (<C>) {
- last if /^deleted file mode|^index/;
- if (/^new file mode/) {
- mypush(@files, $f);
- mypush(@new_versions, $version);
- 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, $f);
- 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_strict) {
- print STDERR "** In strict mode, exiting\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";
-}
-
-sub update_cat_pn {
- my ($t) = @_;
- my ($cwd) = getcwd();
-
- $cwd =~ m|.*/(\w+-\w+\|virtual)/([^/]+)|
- or die "Can't figure out category/package.. sorry!\n";
- my ($category, $package_name) = ($1, $2);
- $t =~ s/^(# ChangeLog for).*/$1 $category\/$package_name/;
-
- return $t;
-}
-
-# 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");
- }
-}
-
-# 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/trunk/src/echangelog/echangelog.1 b/trunk/src/echangelog/echangelog.1
deleted file mode 100644
index 1575644..0000000
--- a/trunk/src/echangelog/echangelog.1
+++ /dev/null
@@ -1,270 +0,0 @@
-.\" 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/trunk/src/echangelog/test/TEST.pm b/trunk/src/echangelog/test/TEST.pm
deleted file mode 100644
index 6632148..0000000
--- a/trunk/src/echangelog/test/TEST.pm
+++ /dev/null
@@ -1,26 +0,0 @@
-# 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/trunk/src/echangelog/test/templates/test.patch b/trunk/src/echangelog/test/templates/test.patch
deleted file mode 100644
index 72d46fa..0000000
--- a/trunk/src/echangelog/test/templates/test.patch
+++ /dev/null
@@ -1,6 +0,0 @@
---- 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/trunk/src/echangelog/test/templates/vcstest-0.0.1.ebuild b/trunk/src/echangelog/test/templates/vcstest-0.0.1.ebuild
deleted file mode 100644
index 2824b83..0000000
--- a/trunk/src/echangelog/test/templates/vcstest-0.0.1.ebuild
+++ /dev/null
@@ -1,16 +0,0 @@
-# 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/trunk/src/echangelog/test/test.sh b/trunk/src/echangelog/test/test.sh
deleted file mode 100755
index f2052f3..0000000
--- a/trunk/src/echangelog/test/test.sh
+++ /dev/null
@@ -1,178 +0,0 @@
-#!/bin/sh
-
-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
-
-rm -rf "${_ROOT}/tmp"
diff --git a/trunk/src/ego/AUTHOR b/trunk/src/ego/AUTHOR
deleted file mode 100644
index 36d5bfd..0000000
--- a/trunk/src/ego/AUTHOR
+++ /dev/null
@@ -1 +0,0 @@
-Aron Griffis <agriffis@gentoo.org>
diff --git a/trunk/src/ego/AUTHORS b/trunk/src/ego/AUTHORS
deleted file mode 100644
index 36d5bfd..0000000
--- a/trunk/src/ego/AUTHORS
+++ /dev/null
@@ -1 +0,0 @@
-Aron Griffis <agriffis@gentoo.org>
diff --git a/trunk/src/ego/ChangeLog b/trunk/src/ego/ChangeLog
deleted file mode 100644
index 503d0da..0000000
--- a/trunk/src/ego/ChangeLog
+++ /dev/null
@@ -1,2 +0,0 @@
-2004-15-01 Karl Trygve Kalleberg <karltk@gentoo.org>
- * Added Makefile
diff --git a/trunk/src/ego/Makefile b/trunk/src/ego/Makefile
deleted file mode 100644
index b27a2cb..0000000
--- a/trunk/src/ego/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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/trunk/src/ego/README b/trunk/src/ego/README
deleted file mode 100644
index 6c44b4c..0000000
--- a/trunk/src/ego/README
+++ /dev/null
@@ -1,2 +0,0 @@
-[ -f ${HOME}/scripts/ego.bash ] &&
-alias ego="unalias ego ; source ${HOME}/scripts/ego.bash ; ego "
diff --git a/trunk/src/ego/TODO b/trunk/src/ego/TODO
deleted file mode 100644
index e69de29..0000000
--- a/trunk/src/ego/TODO
+++ /dev/null
diff --git a/trunk/src/ego/ego b/trunk/src/ego/ego
deleted file mode 100644
index f1691f2..0000000
--- a/trunk/src/ego/ego
+++ /dev/null
@@ -1,86 +0,0 @@
-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/trunk/src/ekeyword/AUTHORS b/trunk/src/ekeyword/AUTHORS
deleted file mode 100644
index 36d5bfd..0000000
--- a/trunk/src/ekeyword/AUTHORS
+++ /dev/null
@@ -1 +0,0 @@
-Aron Griffis <agriffis@gentoo.org>
diff --git a/trunk/src/ekeyword/ChangeLog b/trunk/src/ekeyword/ChangeLog
deleted file mode 100644
index 68d99e5..0000000
--- a/trunk/src/ekeyword/ChangeLog
+++ /dev/null
@@ -1,46 +0,0 @@
-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/trunk/src/ekeyword/Makefile b/trunk/src/ekeyword/Makefile
deleted file mode 100644
index c3aed80..0000000
--- a/trunk/src/ekeyword/Makefile
+++ /dev/null
@@ -1,24 +0,0 @@
-# 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)/
-
diff --git a/trunk/src/ekeyword/README b/trunk/src/ekeyword/README
deleted file mode 100644
index ec7ff5e..0000000
--- a/trunk/src/ekeyword/README
+++ /dev/null
@@ -1,20 +0,0 @@
-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/trunk/src/ekeyword/TODO b/trunk/src/ekeyword/TODO
deleted file mode 100644
index e69de29..0000000
--- a/trunk/src/ekeyword/TODO
+++ /dev/null
diff --git a/trunk/src/ekeyword/ekeyword b/trunk/src/ekeyword/ekeyword
deleted file mode 100755
index 002e44b..0000000
--- a/trunk/src/ekeyword/ekeyword
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/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
-# 12c12
-# < KEYWORDS="x86 ppc sparc"
-# ---
-# > KEYWORDS="x86 ppc sparc ~alpha"
-
-
-my ($kw_re) = '^(?:([-~^]?)(\w[\w-]*)|([-^]\*))$';
-my (@kw);
-
-# make sure the cmdline consists of keywords and ebuilds
-unless (@ARGV > 0) {
- die "syntax: ekeyword { arch | ~[arch] | -[arch] } ebuild...\n"
-}
-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;
-
- while (<I>) {
- if (/^\s*KEYWORDS=/) {
-
- # extract the quoted section from KEYWORDS
- while (not /^KEYWORDS=["'].*?["']/) {
- chomp;
- my $next = <I>;
- $_ = join " ", $_, $next;
- }
- (my $quoted = $_) =~ s/^.*?["'](.*?)["'].*/$1/s;
-
- # 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;
-
- # 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;
-
- 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/trunk/src/ekeyword/ekeyword.pod b/trunk/src/ekeyword/ekeyword.pod
deleted file mode 100644
index 1fac8ef..0000000
--- a/trunk/src/ekeyword/ekeyword.pod
+++ /dev/null
@@ -1,74 +0,0 @@
-=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="~x86 ~ppc ~sparc ~alpha ~mips ~hppa ~amd64 ~ia64"
- ---
- > KEYWORDS="~x86 ~ppc ~sparc alpha ~mips ~hppa ~amd64 ~ia64"
-
-When bumping a package, to mark all arches for testing:
-
- $ ekeyword ~all metalog-0.7-r2.ebuild
- metalog-0.7-r2.ebuild
- < KEYWORDS="x86 ppc sparc alpha mips hppa amd64 ia64"
- ---
- > KEYWORDS="~x86 ~ppc ~sparc ~alpha ~mips ~hppa ~amd64 ~ia64"
-
-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="~x86 ~ppc ~sparc ~alpha ~mips ~hppa ~amd64 ~ia64"
- ---
- > 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="~x86 ~ppc ~sparc ~alpha ~mips ~hppa ~amd64 ~ia64"
- ---
- > KEYWORDS="~x86 ~ppc ~sparc alpha ~mips ~hppa ~amd64 ~ia64"
- metalog-0.7-r2.ebuild
- < KEYWORDS="x86 ppc sparc alpha mips hppa amd64 ia64"
- ---
- > KEYWORDS="~x86 ~ppc ~sparc ~alpha ~mips ~hppa ~amd64 ~ia64"
- metalog-0.7-r3.ebuild
- < KEYWORDS="~x86 ~ppc ~sparc ~alpha ~mips ~hppa ~amd64 ~ia64"
- ---
- > 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/trunk/src/ekeyword2/ekeyword2 b/trunk/src/ekeyword2/ekeyword2
deleted file mode 100755
index ce8842d..0000000
--- a/trunk/src/ekeyword2/ekeyword2
+++ /dev/null
@@ -1,96 +0,0 @@
-#!/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/trunk/src/epkgmove/AUTHORS b/trunk/src/epkgmove/AUTHORS
deleted file mode 100644
index 38fdca1..0000000
--- a/trunk/src/epkgmove/AUTHORS
+++ /dev/null
@@ -1,2 +0,0 @@
-Maintainer:
-Ian Leitch <port001@gentoo.org>
diff --git a/trunk/src/epkgmove/ChangeLog b/trunk/src/epkgmove/ChangeLog
deleted file mode 100644
index 6bfb8d7..0000000
--- a/trunk/src/epkgmove/ChangeLog
+++ /dev/null
@@ -1,20 +0,0 @@
-2004-02-03 Karl Trygve Kalleberg <karltk@gentoo.org>
- * Updated epkgmove to 1.3.1, as availble on
- http://dev.gentoo.org/~port001/DevTools/epkgmove/epkgmove-1.3.1.py
-
-2004-09-27 Karl Trygve Kalleberg <karltk@gentoo.org>
- * Updated epkgmove to 1.1, as availble on
- http://dev.gentoo.org/~port001/DevTools/epkgmove/epkgmove-1.1.py
-
-2004-09-10 Karl Trygve Kalleberg <karltk@gentoo.org>
- * Updated epkgmove to 1.0, as availble on
- http://dev.gentoo.org/~port001/DevTools/epkgmove/epkgmove-1.0.py
-
-2004-07-21 Karl Trygve Kalleberg <karltk@gentoo.org>
- * Updated epkgmove to 0.5, as availble on
- http://dev.gentoo.org/~port001/DevTools/epkgmove/epkgmove-0.5.py
-
-2004-04-02 Karl Trygve Kalleberg <karltk@gentoo.org>
- * Updated epkgmove to 0.4, as availble on
- http://dev.gentoo.org/~port001/DevTools/epkgmove/epkgmove-0.4.py
-
diff --git a/trunk/src/epkgmove/Makefile b/trunk/src/epkgmove/Makefile
deleted file mode 100644
index ce9b950..0000000
--- a/trunk/src/epkgmove/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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/epkgmove/
- cp Makefile AUTHORS README TODO ChangeLog epkgmove ../../$(distdir)/src/epkgmove/
-
-install: all
- install -m 0755 epkgmove $(bindir)/
- install -d $(docdir)/epkgmove
- install -m 0644 AUTHORS README TODO ChangeLog $(docdir)/epkgmove/
-# install -m 0644 epkgmove.1 $(mandir)/
diff --git a/trunk/src/epkgmove/README b/trunk/src/epkgmove/README
deleted file mode 100644
index 4668fa3..0000000
--- a/trunk/src/epkgmove/README
+++ /dev/null
@@ -1,16 +0,0 @@
-
-Package : epkgmove
-Version : 0.5
-Author : See AUTHORS
-
-MOTIVATION
-
-Eases moving around ebuilds in the Portage CVS tree.
-
-MECHANICS
-
-N/A
-
-IMPROVEMENTS
-
-N/A
diff --git a/trunk/src/epkgmove/TODO b/trunk/src/epkgmove/TODO
deleted file mode 100644
index e69de29..0000000
--- a/trunk/src/epkgmove/TODO
+++ /dev/null
diff --git a/trunk/src/epkgmove/epkgmove b/trunk/src/epkgmove/epkgmove
deleted file mode 100644
index 42b6e7d..0000000
--- a/trunk/src/epkgmove/epkgmove
+++ /dev/null
@@ -1,895 +0,0 @@
-#!/usr/bin/python -O
-# Copyright 2004 Ian Leitch
-# Copyright 1999-2004 Gentoo Foundation
-# $Header$
-#
-# Author:
-# Ian Leitch <port001@gentoo.org>
-#
-
-import os
-import re
-import sys
-import signal
-import commands
-from time import sleep
-from random import randint
-from optparse import OptionParser
-
-import portage
-try:
- from portage.output import *
-except ImportError:
- from output import *
-
-__author__ = "Ian Leitch"
-__email__ = "port001@gentoo.org"
-__productname__ = "epkgmove"
-__version__ = "1.3.1 - \"Moving Fusion + Bandages + Plasters\""
-__description__ = "A tool for moving and renaming packages in CVS"
-
-def print_usage():
-
- print
- print "%s %s [ %s ] [ %s ] [ %s ]" % (white("Usage:"), turquoise(__productname__), green("option"), green("origin"), green("destination"))
- print " '%s' and '%s' are expected as a full package name, e.g. net-im/gaim" % (green("origin"), green("destination"))
- print " See %s --help for a list of options" % __productname__
- print
-
-def check_cwd(portdir):
-
- if os.getcwd() != portdir:
- print
- print "%s Not in PORTDIR!" % yellow(" *")
- print "%s Setting to: %s" % (yellow(" *"), os.getcwd())
- os.environ["PORTDIR"]=os.getcwd()
- return os.getcwd()
-
- return portdir
-
-def check_args(args, portdir, options, cvscmd):
-
- booboo = False
- re_expr = "^[\da-zA-Z-]{,}/[\d\w0-9-]{,}$"
- o_re_expr = re.compile(re_expr)
-
- if len(args) == 0:
- print "\n%s ERROR: errr, didn't you forget something" % red("!!!"),
- count = range(3)
- for second in count:
- sys.stdout.write(".")
- sys.stdout.flush()
- sleep(1)
- sys.stdout.write("?")
- sys.stdout.flush()
- sleep(1)
- print "\n\n%s %s hits you with a clue stick %s" % (green(" *"), __productname__, green("*"))
- sleep(1)
- print_usage()
- sys.exit(1)
-
- if options.remove:
- if len(args) > 1:
- error("Please remove packages one at a time")
- sys.exit(1)
- elif not o_re_expr.match(args[0].rstrip("/")):
- error("Expected full package name as argument")
- sys.exit(1)
- elif not os.path.exists(os.path.join(portdir, args[0].rstrip("/"))):
- error("No such package '%s'" % args[0].rstrip("/"))
- sys.exit(1)
- else:
- if not options.cvs_up:
- update_categories(portdir, args, cvscmd["update"])
- return (args[0].rstrip("/"), None)
-
- if len(args) == 2:
- if not o_re_expr.match(args[0].rstrip("/")):
- error("Expected full package name as origin argument")
- booboo = True
- elif not o_re_expr.match(args[1].rstrip("/")):
- error("Expected full package name as destination argument")
- booboo = True
-
- if booboo == True:
- sys.exit(1)
- else:
- error("Expected two arguments as input.")
- print_usage()
- sys.exit(1)
-
- if not options.cvs_up:
- update_categories(portdir, args, cvscmd["update"])
-
- if not os.path.exists(os.path.join(portdir, args[0].rstrip("/"))):
- error("No such package '%s'" % args[0].rstrip("/"))
- booboo = True
- elif os.path.exists(os.path.join(portdir, args[1].rstrip("/"))):
- error("Package '%s' already exists" % args[1].rstrip("/"))
- booboo = True
-
- if booboo == True:
- sys.exit(1)
-
- return (args[0].rstrip("/"), args[1].rstrip("/"))
-
-def check_repos(portdir):
-
- files = os.listdir(portdir)
-
- for file in files:
- if not os.path.isdir(file):
- files.remove(file)
-
- if "CVS" not in files:
- error("Current directory doesn't look like a CVS repository")
- sys.exit(1)
-
-def check_commit_queue():
-
- empty = True
-
- print
- print "%s Checking commit queue for outstanding changes..." % green(" *")
- print "%s Note: This may take a VERY long time" % yellow(" *")
- print
-
- output = commands.getoutput("cvs diff")
-
- for line in output.split("\n"):
- if not line.startswith("?"):
- empty = False
- break
-
- if empty == False:
- error("Commit queue not empty! Please commit all outstanding changes before using %s." % __productname__)
- sys.exit(1)
-
-def update_categories(portdir, catpkgs, cvsupcmd):
-
- my_catpkgs = []
-
- print
- print "%s Updating categories: " % green(" *")
-
- if len(catpkgs) >= 2:
- if catpkgs[0].split("/", 1)[0] == catpkgs[1].split("/", 1)[0]:
- my_catpkgs.append(catpkgs[0])
- else:
- my_catpkgs.append(catpkgs[0])
- my_catpkgs.append(catpkgs[1])
- else:
- my_catpkgs.append(catpkgs[0])
-
- for catpkg in my_catpkgs:
- (category, package) = catpkg.split("/", 1)
- if os.path.exists(os.path.join(portdir, category)):
- os.chdir(os.path.join(portdir, category))
- print " %s %s" % (green("*"), category)
- do_cmd(cvsupcmd)
- else:
- print " %s %s" % (red("!"), category)
-
- os.chdir(portdir)
-
-def error(msg):
-
- sys.stderr.write("\n%s ERROR: %s\n" % (red("!!!"), msg))
-
-def signal_handler(signal_number=None, stack_frame=None):
-
- error("Caught SIGINT; exiting...")
- sys.exit(1)
- os.kill(0, signal.SIGKILL)
-
-def do_cmd(cmd):
-
- (status, output) = commands.getstatusoutput(cmd)
- if status != 0:
- error("Command '%s' failed with exit status %d." % (cmd, status))
- for line in output.split("\n"):
- if line != "":
- print " %s %s" % (red("!"), line)
- sys.exit(1)
-
-class CVSAbstraction:
-
- def __init__(self, portdir, oldcatpkg, newcatpkg, cvscmd, options):
-
- self._portdir = portdir
- self._cvscmd = cvscmd
- self._options = options
- self._ignore = ("CVS")
-
- self._old_category = ""
- self._old_package = ""
- self._new_category = ""
- self._new_package = ""
- self._old_catpkg = oldcatpkg
- self._new_catpkg = newcatpkg
-
- self._action = ""
-
- self._distinguish_action(oldcatpkg, newcatpkg)
-
- def _distinguish_action(self, oldcatpkg, newcatpkg):
-
- (self._old_category, self._old_package) = oldcatpkg.split("/")
- if newcatpkg:
- (self._new_category, self._new_package) = newcatpkg.split("/")
-
- if self._old_category != self._new_category and self._new_category:
- if self._old_package != self._new_package and self._new_package:
- self._action = "MOVE & RENAME"
- else:
- self._action = "MOVE"
- elif self._old_package != self._new_package and self._new_package:
- self._action = "RENAME"
- elif not self._new_package:
- self._action = "REMOVE"
- else:
- error("Unable to distingush required action.")
- sys.exit(1)
-
- def __backup(self):
-
- print "%s Backing up %s..." % (green(" *"), turquoise(self._old_catpkg))
-
- if not os.path.exists("/tmp/%s" % __productname__):
- os.mkdir("/tmp/%s" % __productname__)
-
- if os.path.exists("/tmp/%s/%s" % (__productname__, self._old_package)):
- do_cmd("rm -rf /tmp/%s/%s" % (__productname__, self._old_package))
-
- do_cmd("cp -R %s /tmp/%s/%s" % (os.path.join(self._portdir, self._old_catpkg), __productname__, self._old_package))
-
- def perform_action(self):
-
- count_down = 5
-
- print
- if self._action == "REMOVE":
- print "%s Performing a '%s' of %s..." % (green(" *"), green(self._action), turquoise(self._old_catpkg))
- else:
- print "%s Performing a '%s' of %s to %s..." % (green(" *"), green(self._action), turquoise(self._old_catpkg), yellow(self._new_catpkg))
-
- if not self._options.countdown:
- print "%s Performing in: " % green(" *"),
- count = range(count_down)
- count.reverse()
- for second in count:
- sys.stdout.write("%s " % red(str(second + 1)))
- sys.stdout.flush()
- sleep(1)
- print
-
- if not self._action == "REMOVE":
- self.__backup()
-
- if self._action == "MOVE & RENAME":
- self._perform_move_rename()
- elif self._action == "MOVE":
- self._perform_move()
- elif self._action == "RENAME":
- self._perform_rename()
- elif self._action == "REMOVE":
- self._perform_remove()
-
- def _perform_remove(self):
-
- deps = self.__get_reverse_deps()
-
- if deps:
- print "%s The following ebuild(s) depend on this package:" % red(" *")
- for dep in deps:
- print "%s %s" % (red(" !"), dep)
- if self._options.force:
- print "%s Are you sure you wish to force removal of this package?" % yellow(" *"),
- try:
- choice = raw_input("(Yes/No): ")
- except KeyboardInterrupt:
- error("Interrupted by user.")
- sys.exit(1)
- if choice.strip().lower() != "yes":
- error("Bailing on forced removal.")
- sys.exit(1)
- else:
- error("Refusing to remove from CVS, package has dependents.")
- sys.exit(1)
-
- self.__remove_old_package()
-
- def _perform_move(self):
-
- self.__add_new_package()
- self.__regen_manifest()
- self.__update_dependents(self.__get_reverse_deps())
- self.__remove_old_package()
-
- def _perform_move_rename(self):
-
- self._perform_rename()
-
- def _perform_rename(self):
-
- self.__rename_files()
- self.__add_new_package()
- self.__regen_digests()
- self.__update_dependents(self.__get_reverse_deps())
- self.__remove_old_package()
-
- def __rename_files(self):
-
- def rename_files(arg, dir, files):
-
- if os.path.basename(dir) not in self._ignore:
- if os.path.basename(dir) != self._old_package:
- for file in files:
- new_file = ""
- if file.find(self._old_package) >= 0:
- new_file = file.replace(self._old_package, self._new_package)
- do_cmd("mv %s %s" % (os.path.join(dir, file), os.path.join(dir, new_file)))
- if not os.path.isdir(os.path.join(dir, new_file)) and not file.startswith("digest-"):
- self.__rename_file_contents(os.path.join(dir, new_file))
- else:
- for file in files:
- if file.endswith(".ebuild"):
- new_file = file.replace(self._old_package, self._new_package)
- do_cmd("mv %s %s" % (os.path.join(dir, file), os.path.join(dir, new_file)))
- self.__rename_file_contents(os.path.join(dir, new_file))
- elif file.endswith(".xml"):
- self.__rename_file_contents(os.path.join(dir, file))
-
- print "%s Renaming files..." % green(" *")
- os.path.walk("/tmp/%s/%s" % (__productname__, self._old_package), rename_files , None)
- do_cmd("mv /tmp/%s/%s /tmp/%s/%s" % (__productname__, self._old_package, __productname__, self._new_package))
-
- def __regen_manifest(self, path=None, dep=False):
-
- if dep:
- print "%s Regenerating Manifest..." % green(" *")
- else:
- print "%s Regenerating Manifest..." % green(" *")
- if path:
- os.chdir(path)
- else:
- os.chdir(os.path.join(self._portdir, self._new_catpkg))
- for ebuild in os.listdir("."):
- if ebuild.endswith(".ebuild"):
- do_cmd("/usr/lib/portage/bin/ebuild %s manifest" % ebuild)
- break
-
- self.__gpg_sign(dep)
-
- def __regen_digests(self):
-
- print "%s Regenerating digests:" % green(" *")
- os.chdir(os.path.join(self._portdir, self._new_catpkg))
- for digest in os.listdir("files/"):
- if digest.startswith("digest-"):
- os.unlink("files/%s" % digest)
- for ebuild in os.listdir("."):
- if ebuild.endswith(".ebuild"):
- print " >>> %s" % ebuild
- do_cmd("/usr/lib/portage/bin/ebuild %s digest" % ebuild)
-
- self.__gpg_sign()
-
- def __gpg_sign(self, dep=False):
-
- gpg_cmd = ""
-
- os.chdir(os.path.join(self._portdir, self._new_catpkg))
-
- if "sign" in portage.features:
- if dep:
- print "%s GPG Signing Manifest..." % green(" *")
- else:
- print "%s GPG Signing Manifest..." % green(" *")
- gpg_cmd = "gpg --quiet --sign --clearsign --yes --default-key %s" % portage.settings["PORTAGE_GPG_KEY"]
- if portage.settings.has_key("PORTAGE_GPG_DIR"):
- gpg_cmd = "%s --homedir %s" % (gpg_cmd, portage.settings["PORTAGE_GPG_DIR"])
- do_cmd("%s Manifest" % gpg_cmd)
- do_cmd("mv Manifest.asc Manifest")
- do_cmd("%s 'Manifest recommit'" % self._cvscmd["commit"])
-
- def __rename_file_contents(self, file):
-
- def choice_loop(line, match_count, choice_list, type="name", replace=""):
-
- new_line = line
- accepted = False
- skipp = False
-
- while(not accepted):
- print " ",
- if len(choice_list) > 0:
- for choice in choice_list:
- print "%s: Replace with '%s'," % (white(choice), green(choice_list[choice])),
- if match_count == 0:
- print "%s: Pass, %s: Skip this file, %s: Custom" % (white(str(len(choice_list)+1)), white(str(len(choice_list)+2)), white(str(len(choice_list)+3))),
- else:
- print "%s: Pass, %s: Custom" % (white(str(len(choice_list)+1)), white(str(len(choice_list)+2))),
- try:
- input = raw_input("%s " % white(":"))
- except KeyboardInterrupt:
- print
- error("Interrupted by user.")
- sys.exit(1)
- if choice_list.has_key(input):
- if type == "name":
- new_line = new_line.replace(self._old_package, choice_list[input])
- accepted = True
- elif type == "P":
- new_line = new_line.replace("${P}", choice_list[input])
- accepted = True
- elif type == "PN":
- new_line = new_line.replace("${PN}", choice_list[input])
- accepted = True
- elif type == "PV":
- new_line = new_line.replace("${PV}", choice_list[input])
- accepted = True
- elif type == "PVR":
- new_line = new_line.replace("${PVR}", choice_list[input])
- accepted = True
- elif type == "PR":
- new_line = new_line.replace("${PR}", choice_list[input])
- accepted = True
- elif type == "PF":
- new_line = new_line.replace("${PF}", choice_list[input])
- accepted = True
- elif input == str(len(choice_list)+1):
- accepted = True
- elif input == str(len(choice_list)+2) and match_count == 0:
- accepted = True
- skipp = True
- elif input == str(len(choice_list)+3) and match_count == 0 or input == str(len(choice_list)+2) and match_count != 0:
-
- input_accepted = False
-
- while(not input_accepted):
- try:
- custom_input = raw_input(" %s Replacement string: " % green("*"))
- except KeyboardInterrupt:
- print
- error("Interrupted by user.")
- sys.exit(1)
- while(1):
- print " %s Replace '%s' with '%s'? (Y/N)" % (yellow("*"), white(replace), white(custom_input)),
- try:
- yes_no = raw_input(": ")
- except KeyboardInterrupt:
- print
- error("Interrupted by user.")
- sys.exit(1)
- if yes_no.lower() == "y":
- input_accepted = True
- break
- elif yes_no.lower() == "n":
- break
-
- new_line = new_line.replace(replace, custom_input)
- accepted = True
- else:
- accepted = False
-
- if skipp:
- break
-
- return (new_line, skipp)
-
- found = False
- contents = []
- new_contents = []
- match_count = 0
- skipp = False
-
- try:
- readfd = open(file, "r")
- contents = readfd.readlines()
- readfd.close()
- except IOError, e:
- error(e)
- sys.exit(1)
-
- for line in contents:
- if line.find(self._old_package) >= 0:
- found = True
- break
-
- if found == True:
- print "%s Editing %s:" % (green(" *"), white(file.split("/tmp/%s/%s/" % (__productname__, self._old_package))[1]))
- try:
- writefd = open(file, "w")
- except IOError, e:
- error(e)
- sys.exit(1)
- for line in contents:
- tmp_line = line
- if not line.startswith("# $Header:"):
- if line.find(self._old_package) >= 0:
- print "%s %s" % (green(" !"), line.strip().replace(self._old_package, yellow(self._old_package)))
- (tmp_line, skipp) = choice_loop(tmp_line, match_count, {"1": self._new_package,
- "2": "${PN}"}, type="name", replace=self._old_package)
- match_count += 1
- if skipp:
- break
- if line.find("${P}") >= 0:
- print "%s %s" % (green(" !"), line.strip().replace("${P}", yellow("${P}")))
- (pkg, version, revising) = portage.pkgsplit(os.path.split(file)[1][:-7])
- (tmp_line, skipp) = choice_loop(tmp_line, match_count, {"1": "%s-%s" % (pkg, version),
- "2": "%s-%s" % (self._old_package, version)}, type="P", replace="${P}")
- match_count += 1
- if skipp:
- break
- if line.find("${PN}") >= 0:
- print "%s %s" % (green(" !"), line.strip().replace("${PN}", yellow("${PN}")))
- (tmp_line, skipp) = choice_loop(tmp_line, match_count, {"1": self._new_package,
- "2": self._old_package}, type="PN", replace="${PN}")
- match_count += 1
- if skipp:
- break
- if line.find("${PV}") >= 0:
- print "%s %s" % (green(" !"), line.strip().replace("${PV}", yellow("${PV}")))
- (pkg, version, revision) = portage.pkgsplit(os.path.split(file)[1][:-7])
- (tmp_line, skipp) = choice_loop(tmp_line, match_count, {"1": version}, type="PV", replace="${PV}")
- match_count += 1
- if skipp:
- break
- if line.find("${PVR}") >= 0:
- print "%s %s" % (green(" !"), line.strip().replace("${PVR}", yellow("${PVR}")))
- (pkg, version, revision) = portage.pkgsplit(os.path.split(file)[1][:-7])
- (tmp_line, skipp) = choice_loop(tmp_line, match_count, {"1": "%s-%s" % (version, revision)}, type="PVR", replace="${PVR}")
- match_count += 1
- if skipp:
- break
- if line.find("${PR}") >= 0:
- print "%s %s" % (green(" !"), line.strip().replace("${PR}", yellow("${PR}")))
- (pkg, version, revision) = portage.pkgsplit(os.path.split(file)[1][:-7])
- (tmp_line, skipp) = choice_loop(tmp_line, match_count, {"1": revision}, type="PR", replace="${PR}")
- match_count += 1
- if skipp:
- break
- if line.find("${PF}") >= 0:
- print "%s %s" % (green(" !"), line.strip().replace("${PF}", yellow("${PF}")))
- (pkg, version, revision) = portage.pkgsplit(os.path.split(file)[1][:-7])
- (tmp_line, skipp) = choice_loop(tmp_line, match_count, {"1": "%s-%s-%s" % (pkg, version, revision),
- "2": "%s-%s-%s" % (self._old_package, version, revision)}, type="PF", replace="${PF}")
- match_count += 1
- if skipp:
- break
- if line.find("${P/") >= 0:
- start = line.find("${P/")
- i = 0
- hi_str = ""
- while(line[start + (i - 1)] != "}"):
- hi_str += line[start + i]
- i += 1
- print "%s %s" % (green(" !"), line.strip().replace(hi_str, red(hi_str)))
- (tmp_line, skipp) = choice_loop(tmp_line, match_count, {}, type=None, replace=hi_str)
- match_count += 1
- if skipp:
- break
- if line.find("${PN/") >= 0:
- start = line.find("${PN/")
- i = 0
- hi_str = ""
- while(line[start + (i - 1)] != "}"):
- hi_str += line[start + i]
- i += 1
- print "%s %s" % (green(" !"), line.strip().replace(hi_str, red(hi_str)))
- (tmp_line, skipp) = choice_loop(tmp_line, match_count, {}, type=None, replace=hi_str)
- match_count += 1
- if skipp:
- break
- if line.find("${PV/") >= 0:
- start = line.find("${PV/")
- i = 0
- hi_str = ""
- while(line[start + (i - 1)] != "}"):
- hi_str += line[start + i]
- i += 1
- print "%s %s" % (green(" !"), line.strip().replace(hi_str, red(hi_str)))
- (tmp_line, skipp) = choice_loop(tmp_line, match_count, {}, type=None, replace=hi_str)
- match_count += 1
- if skipp:
- break
- if line.find("${PVR/") >= 0:
- start = line.find("${PVR/")
- i = 0
- hi_str = ""
- while(line[start + (i - 1)] != "}"):
- hi_str += line[start + i]
- i += 1
- print "%s %s" % (green(" !"), line.strip().replace(hi_str, red(hi_str)))
- (tmp_line, skipp) = choice_loop(tmp_line, match_count, {}, type=None, replace=hi_str)
- match_count += 1
- if skipp:
- break
- if line.find("${PR/") >= 0:
- start = line.find("${PR/")
- i = 0
- hi_str = ""
- while(line[start + (i - 1)] != "}"):
- hi_str += line[start + i]
- i += 1
- print "%s %s" % (green(" !"), line.strip().replace(hi_str, red(hi_str)))
- (tmp_line, skipp) = choice_loop(tmp_line, match_count, {}, type=None, replace=hi_str)
- match_count += 1
- if skipp:
- break
- if line.find("${PF/") >= 0:
- start = line.find("${PF/")
- i = 0
- hi_str = ""
- while(line[start + (i - 1)] != "}"):
- hi_str += line[start + i]
- i += 1
- print "%s %s" % (green(" !"), line.strip().replace(hi_str, red(hi_str)))
- (tmp_line, skipp) = choice_loop(tmp_line, match_count, {}, type=None, replace=hi_str)
- match_count += 1
- if skipp:
- break
-
- new_contents.append(tmp_line)
-
- if not skipp:
- for line in new_contents:
- writefd.write(line)
- else:
- for line in contents:
- writefd.write(line)
-
- writefd.close()
-
- def __update_dependents(self, dep_list):
-
- if len(dep_list) <= 0:
- return
-
- print "%s Updating dependents:" % green(" *")
- os.chdir(self._portdir)
-
- for dep in dep_list:
- print " >>> %s" % dep
- new_contents = []
- (category, pkg) = dep.split("/")
- pkg_split = portage.pkgsplit(pkg)
- os.chdir(self._portdir)
- do_cmd("%s %s" % (self._cvscmd["update"], os.path.join(category, pkg_split[0])))
-
- try:
- readfd = open(os.path.join(self._portdir, category, pkg_split[0], "%s.ebuild" % pkg), "r")
- contents = readfd.readlines()
- readfd.close()
- except IOError, e:
- error(e)
- sys.exit(1)
-
- for line in contents:
- if self._old_catpkg in line:
- new_contents.append(line.replace(self._old_catpkg, self._new_catpkg))
- else:
- new_contents.append(line)
-
- try:
- writefd = open(os.path.join(self._portdir, category, pkg_split[0], "%s.ebuild" % pkg), "w")
- writefd.write("".join(new_contents))
- writefd.close()
- except IOError, e:
- error(e)
- sys.exit(1)
-
- os.chdir(os.path.join(self._portdir, category, pkg_split[0]))
- do_cmd("echangelog 'Dependency update: %s -> %s.'" % (self._old_catpkg, self._new_catpkg))
- do_cmd("%s 'Dependency update: %s -> %s.'" % (self._cvscmd["commit"], self._old_catpkg, self._new_catpkg))
- self.__regen_manifest(path=os.path.join(self._portdir, category, pkg_split[0]), dep=True)
-
- def __get_reverse_deps(self):
-
- dep_list = []
- conf_portdir = "/usr/portage"
-
- def scan_for_dep(arg, dir, files):
-
- (null, category) = os.path.split(dir)
-
- for file in files:
- if self._old_catpkg not in os.path.join(category, file):
- if not os.path.isdir(os.path.join(dir, file)):
- try:
- fd = open(os.path.join(dir, file), "r")
- contents = fd.readlines()
- fd.close()
- except IOError, e:
- error(e)
- sys.exit(1)
- if self._old_catpkg in contents[0] or self._old_catpkg in contents[1] or self._old_catpkg in contents[12]:
- dep_list.append(os.path.join(category, file))
-
- print "%s Resolving reverse dependencies..." % green(" *")
-
- try:
- fd = open("/etc/make.conf", "r")
- contents = fd.readlines()
- fd.close()
- except IOError, e:
- error(e)
- sys.exit(1)
-
- for line in contents:
- if line.startswith("PORTDIR="):
- (null, conf_portdir) = line.strip("\"\n").split("=")
- break
-
- os.path.walk(os.path.join(conf_portdir, "metadata/cache"), scan_for_dep, None)
-
- return dep_list
-
- def __remove_old_package(self):
-
- def remove_files(arg, dir, files):
-
- if os.path.basename(dir) not in self._ignore:
- for file in files:
- if not os.path.isdir(os.path.join(dir, file)):
- print " <<< %s" % (os.path.join(dir.strip("./"), file))
- os.unlink(os.path.join(dir, file))
- do_cmd("%s %s" % (self._cvscmd["remove"], os.path.join(dir, file)))
-
- print "%s Removing %s from CVS:" % (green(" *"), turquoise(self._old_catpkg))
- os.chdir(os.path.join(self._portdir, self._old_catpkg))
- os.path.walk('.', remove_files , None)
- os.chdir("..")
-
- print "%s Commiting changes..." % green(" *")
- if self._options.remove:
- explanation = ""
- while(1):
- print "%s Please provide an explanation for this removal:" % yellow(" *"),
- try:
- explanation = raw_input("")
- explanation = explanation.replace("'", "\\'").replace('"', '\\"')
- except KeyboardInterrupt:
- print
- error("Interrupted by user.")
- sys.exit(1)
- if explanation != "":
- break
- do_cmd("""%s "Removed from %s: %s" """ % (self._cvscmd["commit"], self._old_category, explanation))
- else:
- do_cmd("%s 'Moved to %s.'" % (self._cvscmd["commit"], self._new_catpkg))
- do_cmd("rm -rf %s" % os.path.join(self._portdir, self._old_catpkg))
-
- print "%s Checking for remnant files..." % (green(" *"))
- do_cmd(self._cvscmd["update"])
-
- if not os.path.exists(os.path.join(self._portdir, self._old_catpkg)):
- if not self._action == "REMOVE":
- print "%s %s successfully removed from CVS." % (green(" *"), turquoise(self._old_catpkg))
- else:
- error("Remnants of %s still remain in CVS." % (turquoise(self._old_catpkg)))
-
- def __add_new_package(self):
-
- def add_files(arg, dir, files):
-
- (null, null, null, dirs) = dir.split("/", 3)
-
- if os.path.basename(dir) not in self._ignore:
- os.chdir(os.path.join(self._portdir, self._new_category))
- if os.path.basename(dir) != self._new_package:
- print " >>> %s/" % dirs
- os.mkdir(dirs)
- do_cmd("%s %s" % (self._cvscmd["add"], dirs))
- for file in files:
- if not os.path.isdir(os.path.join(dir, file)):
- print " >>> %s" % os.path.join(dirs, file)
- do_cmd("cp %s %s" % (os.path.join(dir, file), dirs))
- do_cmd("%s %s" % (self._cvscmd["add"], os.path.join(dirs, file)))
-
- print "%s Adding %s to CVS:" % (green(" *"), turquoise(self._new_catpkg))
- os.chdir(os.path.join(self._portdir, self._new_category))
- print " >>> %s/" % self._new_package
- os.mkdir(self._new_package)
- do_cmd("%s %s" % (self._cvscmd["add"], self._new_package))
- os.chdir(self._new_package)
- os.path.walk("/tmp/%s/%s" % (__productname__, self._new_package), add_files , None)
- os.chdir(os.path.join(self._portdir, self._new_catpkg))
-
- print "%s Adding ChangeLog entry..." % green(" *")
- do_cmd("echangelog 'Moved from %s to %s.'" % (self._old_catpkg, self._new_catpkg))
-
- print "%s Commiting changes..." % green(" *")
- do_cmd("%s 'Moved from %s to %s.'" % (self._cvscmd["commit"], self._old_catpkg, self._new_catpkg))
-
- print "%s %s successfully added to CVS." % (green(" *"), turquoise(self._new_catpkg))
-
- def log_move(self):
-
- if not self._action == "REMOVE":
-
- update_files = []
- update_regex = "^[\d]Q-[\d]{4}$"
-
- p_file_regex = re.compile(update_regex)
-
- print "%s Logging move:" % (green(" *"))
- os.chdir(os.path.join(self._portdir, "profiles/updates"))
- do_cmd(self._cvscmd["update"])
-
- for file in os.listdir("."):
- o_file_regex = p_file_regex.match(file)
- if file not in self._ignore and o_file_regex:
- (q, y) = file.split("-")
- update_files.append("%s-%s" % (y, q))
-
- update_files.sort()
- (y, q) = update_files[-1].split("-")
- upfile = "%s-%s" % (q, y)
- print " >>> %s" % upfile
-
- try:
- fd = open(upfile, "a")
- fd.write("move %s %s\n" % (self._old_catpkg, self._new_catpkg))
- fd.close()
- except IOError, e:
- error(e)
- sys.exit(1)
-
- do_cmd("%s 'Moved %s to %s'" % (self._cvscmd["commit"], self._old_catpkg, self._new_catpkg))
- os.chdir(self._portdir)
-
- def clean_up(self):
-
- if not self._action == "REMOVE":
- print "%s Removing back-up..." % (green(" *"))
- do_cmd("rm -rf /tmp/%s/%s" % (__productname__, self._old_package))
- if len(os.listdir("/tmp/%s" % __productname__)) == 0:
- do_cmd("rmdir /tmp/%s" % __productname__)
-
- os.chdir(self._portdir)
-
-if __name__ == "__main__":
-
- signal.signal(signal.SIGINT, signal_handler)
-
- cvscmd = {"remove": "cvs -Qf rm",
- "commit": "cvs -Qf commit -m",
- "update": "cvs -Qf up -dPC",
- "add": "cvs -Qf add"}
-
- parser = OptionParser(usage="%prog [ option ] [ origin ] [ destination ]", version="%s-%s" % (__productname__, __version__))
- parser.add_option("--usage", action="store_true", dest="usage", default=False, help="Pint usage information")
- parser.add_option("-q", "--queue-check", action="store_true", dest="commit_queue", default=False, help="Check the cvs tree for files awaiting commit")
- parser.add_option("-u", "--no-cvs-up", action="store_true", dest="cvs_up", default=False, help="Skip running cvs up in the origin and destination categories")
- parser.add_option("-c", "--no-countdown", action="store_true", dest="countdown", default=False, help="Skip countdown before performing")
- parser.add_option("-R", "--remove", action="store_true", dest="remove", default=False, help="Remove package")
- parser.add_option("-F", "--force", action="store_true", dest="force", default=False, help="Force removal of package, ignoring any reverse deps")
- (options, args) = parser.parse_args()
-
- if options.usage:
- print_usage()
- sys.exit(0)
-
- if randint(1, 100) == 50:
- print "%s I put on my robe and wizard hat..." % green(" *")
-
- portdir = check_cwd(portage.settings["PORTDIR"].rstrip("/"))
- check_repos(portdir)
- (oldcatpkg, newcatpkg) = check_args(args, portdir, options, cvscmd)
-
- if options.commit_queue:
- check_commit_queue()
-
- ThisPackage = CVSAbstraction(portdir, oldcatpkg, newcatpkg, cvscmd, options)
-
- ThisPackage.perform_action()
- ThisPackage.log_move()
- ThisPackage.clean_up()
-
- if options.remove:
- print "%s %s successfully removed from CVS." % (green(" *"), turquoise(oldcatpkg))
- else:
- print "%s %s successfully moved to %s." % (green(" *"), turquoise(oldcatpkg), yellow(newcatpkg))
-
diff --git a/trunk/src/etc-update/AUTHORS b/trunk/src/etc-update/AUTHORS
deleted file mode 100644
index e69de29..0000000
--- a/trunk/src/etc-update/AUTHORS
+++ /dev/null
diff --git a/trunk/src/etc-update/ChangeLog b/trunk/src/etc-update/ChangeLog
deleted file mode 100644
index e69de29..0000000
--- a/trunk/src/etc-update/ChangeLog
+++ /dev/null
diff --git a/trunk/src/etc-update/Makefile b/trunk/src/etc-update/Makefile
deleted file mode 100644
index 95838ad..0000000
--- a/trunk/src/etc-update/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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:
- echo "PAPPLE (vb.) To do what babies do to soup with their spoons."
-
-dist:
- mkdir -p ../../$(distdir)/src/etc-update
- cp Makefile AUTHORS README TODO ChangeLog etc-update etc-update.1 ../../$(distdir)/src/etc-update/
-
-install:
- install -m 0755 etc-update $(bindir)/
- install -d $(docdir)/etc-update
- install -m 0644 AUTHORS ChangeLog README $(docdir)/etc-update/
- install -m 0644 etc-update.1 $(mandir)/
diff --git a/trunk/src/etc-update/README b/trunk/src/etc-update/README
deleted file mode 100644
index e69de29..0000000
--- a/trunk/src/etc-update/README
+++ /dev/null
diff --git a/trunk/src/etc-update/etc-update b/trunk/src/etc-update/etc-update
deleted file mode 100755
index f566dff..0000000
--- a/trunk/src/etc-update/etc-update
+++ /dev/null
@@ -1,165 +0,0 @@
-#! /usr/bin/python
-#
-# $Header$
-#
-# Distributed under the terms of the GNU General Public License v2
-# Copyright (c) 2003 Karl Trygve Kalleberg
-#
-# Based on previous versions, by
-# - Brandon Low <lostlogic@gentoo.org>
-# - Jochem Kossen <j.kossen@home.nl>
-# - Leo Lipelis <aeoo@gentoo.org>
-
-from dialog import Dialog
-import portage
-import time
-import re
-import os
-
-__author__ = "Karl Trygve Kalleberg"
-__email__ = "karltk@gentoo.org"
-__version__ = "0.2.0"
-__productname__ = "etc-update"
-__description__ = "Interactive config file updater"
-
-globals = portage.settings.configdict["globals"]
-
-for i in globals["CONFIG_PROTECT"].split():
- print i
-
-# list all files in all CONFIG_PROTECT dirs
-# list them in the gui
-# one-by-one:
-# - is update to header only?
-# - is the original unmodified from the previous package? (not checkable - duh!)
-# -
-
-class Config:
- pass
-
-def loadConfig():
- cfg = Config()
- globals = portage.settings.configdict["globals"]
- cfg.config_protect = globals["CONFIG_PROTECT"].split()
- return cfg
-
-def _recurseFiles(path):
- files = []
- if os.path.exists(path):
- try:
- tmpfiles = os.listdir(path)
- for i in tmpfiles:
- fn = path + "/" + i
- if os.path.isdir(fn):
- files += _recurseFiles(fn)
- elif os.path.isfile(fn):
- m = re.search("\._cfg...._",fn)
- if m:
- files.append(fn)
- else:
- print "What is this anyway?:", fn
- except OSError:
- pass
- # print "Access denied:", path
-
- return files
-
-def findAllFiles(dlg, config):
- files = []
- gauge = dlg.gauge(0,
- "Processing CONFIG_PROTECT directories...",
- 7,
- 60,
- "Gauge",
- sleep=3)
- num_dirs = len(config.config_protect)
- for i in xrange(num_dirs):
- rem = repr(num_dirs - i / num_dirs)
- gauge.update(rem, "Directories remaining: %s" % rem)
- files += _recurseFiles(config.config_protect[i])
- return files
-
-def prettifyFiles(files):
- rx = re.compile("\._cfg...._")
- def strip_cfg(x):
- """Remove ._cfg????_ part """
- m = rx.search(x)
- if m:
- s,e = m.span(0)
- return x[:s] + x[e:]
- return x
- return map(strip_cfg, files)
-
-def updateFile(dlg, original):
-
- # Find candidates
-
- dir = os.path.dirname(original)
- filename = os.path.basename(original)
- rx = re.compile("\._cfg...._" + filename)
- cand = filter(lambda x: rx.search(x), os.listdir(dir))
-
- if len(cand) > 1:
-
- # Add mtimes
- for i in xrange(len(cand)):
- stamp = time.localtime(os.path.getmtime(dir + "/" + cand[i]))
- tstr = time.strftime("%a, %d %b %Y %H:%M:%S", stamp)
- cand[i] = cand[i] + " - " + tstr
-
-
- # Show selection
- replacement = dlg.menu("Files that need updating",
- Dialog.AUTO_SIZE,
- list = cand,
- showHelp = False,
- title="Checklist")
-
- else:
- replacement = cand[0]
-
-
- # Display diff
-
- dlg.yesno("Would you like to update \n" + \
- "[" + original + "]with\n[" + dir + "/" + replacement + "] ?")
-
-def displayFiles(dlg, config, files):
-
- pretty_files = prettifyFiles(files)
-
- while 1:
- result = dlg.menu("Files that need updating",
- Dialog.AUTO_SIZE,
- list = pretty_files,
- showHelp = False,
- title="Checklist")
- if result == None:
- if dlg.ERR_CANCEL:
- break
-
- updateFile(dlg, result)
-
- if len(pretty_files):
- print "!!! Warning: There are still files that require updating."
-
-
-def main():
- dlg = Dialog("etc-update")
-# dlg = None
-
- config = loadConfig()
- files = findAllFiles(dlg, config)
- displayFiles(dlg, config,files)
-
-
-if __name__ == "__main__":
- try:
- main()
- except KeyboardInterrupt:
- print "Operation aborted!"
-
-# TODO:
-# - option for automatically update untouched files
-# - show coloured diff
-# - proper progress bar
diff --git a/trunk/src/etc-update/etc-update.1 b/trunk/src/etc-update/etc-update.1
deleted file mode 100644
index 53477d8..0000000
--- a/trunk/src/etc-update/etc-update.1
+++ /dev/null
@@ -1,12 +0,0 @@
-.TH etc-update "1" "Nov 2003" "gentoolkit"
-.SH NAME
-etc-update \- Gentoo: Configuration Update Utility
-.SH SYNOPSIS
-.B etc-update
-.SH BUGS
-This tool does not yet have a man page. Feel free to submit a bug about it to
-http://bugs.gentoo.org
-.SH AUTHORS
-This informative man page was written by Karl Trygve Kalleberg
-<karltk@gentoo.org>.
-
diff --git a/trunk/src/etcat/AUTHORS b/trunk/src/etcat/AUTHORS
deleted file mode 100644
index 5da0b07..0000000
--- a/trunk/src/etcat/AUTHORS
+++ /dev/null
@@ -1,5 +0,0 @@
-Maintainer:
-Karl Trygve Kalleberg <karltk@gentoo.org>
-
-Authors:
-Alastair Tse <liquidx@gentoo.org> (original author)
diff --git a/trunk/src/etcat/ChangeLog b/trunk/src/etcat/ChangeLog
deleted file mode 100644
index bdadcb6..0000000
--- a/trunk/src/etcat/ChangeLog
+++ /dev/null
@@ -1,36 +0,0 @@
-2004-04-20 Marius Mauch <genone@gentoo.org>
- - fixing -u behavior so it matches equery (bug #47690)
-
-2004-03-13 Marius Mauch <genone@gentoo.org>
- - grouping version in --version output
-
-2004-01-23 Marius Mauch <genone@gentoo.org>
- - now catches exceptions thrown by portage
- - minor bugfixes
-
-2004-01-07 Karl Trygve Kalleberg <karltk@gentoo.org>
- * Added man page from app-portage/gentoolkit
- * Added Makefile
- * Added sys.path workaround for Portage >=2.0.50
-
-* etcat-0.2.0 (06 May 2003)
- 06 May 2003; Alastair Tse <liquidx@gentoo.org>
- Trying to add a dependency graph feature. kind of works with
- some weird hacks parsing the depenency string. probably needs
- to use functions in portage to parse it properly.
-
-* etcat-0.1.4 (27 Apr 2003)
-
- 27 Apr 2003; Alastair Tse <liquidx@gentoo.org>
- Added "files", "belongs", "depends" functions.
-
-*etcat-0.1.3 (24 Apr 2003)
-
- 24 Apr 2003; Alastair Tse <liquidx@gentoo.org>
- Fixed bug if ebuild doesn't exist. Added manpage.
-
-*etcat-0.1.2 (29 Mar 2003)
-
- 29 Mar 2003; Alastair Tse <liquidx@gentoo.org>
- Initial commit to gentoolkit. Check source for previous changes
-
diff --git a/trunk/src/etcat/Makefile b/trunk/src/etcat/Makefile
deleted file mode 100644
index 2281646..0000000
--- a/trunk/src/etcat/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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/etcat
- cp Makefile AUTHORS README TODO ChangeLog etcat etcat.1 ../../$(distdir)/src/etcat
-
-install:
- install -d $(docdir)/deprecated/etcat
- install -m 0755 etcat $(docdir)/deprecated/etcat/
- install -m 0644 etcat.1 README AUTHORS $(docdir)/deprecated/etcat/
diff --git a/trunk/src/etcat/README b/trunk/src/etcat/README
deleted file mode 100644
index 50bd2f3..0000000
--- a/trunk/src/etcat/README
+++ /dev/null
@@ -1,2 +0,0 @@
-For more information, this tool was originally hosted on:
-http://www.liquidx.net/projects/etcat/
diff --git a/trunk/src/etcat/TODO b/trunk/src/etcat/TODO
deleted file mode 100644
index e69de29..0000000
--- a/trunk/src/etcat/TODO
+++ /dev/null
diff --git a/trunk/src/etcat/etcat b/trunk/src/etcat/etcat
deleted file mode 100755
index 5137683..0000000
--- a/trunk/src/etcat/etcat
+++ /dev/null
@@ -1,688 +0,0 @@
-#!/usr/bin/env python2
-#
-# -*- mode: python; -*-
-#
-# --| Version Information |------------------------------------------
-#
-# etcat v0.1.4 (27 Apr 2003)
-#
-# $Header$
-#
-# --| About |--------------------------------------------------------
-#
-# etcat is a Portage/Ebuild Information Extractor. Basically, it
-# provides higher level convienence functions to the Portage system
-# used by Gentoo Linux.
-#
-# You can use it to quickly find out the recent changes of your
-# favourite package, the size of installed packages, the
-# available versions for a package and more.
-#
-# --| License |------------------------------------------------------
-#
-# Distributed under the terms of the GNU General Public License v2
-# Copyright (c) 2002 Alastair Tse.
-#
-# --| Usage |--------------------------------------------------------
-#
-# etcat [options] <command> <package[-ver]|ebuild|category/package[-ver]>
-#
-# -b/belongs ) checks what package(s) a file belongs to
-# -c/changes ) list the more recent changelog entry
-# -d/depends ) list all those that have this in their depends
-# -f/files ) list all files that belong to this package
-# -g/graph ) graph dependencies
-# -s/size ) guesses the size of a installed packaged.
-# -u/uses ) list all the use variables used in this package/ebuild
-# -v/versions ) list all the versions available for a package
-#
-# --| TODO |---------------------------------------------------------
-#
-# - in ver_cmp: 1.2.10a < 1.2.10, need to fix that
-#
-# --| Changes |------------------------------------------------------
-#
-# * etcat-0.3.1 (10 Oct 2004) [karltk]
-# - Fixed changes help examples
-# * etcat-0.3.1 (08 Jan 2004) [genone]
-# - adding missing python searchpath modification
-# - fixing sort order
-# * etcat-0.3.0 (12 Jul 2003) [karltk]
-# - Refactored interesting stuff into the Gentoolkit module
-# * etcat-0.2.0 (13 Jun 2003)
-# - Updated "versions" with PORTAGE_OVERLAY detection
-# - Added "graph" feature
-# * etcat-0.1.5 (30 Apr 2003)
-# - Fixed disappearing short opts. Oops.
-# * etcat-0.1.4 (27 Apr 2003)
-# - Cleaned up command execution code to provide a single place
-# to specify functions
-# - Added own custom wrapping print code.
-# - Added "files" feature
-# - Added "depends" feature
-# * etcat-0.1.3 (24 Apr 2003)
-# - Overhaul of commandline interpreter
-# - Added "belongs" feature
-# - Reimplemented "uses" to deal with IUSE more cleanly
-# and sources use.local.desc
-# - Natural Order Listings for version
-# * etcat-0.1.2 (29 Mar 2003)
-# - Added unstable indicator to complement masked
-# - improved use flag listing
-# * etcat-0.1.1 (21 Jan 2003)
-# - Add package to versions listing even if it's not in
-# the portage anymore (21 Jan 2003)
-# - Fixed old ehack references (17 Jan 2003)
-# * etcat-0.1 (31 Oct 2002)
-# Initial Release;
-#
-# -------------------------------------------------------------------
-
-
-
-import os
-import sys
-import re
-import pprint
-import getopt
-import glob
-
-# portage and gentoolkit need special path modifications
-sys.path.insert(0, "/usr/lib/portage/pym")
-sys.path.insert(0, "/usr/lib/gentoolkit/pym")
-
-import gentoolkit
-from stat import *
-try:
- from portage.output import *
-except ImportError:
- from output import *
-
-__author__ = "Alastair Tse"
-__email__ = "liquidx@gentoo.org"
-__version__ = "0.3.1"
-__productname__ = "etcat"
-__description__ = "Portage Information Extractor"
-
-# .-------------------------------------------------------.
-# | Initialise Colour Settings |
-# `-------------------------------------------------------'
-if (not sys.stdout.isatty()) or (gentoolkit.settings["NOCOLOR"] in ["yes","true"]):
- nocolor()
-
-# "option": ("shortcommand","desc",["example one", "example two"])
-options = {
-"belongs": \
-("b","Searches for a package that owns a specified file with an option to restrict the search space.",
-["etcat belongs /usr/bin/gimp media-gfx",
- "etcat belongs /usr/lib/libjpeg.so media-*",
- "etcat belongs /usr/lib/libmpeg.so"]),
-"changes": \
-("c","Outputs the changelog entry to screen. It is possible to give a version number along with the package name.",
-["etcat changes mozilla",
- "etcat changes =mozilla-1.1-r1",
- "etcat changes gkrellm$"]),
-"depends": \
-("d","Finds all packages that are directly dependent to a regex search string.",
-["etcat depends 'gnome-base/libgnome'",
- "etcat depends '>=dev-lang/python-2.2'"]),
-"files": \
-("f","Lists files that belongs to a package and optionally with version.",[]),
-"graph": \
-("g","Graphs Dependencies (NON WORKING)",[]),
-"size": \
-("s","Lists the installed size of a package.",[]),
-"uses": \
-("u", "Advanced output of USE vars in a package. Tells you flags used by a package at time of installation, flags in current config and flag description.",[]),
-"versions": \
-("v","Displays the versions available for a specific package. Colour coded to indicate installation status and displays slot information.",
-[turquoise("(I)") + "nstalled",
- yellow("(~)") + "Unstable Testing Branch",
- red("(M)") + "asked Package"])
-}
-
-# .-------------------------------------------------------.
-# | Small Wrapping Printer with Indent Support |
-# `-------------------------------------------------------'
-
-def wrap_print(string, indent=0, width=74):
- line_len = width - indent
- str_len = len(string)
- lines = []
-
- pos = 0
- thisline = ""
- while pos < str_len:
- # if we still have space stuff the
- # character in this line
- if len(thisline) < line_len-1:
- thisline += string[pos]
- pos += 1
- # if we're at the end of the line,
- # check if we should hyphenate or
- # append
- elif len(thisline) == line_len -1:
- # end of a text
- if pos == str_len -1:
- thisline += string[pos]
- pos += 1
- # end of a word
- elif string[pos] != " " and string[pos+1] == " ":
- thisline += string[pos]
- pos += 1
- # just a space
- elif string[pos] == " ":
- thisline += string[pos]
- pos += 1
- # start of a word, we start the word on the next line
- elif pos>0 and string[pos-1] == " ":
- thisline += " "
- # needs hyphenating
- else:
- thisline += "-"
-
- # append the line
- lines.append(thisline)
- thisline = ""
-
- # append last line
- if thisline:
- lines.append(thisline)
-
- for line in lines:
- print " "*indent + line
-
-# +-------------------------------------------------------+
-# | Pretty Print Log |
-# +-------------------------------------------------------+
-# | Extracts and prints out the log entry corresponding |
-# | to a certain revision if given. If not supplied, |
-# | prints out the latest/topmost entry |
-# `-------------------------------------------------------'
-
-# output the latest entry in changelog
-def output_log(lines, package_ver=""):
- # using simple rules that all changelog entries have a "*"
- # as the first char
- is_log = 0
- is_printed = 0
-
- for line in lines:
- if package_ver:
- start_entry = re.search("^[\s]*\*[\s]*(" + package_ver + ")[\s]+.*(\(.*\))",line)
- else:
- start_entry = re.search("^[\s]*\*[\s]*(.*)[\s]+.*(\(.*\))",line)
- if not is_log and start_entry:
- is_printed = 1
- is_log = 1
- print green("*") + " " + white(start_entry.group(1)) + " " + turquoise(start_entry.group(2)) + " :"
- elif is_log and re.search("^[\s]*\*[\s]*(.*)[\s]+.*(\(.*\))",line):
- break
- elif is_log:
- print line.rstrip()
- else:
- pass
-
- return is_printed
-
-# .-------------------------------------------------------.
-# | Changes Function |
-# +-------------------------------------------------------+
-# | Print out the ChangeLog entry for package[-version] |
-# `-------------------------------------------------------'
-
-def changes(query, matches):
- if not report_matches(query,matches,installed_only=0):
- return
-
- for pkg in matches:
- changelog_file = pkg.get_package_path() + "/ChangeLog"
- if os.path.exists(changelog_file):
- output_log(open(changelog_file).readlines(), pkg.get_name()+"-"+pkg.get_version())
- else:
- print red("Error") + ": No Changelog for " + pkg.get_cpv()
-
-
-# .-------------------------------------------------------.
-# | Versions Function |
-# +-------------------------------------------------------+
-# | Prints out the available version, masked status and |
-# | installed status. |
-# `-------------------------------------------------------'
-
-def versions(query, matches):
- # this function should also report masked packages
- matches = gentoolkit.find_packages(query, masked=True)
- if not report_matches(query,matches):
- return
-
- # sorting result list
- matches = gentoolkit.sort_package_list(matches)
-
- # FIXME: old version printed result of regex search on name,
- # so "ant" would return app-emacs/semantic, etc...
-
- last_cp = ""
-
- for pkg in matches:
- new_cp = pkg.get_category()+"/"+pkg.get_name()
- if last_cp != new_cp:
- print green("*") + " " + white(new_cp) + " :"
- last_cp = new_cp
-
- state = []
- color = green
- unstable = 0
- overlay = ""
-
- # check if masked
- if pkg.is_masked():
- state.append(red("M"))
- color = red
- else:
- state.append(" ")
-
- # check if in unstable
- kwd = pkg.get_env_var("KEYWORDS")
- if "~" + gentoolkit.settings["ARCH"] in kwd.split():
- state.append(yellow("~"))
- if color != red:
- color = yellow
- unstable = 1
- else:
- state.append(" ")
-
- # check if installed
- if pkg.is_installed():
- state.append(turquoise("I"))
- color = turquoise
- else:
- state.append(" ")
-
- # check if this is a OVERLAY ebuilds
- if pkg.is_overlay():
- overlay = " OVERLAY"
-
- ver = pkg.get_version()
- slot = pkg.get_env_var("SLOT")
- print " "*8 + "[" + "".join(state) + "] " + color(ver) + " (" + color(slot) + ")" + overlay
-
-# .-------------------------------------------------------.
-# | List USE flags for a single ebuild, if it's installed |
-# +-------------------------------------------------------+
-# | Just uses the new IUSE parameter in ebuilds |
-# `-------------------------------------------------------'
-def uses(query, matches):
- useflags = gentoolkit.settings["USE"].split()
- usedesc = {}
- uselocaldesc = {}
-
- # Load global USE flag descriptions
- try:
- fd = open(gentoolkit.settings["PORTDIR"]+"/profiles/use.desc")
- usedesc = {}
- for line in fd.readlines():
- if line[0] == "#":
- continue
- fields = line.split(" - ")
- if len(fields) == 2:
- usedesc[fields[0].strip()] = fields[1].strip()
- except IOError:
- pass
-
- # Load local USE flag descriptions
- try:
- fd = open(gentoolkit.settings["PORTDIR"]+"/profiles/use.local.desc")
- for line in fd.readlines():
- if line[0] == "#":
- continue
- fields = line.split(" - ")
- if len(fields) == 2:
- catpkguse = re.search("([a-z]+-[a-z]+/.*):(.*)", fields[0])
- if catpkguse:
- if not uselocaldesc.has_key(catpkguse.group(1).strip()):
- uselocaldesc[catpkguse.group(1).strip()] = {catpkguse.group(2).strip() : fields[1].strip()}
- else:
- uselocaldesc[catpkguse.group(1).strip()][catpkguse.group(2).strip()] = fields[1].strip()
- except IOError:
- pass
-
- print "[ Colour Code : " + green("set") + " " + red("unset") + " ]"
- print "[ Legend : (U) Col 1 - Current USE flags ]"
- print "[ : (I) Col 2 - Installed With USE flags ]"
-
- if filter(gentoolkit.Package.is_installed, matches):
- only_installed = True
- else:
- only_installed = False
-
- # Iterate through matches, printing a report for each package
- for p in matches:
- if not p.is_installed() and only_installed:
- continue
-
- bestver = p.get_cpv()
- iuse = p.get_env_var("IUSE")
-
- if iuse: usevar = iuse.split()
- else: usevar = []
-
- inuse = []
- used = p.get_use_flags().split()
-
- # store (inuse, inused, flag, desc)
- output = []
-
- for u in usevar:
- inuse = 0
- inused = 0
- try:
- desc = usedesc[u]
- except KeyError:
- try:
- desc = uselocaldesc[p.get_category()+"/"+p.get_name()][u]
- except KeyError:
- desc = ""
-
- if u in p.get_settings("USE"): inuse = 1
- if u in used: inused = 1
-
- output.append((inuse, inused, u, desc))
-
- # pretty print
- if output:
- print
- print white(" U I ") + "[ Found these USE variables in : " + white(bestver) + " ]"
- maxflag_len = 0
- for inuse, inused, u, desc in output:
- if len(u) > maxflag_len:
- maxflag_len = len(u)
-
- for inuse, inused, u, desc in output:
- flag = ["-","+"]
- colour = [red, green]
- if inuse != inused:
- print yellow(" %s %s" % (flag[inuse], flag[inused])),
- else:
- print " %s %s" % (flag[inuse], flag[inused]),
-
- print colour[inuse](u.ljust(maxflag_len)),
-
- # print description
- if desc:
- print ":", desc
- else:
- print ": unknown"
- else:
- print "[ No USE flags found for :", white(p.get_cpv()), "]"
-
- return
-
-# .-------------------------------------------------------.
-# | Graphs the Dependency Tree for a package |
-# +-------------------------------------------------------+
-# | Naive graphing of dependencies
-# `-------------------------------------------------------'
-
-def graph(query, matches):
- if not report_matches(query, matches):
- return
-
- for pkg in matches:
- if not pkg.is_installed():
- continue
- rgraph(pkg)
-
-def rgraph(pkg,level=0,pkgtbl=[],suffix=""):
-
- cpv=pkg.get_cpv()
-
- print level*" " + "`-- " + cpv + suffix
- pkgtbl.append(cpv)
-
- for x in pkg.get_runtime_deps():
- suffix=""
- cpv=x[2]
- pkg=gentoolkit.find_best_match(x[0] + cpv)
- if not pkg:
- continue
- if pkg.get_cpv() in pkgtbl:
- continue
- if cpv.find("virtual")==0:
- suffix+=" (" + cpv + ")"
- if len(x[1]):
- suffix+=" [ " + "".join(x[1]) + " ]"
- pkgtbl=rgraph(pkg,level+1,pkgtbl,suffix)
- return pkgtbl
-
-# .-------------------------------------------------------.
-# | Required By Function |
-# +-------------------------------------------------------+
-# | Find what packages require a given package name |
-# `-------------------------------------------------------'
-
-def depends(query, matches):
-
- print "[ Results for search key : " + white(query) + " ]"
-
- isdepend = gentoolkit.split_package_name(query)
-
- for pkg in matches:
- if pkg.is_installed():
- deps = pkg.get_runtime_deps()
- for x in deps:
- cpvs=gentoolkit.split_package_name(x[2])
- cat_match=0
- ver_match=0
- name_match=0
- if not isdepend[0] or isdepend[0] == cpvs[0]:
- cat_match=1
- if not isdepend[2] or \
- (isdepend[2] == cpvs[2] and isdepend[3] == cpvs[3]):
- ver_match=1
- if isdepend[1] == cpvs[1]:
- name_match=1
- if cat_match and ver_match and name_match:
- print turquoise("*"), white(pkg.get_cpv()), white("[ ") + "".join(x[1]), white("]")
-
-# .-------------------------------------------------------.
-# | Belongs to which package |
-# +-------------------------------------------------------+
-# | Finds what package a file belongs to |
-# `-------------------------------------------------------'
-
-def belongs(query,matches):
-
- q = query.split()
-
- if len(q) > 1:
- item=q[0]
- cat=q[1]
- fn=lambda x: x.find(cat)==0
- else:
- item=q[0]
- cat="*"
- fn=None
- matches = gentoolkit.find_all_installed_packages(fn)
-
- print "Searching for " + item + " in " + cat + " ..."
-
- rx = re.compile(item)
-
- for pkg in matches:
- if pkg.get_contents():
- for fn in pkg.get_contents().keys():
- if rx.search(fn):
- print pkg.get_cpv()
- break # We know this pkg matches, look for any more matches
- return
-
-# .-------------------------------------------------------.
-# | Size of all packages matching query |
-# +-------------------------------------------------------+
-# | Finds the size of installed packages |
-# `-------------------------------------------------------'
-def size(query,packages):
- packages = gentoolkit.find_packages(query)
- if not report_matches(query, packages):
- return
-
- for pkg in packages:
- if not pkg.is_installed():
- continue
- x=pkg.size()
- size=x[0]
- files=x[1]
- uncounted=x[2]
- print turquoise("*") + " " + white(pkg.get_cpv())
- print " Total Files : ".rjust(25) + str(files)
- if uncounted:
- print " Inaccessible Files : ".rjust(25) + str(uncounted)
- print " Total Size : ".rjust(25) + "%.2f KB" % (size/1024.0)
-
-
-def report_matches(query, matches, installed_only=1):
- print "[ Results for search key : " + white(query) + " ]"
- print "[ Candidate applications found : " + white(str(len(matches))) + " ]"
- print
-
- if installed_only and matches:
- print " Only printing found installed programs."
- print
- elif installed_only:
- print "No packages found."
-
- if matches:
- return 1
- else:
- return 0
-
-
-# .-------------------------------------------------------.
-# | Files in a package |
-# +-------------------------------------------------------+
-# | Lists all the files in a package |
-# `-------------------------------------------------------'
-def files(query,matches):
- if not report_matches(query, matches):
- return
-
- for package in matches:
- if not package.is_installed():
- continue
- contents = package.get_contents()
-
- print yellow(" * ") + white(package.get_cpv())
- for x in contents.keys():
- t = contents[x][0]
- if t == "obj":
- print x
- elif t == "sym":
- print turquoise(x)
- elif t == "dir":
- print blue(x)
- else:
- print x
-
-# .-------------------------------------------------------.
-# | Help Function |
-# `-------------------------------------------------------'
-def ver():
- print __productname__ + " (" + __version__ + ") - " + __description__ + " - By: " + __author__
-
-def help():
- screenwidth = 74
- margin = 2
- margin_desc = 4
- margin_ex = 8
-
- ver()
- print yellow("NOTICE: ") + "This tool will be phased out at some point in"
- print " the future, please use equery instead."
- print " Bugs are still fixed, but new features won't be added."
- print
- print white("Usage: ") + turquoise(__productname__) + " [ " + green("options") + " ] [ " + turquoise("action") + " ] [ " + turquoise("package") + " ]"
- print
- print turquoise("Actions:")
- print
- for name,tup in options.items():
- print " "*margin + green(name) + " (" + green("-" + tup[0]) + " short option)"
- wrap_print(tup[1],indent=margin_desc)
- for example in tup[2]:
- print " "*margin_ex + example
- print
-
-# .-------------------------------------------------------.
-# | Main Function |
-# `-------------------------------------------------------'
-def main():
-
- action = ''
- query = ''
-
- if len(sys.argv) < 3:
- help()
- sys.exit(1)
-
- # delegates the commandline stuff to functions
- pointer = 2
- # short/long opts mapping
- shortopts = ["-"+x[0] for x in options.values()]
- short2long = {}
- for k,v in options.items():
- short2long[v[0]] = k
- longopts = options.keys()
- # loop thru arguments
- for arg in sys.argv[1:]:
- if arg[0] == "-" and len(arg) == 2 and arg in shortopts:
- action = short2long[arg[1]]
- query = ' '.join(sys.argv[pointer:])
- break
- elif arg in longopts:
- action = arg
- query = ' '.join(sys.argv[pointer:])
- break
- else:
- pointer += 1
-
- # abort if we don't have an action or query string
- if not query or action not in options.keys():
- help()
- sys.exit(1)
- else:
- try:
- matches = gentoolkit.find_packages(query)
- except KeyError, e:
- if e[0].find("Specific key requires operator") == 0:
- print red("!!!"), "Invalid syntax: missing operator"
- print red("!!!"), "If you want only specific versions please use one of"
- print red("!!!"), "the following operators as prefix for the package name:"
- print red("!!!"), " > >= = <= <"
- print red("!!!"), "Example to only match gcc versions greater or equal 3.2:"
- print red("!!!"), " >=sys-devel/gcc-3.2"
- else:
- print red("!!!"), "Internal portage error, terminating"
- if len(e[0]):
- print red("!!!"), e
- sys.exit(2)
- except ValueError, e:
- if isinstance(e[0],list):
- print red("!!!"), "Ambiguous package name \"%s\"" % query
- print red("!!!"), "Please use one of the following long names:"
- for p in e[0]:
- print red("!!!"), " "+p
- else:
- print red("!!!"), "Internal portage error, terminating"
- if len(e[0]):
- print red("!!!"), e[0]
- sys.exit(2)
- function = globals()[action]
- function(query, matches)
-
-if __name__ == "__main__":
- try:
- main()
- except KeyboardInterrupt:
- print "Operation Aborted!"
-
-
diff --git a/trunk/src/etcat/etcat.1 b/trunk/src/etcat/etcat.1
deleted file mode 100644
index 6704f3b..0000000
--- a/trunk/src/etcat/etcat.1
+++ /dev/null
@@ -1,79 +0,0 @@
-.TH "etcat" "1" "0.1.4" "Alastair Tse <liquidx@gentoo.org>" "Gentoo Administration"
-.SH "NAME"
-.LP
-etcat \- Gentoo: Portage Information Extractor
-.SH "SYNTAX"
-.LP
-etcat [\fIoption\fP|command] <\fIquery|package\fP>
-
-.SH "DESCRIPTION"
-.LP
-etcat tries to complement the existing portage related tools but geared specifically for the power user. It enables users and developers to quickly find out information on particular packages without resorting to manually poking the portage tree and portage database.
-
-.LP
-More specifically, it lists the versions available highlighted by their status (stable/testing/masked/install) for a package, lists use flags per package with descriptions, calculates the installed size of a package and also outputs the relevent entries in the changelog related to the package version.
-
-.LP
-It also employes a smarter package query syntax than emerge where examples such as:
-.LP .IP
-mozilla\-1.1
-.br
-mozilla\-1.*
-.LP
-are accepted.
-
-.SH "OPTIONS"
-.LP
-\fB\-b\fR <\fI/path/to/file\fR> [\fIcategory\fR]
-.br
-\fBbelongs\fR <\fI/path/to/file\fR> [\fIcategory\fR]
-.IP
-Searches for the package which a file belongs to with an option to restrict a search to a single or multiple category. Wildcards in the category name is accepted to speed up searching. (eg. etcat belongs /usr/lib/libmpeg.so "media\-*")
-
-.LP
-\fB\-c\fR <\fIpackage[\-version]\fR>
-.br
-\fBchanges\fR <\fIpackage[\-version]\fR>
-.IP
-Outputs ChangeLog entry for the package and version specified. Uses the latest package version if none specified.
-
-.LP
-\fB\-d\fR <\fIregex expression\fR>
-.br
-\fBdepends\fR <\fIregex expression\fR>
-.IP
-Searches through portage for a dependency string satisfying that regular expression.
-
-.LP
-\fB\-f\fR <\fIpackage[\-version]\fR>
-.br
-\fBfiles\fR <\fIpackage[\-version]\fR>
-.IP
-Lists all the files installed for this package.
-
-.LP
-\fB\-s\fR <\fIpackage\fR>
-.br
-\fBsize\fR <\fIpackage\fR>
-.IP
-Outputs the installed size of the package.
-
-.LP
-\fB\-u\fR <\fIpackage[\-version]\fR>
-.br
-\fBuses\fR <\fIpackage[\-version]\fR>
-.IP
-Outputs the USE flags supported by this package and also their installed state and description.
-
-.LP
-\fB\-v\fR <\fIpackage\fR>
-.br
-\fBversions\fR <\fIpackage\fR>
-.IP
-Output all the versions for packages that match the \fIpackage\fR name given with indication of whether the packages is stable, masked, unstable or installed.
-.SH "SEE ALSO"
-.LP
-Type \fBetcat\fR for examples and more information
-.SH "AUTHORS"
-.LP
-Alastair Tse <liquidx@gentoo.org>
diff --git a/trunk/src/eviewcvs/AUTHORS b/trunk/src/eviewcvs/AUTHORS
deleted file mode 100644
index 36d5bfd..0000000
--- a/trunk/src/eviewcvs/AUTHORS
+++ /dev/null
@@ -1 +0,0 @@
-Aron Griffis <agriffis@gentoo.org>
diff --git a/trunk/src/eviewcvs/Makefile b/trunk/src/eviewcvs/Makefile
deleted file mode 100644
index ee4208f..0000000
--- a/trunk/src/eviewcvs/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-# 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)/
diff --git a/trunk/src/eviewcvs/README b/trunk/src/eviewcvs/README
deleted file mode 100644
index c7258d7..0000000
--- a/trunk/src/eviewcvs/README
+++ /dev/null
@@ -1,11 +0,0 @@
-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/trunk/src/eviewcvs/eviewcvs b/trunk/src/eviewcvs/eviewcvs
deleted file mode 100755
index 280ec0b..0000000
--- a/trunk/src/eviewcvs/eviewcvs
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/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/trunk/src/eviewcvs/eviewcvs.pod b/trunk/src/eviewcvs/eviewcvs.pod
deleted file mode 100644
index b4403c8..0000000
--- a/trunk/src/eviewcvs/eviewcvs.pod
+++ /dev/null
@@ -1,48 +0,0 @@
-=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/trunk/src/genpkgindex/Makefile b/trunk/src/genpkgindex/Makefile
deleted file mode 100644
index 9f0ea2c..0000000
--- a/trunk/src/genpkgindex/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-# 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:
- echo "ABWONG (AB-wong vb.) To bounce cheerfully on a bed."
-
-dist:
- mkdir -p ../../$(distdir)/src/genpkgindex
- cp Makefile genpkgindex genpkgindex.1 ../../$(distdir)/src/genpkgindex/
-
-install:
- install -m 0755 genpkgindex $(bindir)/
- install -m 0644 genpkgindex.1 $(mandir)/
diff --git a/trunk/src/genpkgindex/genpkgindex b/trunk/src/genpkgindex/genpkgindex
deleted file mode 100644
index c079b83..0000000
--- a/trunk/src/genpkgindex/genpkgindex
+++ /dev/null
@@ -1,336 +0,0 @@
-#!/usr/bin/python
-# Copyright 2006-2007 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-
-
-import os
-import stat
-import sys
-import time
-import getopt
-from stat import *
-
-if getattr(__builtins__, "set", None) is None:
- from sets import Set as set
-
-for x in ['CFLAGS','CXXFLAGS', 'LDFLAGS','USE']:
- os.environ[x] = ''
-del x
-
-os.environ["USE_EXPAND"] = "-*"
-
-import portage
-
-try:
- import portage.xpak as xpak
- import portage.checksum as portage_checksum
- import portage.dep as portage_dep
- import portage.util as portage_util
- import portage.const as portage_const
-except ImportError:
- import xpak
- import portage_checksum
- import portage_dep
- import portage_util
- import portage_const
-
-compress = bool(os.environ.get("COMPRESSPKGFILE", ''))
-pkgdir = portage.settings["PKGDIR"]
-opt_args_short="hqvcP:"
-opt_args_long=["help", "quiet", "verbose", "compress", "pkgdir"]
-quiet = False
-verbose = False
-
-def usage():
- print portage.output.green("Usage:")+"\t"+portage.output.yellow("genpkgindex")+" -"+portage.output.blue("["+opt_args_short+"]")
- print portage.output.white(" Options:")+" --"+" --".join(opt_args_long)
- sys.exit(1)
-
-def update_pkgdir():
- if not os.path.exists(portage.settings["PKGDIR"]+"/All"):
- return
-
- os.chdir(portage.settings["PKGDIR"]+"/All")
- for x in os.listdir("."):
- pkg = os.path.basename(x)
- if pkg[-5:] != ".tbz2":
- continue
-
- mode = os.lstat(pkg)[ST_MODE]
- if not S_ISREG(mode):
- if S_ISLNK(mode):
- if not os.path.exists(os.readlink(x)):
- if verbose:
- portage.writemsg(portage.output.yellow(" * ")+"Removing broken symlink: "+x+"\n")
- os.unlink(x)
- continue
- tbz2 = xpak.tbz2(pkg)
- data = tbz2.getboth()
- cat = xpak.getitem(data, "CATEGORY")
- cat = cat[:-1]
- if not os.path.exists("../"+cat):
- os.mkdir("../"+cat)
- if os.path.exists("../"+ cat + "/" + pkg):
- os.unlink("../"+ cat + "/" + pkg)
- os.rename(pkg, "../"+ cat + "/" + pkg)
- os.symlink("../"+ cat + "/"+ pkg, pkg)
-
-def grabpkgnames(dirp):
- names = []
- categories = portage.grabfile(portage.settings["PORTDIR"]+"/profiles/categories")
- os.chdir(dirp)
- for cat in os.listdir('.'):
- if cat in categories:
- for pkg in os.listdir(cat):
- if os.path.basename(pkg).endswith("tbz2"):
- names.append(cat+"/"+pkg)
- names.sort()
- return names
-
-def cleanxfiles(dirp):
- global verbose
- # Clean up stale cache files
- os.chdir(portage_const.CACHE_PATH+"/xpak")
- for pkg in os.listdir('.'):
- p = os.path.basename(pkg)
- if not p.endswith(".xpak"):
- continue
- tbz2 = xpak.tbz2(p)
- stuff = tbz2.getboth()
- cat = xpak.getitem(stuff, "CATEGORY")
- if not os.path.exists(dirp + "/" + cat[:-1] + "/" + p[:-5] + ".tbz2"):
- # tidy up
- if verbose:
- portage.writemsg(portage.output.yellow(" * ") + "Stale entry: " + dirp + "/" + cat[:-1] + "/" + p[:-5] + ".tbz2\n")
- os.unlink(p)
- os.unlink(p[:-5]+".md5")
-
-def cleanpkgdir():
- if os.path.exists("/usr/bin/eclean"):
- os.system("/usr/bin/eclean -d packages")
-
-
-def parseargs():
- global pkgdir
- global compress
- global verbose
- global quiet
-
- if portage.settings.get("NOCOLOR") not in ("yes","true"):
- portage.output.havecolor = 1
- else:
- portage.output.havecolor = 0
-
- # Parse the cmdline.
- try:
- opts, args = getopt.getopt(sys.argv[1:], opt_args_short, opt_args_long)
- except getopt.GetoptError:
- usage()
- sys.exit(2)
-
- for opt, optarg in opts:
- if opt in ("-v", "verbose"):
- verbose = True
- if opt in ("-h", "--help"):
- usage()
- if opt in ("-c", "--compress"):
- compress = True
- if opt in ("-q", "--quiet"):
- quiet = True
- if opt in ("-P", "--pkgdir"):
- pkgdir = optarg
-
- if "cleanpkgdir" in portage.settings["FEATURES"]:
- cleanpkgdir()
-
-def serialize_depset(src, context='and'):
- l = []
- if not src:
- return ''
- if isinstance(src, basestring):
- return src
- i = iter(src)
- for x in i:
- if isinstance(x, basestring):
- if x != '||':
- l.append(x)
- continue
- x = i.next()
- if len(x) == 1:
- l.append(serialize_depset(x[0]))
- else:
- l.append("|| ( %s )" % serialize_depset(x))
- else:
- # and block.
- if context == 'and':
- v = serialize_depset(x, context=context)
- if v.strip():
- l.append(v)
- else:
- v = serialize_depset(x, context='or')
- if v.strip():
- l.append("( %s )" % v.strip())
- return ' '.join(l)
-
-def getallpkgs():
- packages = []
- os.chdir(pkgdir)
- for pkg in grabpkgnames(pkgdir):
-
- st = os.stat(pkg)
-
- if not os.path.exists(portage_const.CACHE_PATH+"/xpak/"):
- os.mkdir(portage_const.CACHE_PATH+"/xpak/")
-
- fname = portage_const.CACHE_PATH+"/xpak/"+os.path.basename(pkg)[:-5]+".xpak"
-
- if os.path.exists(fname):
- if st.st_mtime != os.stat(fname).st_mtime:
- #print "unlinking "+fname
- os.unlink(fname)
-
- if not os.path.exists(fname):
- tbz2 = xpak.tbz2(pkg)
- xpdata = xpak.xpak_mem(tbz2.get_data())
- fp = open(fname, "w")
- fp.write(xpdata+xpak.encodeint(len(xpdata))+"STOP")
- fp.close()
-
- chksum = portage_checksum.perform_md5(pkg)
- fp = open(fname[:-5]+".md5", "w")
- fp.write(chksum)
- fp.close()
-
- os.utime(fname, (st.st_mtime, st.st_mtime))
-
- else:
- if os.path.exists(fname[:-5]+".md5"):
- chksum = "".join(portage.grabfile(fname[:-5]+".md5"))
- else:
- chksum = portage_checksum.perform_md5(pkg)
-
- tbz2 = xpak.tbz2(fname)
-
- packages.append((pkg, tbz2, chksum, st))
- return packages
-
-def genpkgindex_header(fp, packages):
- import re
- profilever = os.path.normpath("///"+os.readlink("/etc/make.profile"))
- basepath = os.path.normpath("///"+portage.settings["PORTDIR"]+"/profiles")
- if re.match(basepath,profilever):
- profilever = profilever[len(basepath)+1:]
- else:
- profilever = "!"+profilever
- del basepath
-
- timestamp = str(time.time()).split(".")[0]
- fp.write("# This file was auto generated by " + os.path.basename(sys.argv[0]) + "\n")
- if pkgdir == portage.settings["PKGDIR"]:
- fp.write("PROFILE: "+profilever+"\n")
- fp.write("PACKAGES: "+str(len(packages)) +"\n")
- fp.write("TIMESTAMP: "+timestamp+"\n")
-
- vmask = [ "AUTOCLEAN", "DISTDIR", "PKGDIR", "PORTDIR" , "PORTAGE_TMPDIR" , "PORTAGE_RSYNC_OPTS" ]
- variables = portage_util.grabfile(portage.settings["PORTDIR"]+"/profiles/info_vars")
- variables = [v for v in variables if v not in vmask]
- variables.sort()
-
- for var in variables:
- if var in portage.settings:
- if (len(portage.settings[var])):
- fp.write(var+": "+portage.settings[var]+"\n")
- else:
- fp.write("PACKAGES: "+str(len(packages)) +"\n")
- fp.write("TIMESTAMP: "+timestamp+"\n")
- fp.write("\n")
-
-def genpkgindex(packages):
- os.chdir(pkgdir)
- control_file = ".Packages"
- fp = open(control_file, "w")
- genpkgindex_header(fp, packages)
-
- for pkg, tbz2, chksum, st in packages:
- stuff = tbz2.getboth()
- if not stuff:
- print "Not a tbz2: "+str(pkg)
- continue
-
- cat = xpak.getitem(stuff, "CATEGORY")
-
- use = xpak.getitem(stuff, "USE")
- if use is None:
- use = ''
- iuse = xpak.getitem(stuff, "IUSE")
- if iuse is None:
- iuse = ''
-
- s = xpak.getitem(stuff, "DESCRIPTION")
- if s is not None:
- s = ' '.join(s.split())