diff options
Diffstat (limited to 'src/genpkgindex')
-rw-r--r-- | src/genpkgindex/Makefile | 18 | ||||
-rw-r--r-- | src/genpkgindex/genpkgindex | 336 | ||||
-rw-r--r-- | src/genpkgindex/genpkgindex.1 | 59 |
3 files changed, 413 insertions, 0 deletions
diff --git a/src/genpkgindex/Makefile b/src/genpkgindex/Makefile new file mode 100644 index 0000000..9f0ea2c --- /dev/null +++ b/src/genpkgindex/Makefile @@ -0,0 +1,18 @@ +# Copyright 2004 Karl Trygve Kalleberg <karltk@gentoo.org> +# Copyright 2004 Gentoo Technologies, Inc. +# Distributed under the terms of the GNU General Public License v2 +# +# $Header$ + +include ../../makedefs.mak + +all: + 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/src/genpkgindex/genpkgindex b/src/genpkgindex/genpkgindex new file mode 100644 index 0000000..c079b83 --- /dev/null +++ b/src/genpkgindex/genpkgindex @@ -0,0 +1,336 @@ +#!/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()) + if s: + fp.write("DESC: %s\n" % s) + # drop '.tbz2' + fp.write("CPV: %s/%s\n" % (cat.strip(), os.path.basename(pkg[:-5]))) + s = xpak.getitem(stuff, "SLOT") + if s is not None: + s = ' '.join(s.split()) + if s and s != "0": + fp.write("SLOT: %s\n" % s) + + split_use = use.split() + for name in ("LICENSE", "RDEPEND", "PDEPEND", "PROVIDE"): + item = xpak.getitem(stuff, name) + if item is None: + continue + val = portage_dep.use_reduce(portage_dep.paren_reduce(' '.join(item.split())), uselist=split_use) + if val: + fp.write("%s: %s\n" % (name, serialize_depset(val))) + + # map IUSE->USE and look for matching flags, filter dupes + # if both flags match then this is what matters. + s = set(split_use).intersection(iuse.split()) + if s: + l = list(s) + l.sort() + fp.write("USE: %s\n" % ' '.join(l)) + + fp.write("SIZE: "+ str(st[stat.ST_SIZE]) +"\n") + fp.write("MD5: "+chksum+"\n") + fp.write("\n") + + fp.write("\n") + fp.flush() + fp.close() + + if (compress): + os.system("bzip2 < .Packages > .Packages.bz2") + os.rename(".Packages.bz2", "Packages.bz2") + else: + if os.path.exists("Packages.bz2"): + os.unlink("Packages.bz2") + + os.rename(".Packages", "Packages") + + +def main(): + update_pkgdir() + + parseargs() + + if not quiet: + portage.writemsg(portage.output.green(' * ')+'Update binary package index %s/Packages\n' % pkgdir); + + start = time.time() + packages = getallpkgs() + genpkgindex(packages) + cleanxfiles(pkgdir) + finish = time.time() + + if not quiet: + portage.writemsg(portage.output.green(' * ')+"PKGDIR contains "+ str(len(packages)) + ' packages. (%.01fsec)\n' % (finish - start)); + + +if __name__ == "__main__": + main() diff --git a/src/genpkgindex/genpkgindex.1 b/src/genpkgindex/genpkgindex.1 new file mode 100644 index 0000000..8a3956e --- /dev/null +++ b/src/genpkgindex/genpkgindex.1 @@ -0,0 +1,59 @@ +.TH "genpkgindex" "1" "" "Ned Ludd" "gentoolkit" +.SH "NAME" +.LP +genpkgindex \- Generates package metadata from binary packages for use with programs such a qmerge from portage\-utils +.SH "USAGE" +.LP +genpkgindex [\fI\-\-options\fP] + +.SH "DESCRIPTION" +.LP +Generates package metadata from binary packages for use with programs such a qmerge from portage\-utils +.SH "OPTIONS" +.LP +.TP +\fB\-h, \-\-help\fR + Display help and exit +.TP +\fB\-v, \-\-verbose\fR + Be verbose +.TP +\fB\-q, \-\-quiet\fR + Be quiet +.TP +\fB\-c, \-\-compress\fR + Compresses the generated metadata with bzip2. +.TP +\fB\-P, \-\-pkgdir <path>\fR + Set the base location of the binary packages. The default is normally /usr/portage/packages +.TP + +.SH "ENVIRONMENT VARIABLES" +.LP +.TP +\fBPKGDIR\fP +is the location of binary packages that you can have created with FEATURES=buildpkg, '\-\-buildpkg' or '\-b/\-B' while emerging a package. +.SH "EXAMPLES" +.LP +Typical usage is to simply run: +.LP +genpkgindex +.LP +Alternatively if you want the metadata compressed: +.LP +genpkgindex \-\-compress +.LP +.SH "NOTES" +.LP +When no package directories are directly given to genpkgindex on the command line it will output additional variables that it assumes from the running portage environment. +.LP +When FEATURES=cleanpkgdir is enabled genpkgindex will invoke "/usr/bin/eclean \-d packages" before creating any package metadata. +.LP +genpkgindex intended use is to be run from /etc/portage/bashrc in the $EBUILD_PHASE of "postinst". +.LP +.SH "AUTHORS" +.LP +Ned Ludd <solar@gentoo.org> +.SH "SEE ALSO" +.LP +emerge(1) qmerge(1) make.conf(5) portage(5) |