#!/usr/bin/python # Copyright 2006 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import os, string, stat, sys, time if getattr(__builtins__, "set", None) is None: from sets import Set as set for x in ['CFLAGS','CXXFLAGS', 'LDFLAGS','USE']: os.environ[x]='' import xpak, portage, portage_checksum, portage_dep, portage_util, portage_const argc=len(sys.argv) if argc >= 2: if (sys.argv[1][0] == "-"): print "Usage:\tgenpkgindex " print "\t- default dir "+portage.settings["PKGDIR"]+"/All" sys.exit(1) All=sys.argv[1] else: All=portage.settings["PKGDIR"]+"/All" All=os.path.normpath(All) if os.path.exists("/usr/bin/eclean") and "cleanpkgdir" in portage.settings["FEATURES"]: os.system("/usr/bin/eclean -d packages") os.chdir(All) portage.writemsg(portage.green(' * ')+'Update binary package index %s\n' % All); start = time.time() # generic name of our package index. control_file = ".Packages" try: 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 except SystemExit, e: raise # Needed else can't exit except: profilever="unavailable" packages = [] for pkg in os.listdir('.'): if not os.path.basename(pkg).endswith("tbz2"): continue 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)) packages.sort() timestamp=str(start).split(".")[0] # trunc the file and begin write operations. fp = open(control_file, "w") if argc <= 1: 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 x in variables: if portage.settings.has_key(x): if (len(portage.settings[x])): fp.write(x+": "+portage.settings[x]+"\n") else: fp.write("PACKAGES: "+str(len(packages)) +"\n") fp.write("TIMESTAMP: "+timestamp+"\n") fp.write("\n") 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) 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("PF: %s\nCATEGORY: %s\n" % (pkg[:-5], cat.strip())) 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() os.rename(".Packages", "Packages") # 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 if not os.path.exists(All + "/" + p[:-5] + ".tbz2"): #print "Stale entry: " + All + "/" + p[:-5] + ".tbz2" os.unlink(p) os.unlink(p[:-5]+".md5") finish = time.time() portage.writemsg(portage.green(' * ')+"PKGDIR contains "+ str(len(packages)) + ' packages. (%.01fsec)\n' % (finish - start));