summaryrefslogtreecommitdiffstats
path: root/pym/dbapi/vardb.py
diff options
context:
space:
mode:
Diffstat (limited to 'pym/dbapi/vardb.py')
-rw-r--r--pym/dbapi/vardb.py394
1 files changed, 394 insertions, 0 deletions
diff --git a/pym/dbapi/vardb.py b/pym/dbapi/vardb.py
new file mode 100644
index 000000000..352f78077
--- /dev/null
+++ b/pym/dbapi/vardb.py
@@ -0,0 +1,394 @@
+from dbapi import dbapi
+from portage import settings, db, listdir, dblink
+from portage_const import VDB_PATH
+from portage_versions import pkgsplit, catpkgsplit
+from portage_util import write_atomic, writemsg, writems_stdout, grabfile
+from portage_dep import isjustname, isvalidatom, dep_getkey, dep_getslot, \
+ match_from_list, dep_expand
+from portage_update import fixdbentries
+
+import portage_exception
+import os, sys
+
+cptot=0
+class vardbapi(dbapi):
+ def __init__(self, root, categories=None, settings=None, vartree=None):
+ self.root = root[:]
+ #cache for category directory mtimes
+ self.mtdircache = {}
+ #cache for dependency checks
+ self.matchcache = {}
+ #cache for cp_list results
+ self.cpcache = {}
+ self.blockers = None
+ if settings is None:
+ settings = globals()["settings"]
+ self.settings = settings
+ if categories is None:
+ categories = settings.categories
+ self.categories = categories[:]
+ if vartree is None:
+ vartree = globals()["db"][root]["vartree"]
+ self.vartree = vartree
+
+ def cpv_exists(self,mykey):
+ "Tells us whether an actual ebuild exists on disk (no masking)"
+ return os.path.exists(self.root+VDB_PATH+"/"+mykey)
+
+ def cpv_counter(self,mycpv):
+ "This method will grab the COUNTER. Returns a counter value."
+ cdir=self.root+VDB_PATH+"/"+mycpv
+ cpath=self.root+VDB_PATH+"/"+mycpv+"/COUNTER"
+
+ # We write our new counter value to a new file that gets moved into
+ # place to avoid filesystem corruption on XFS (unexpected reboot.)
+ corrupted=0
+ if os.path.exists(cpath):
+ cfile=open(cpath, "r")
+ try:
+ counter=long(cfile.readline())
+ except ValueError:
+ print "portage: COUNTER for",mycpv,"was corrupted; resetting to value of 0"
+ counter=long(0)
+ corrupted=1
+ cfile.close()
+ elif os.path.exists(cdir):
+ mys = pkgsplit(mycpv)
+ myl = self.match(mys[0],use_cache=0)
+ print mys,myl
+ if len(myl) == 1:
+ try:
+ # Only one package... Counter doesn't matter.
+ write_atomic(cpath, "1")
+ counter = 1
+ except SystemExit, e:
+ raise
+ except Exception, e:
+ writemsg("!!! COUNTER file is missing for "+str(mycpv)+" in /var/db.\n",
+ noiselevel=-1)
+ writemsg("!!! Please run /usr/lib/portage/bin/fix-db.py or\n",
+ noiselevel=-1)
+ writemsg("!!! unmerge this exact version.\n", noiselevel=-1)
+ writemsg("!!! %s\n" % e, noiselevel=-1)
+ sys.exit(1)
+ else:
+ writemsg("!!! COUNTER file is missing for "+str(mycpv)+" in /var/db.\n",
+ noiselevel=-1)
+ writemsg("!!! Please run /usr/lib/portage/bin/fix-db.py or\n",
+ noiselevel=-1)
+ writemsg("!!! remerge the package.\n", noiselevel=-1)
+ sys.exit(1)
+ else:
+ counter=long(0)
+ if corrupted:
+ # update new global counter file
+ write_atomic(cpath, str(counter))
+ return counter
+
+ def cpv_inject(self,mycpv):
+ "injects a real package into our on-disk database; assumes mycpv is valid and doesn't already exist"
+ os.makedirs(self.root+VDB_PATH+"/"+mycpv)
+ counter = self.counter_tick(self.root, mycpv=mycpv)
+ # write local package counter so that emerge clean does the right thing
+ write_atomic(os.path.join(self.root, VDB_PATH, mycpv, "COUNTER"), str(counter))
+
+ def isInjected(self,mycpv):
+ if self.cpv_exists(mycpv):
+ if os.path.exists(self.root+VDB_PATH+"/"+mycpv+"/INJECTED"):
+ return True
+ if not os.path.exists(self.root+VDB_PATH+"/"+mycpv+"/CONTENTS"):
+ return True
+ return False
+
+ def move_ent(self,mylist):
+ origcp=mylist[1]
+ newcp=mylist[2]
+
+ # sanity check
+ for cp in [origcp,newcp]:
+ if not (isvalidatom(cp) and isjustname(cp)):
+ raise portage_exception.InvalidPackageName(cp)
+ origmatches=self.match(origcp,use_cache=0)
+ if not origmatches:
+ return
+ for mycpv in origmatches:
+ mycpsplit=catpkgsplit(mycpv)
+ mynewcpv=newcp+"-"+mycpsplit[2]
+ mynewcat=newcp.split("/")[0]
+ if mycpsplit[3]!="r0":
+ mynewcpv += "-"+mycpsplit[3]
+ mycpsplit_new = catpkgsplit(mynewcpv)
+ origpath=self.root+VDB_PATH+"/"+mycpv
+ if not os.path.exists(origpath):
+ continue
+ writemsg_stdout("@")
+ if not os.path.exists(self.root+VDB_PATH+"/"+mynewcat):
+ #create the directory
+ os.makedirs(self.root+VDB_PATH+"/"+mynewcat)
+ newpath=self.root+VDB_PATH+"/"+mynewcpv
+ if os.path.exists(newpath):
+ #dest already exists; keep this puppy where it is.
+ continue
+ os.rename(origpath, newpath)
+
+ # We need to rename the ebuild now.
+ old_eb_path = newpath+"/"+mycpsplit[1] +"-"+mycpsplit[2]
+ new_eb_path = newpath+"/"+mycpsplit_new[1]+"-"+mycpsplit[2]
+ if mycpsplit[3] != "r0":
+ old_eb_path += "-"+mycpsplit[3]
+ new_eb_path += "-"+mycpsplit[3]
+ if os.path.exists(old_eb_path+".ebuild"):
+ os.rename(old_eb_path+".ebuild", new_eb_path+".ebuild")
+
+ write_atomic(os.path.join(newpath, "CATEGORY"), mynewcat+"\n")
+ fixdbentries([mylist], newpath)
+
+ def update_ents(self, update_iter):
+ """Run fixdbentries on all installed packages (time consuming). Like
+ fixpackages, this should be run from a helper script and display
+ a progress indicator."""
+ dbdir = os.path.join(self.root, VDB_PATH)
+ for catdir in listdir(dbdir):
+ catdir = dbdir+"/"+catdir
+ if os.path.isdir(catdir):
+ for pkgdir in listdir(catdir):
+ pkgdir = catdir+"/"+pkgdir
+ if os.path.isdir(pkgdir):
+ fixdbentries(update_iter, pkgdir)
+
+ def move_slot_ent(self,mylist):
+ pkg=mylist[1]
+ origslot=mylist[2]
+ newslot=mylist[3]
+
+ if not isvalidatom(pkg):
+ raise portage_exception.InvalidAtom(pkg)
+
+ origmatches=self.match(pkg,use_cache=0)
+
+ if not origmatches:
+ return
+ for mycpv in origmatches:
+ origpath=self.root+VDB_PATH+"/"+mycpv
+ if not os.path.exists(origpath):
+ continue
+
+ slot=grabfile(origpath+"/SLOT");
+ if (not slot):
+ continue
+
+ if (slot[0]!=origslot):
+ continue
+
+ writemsg_stdout("s")
+ write_atomic(os.path.join(origpath, "SLOT"), newslot+"\n")
+
+ def cp_list(self,mycp,use_cache=1):
+ mysplit=mycp.split("/")
+ if mysplit[0] == '*':
+ mysplit[0] = mysplit[0][1:]
+ try:
+ mystat=os.stat(self.root+VDB_PATH+"/"+mysplit[0])[stat.ST_MTIME]
+ except OSError:
+ mystat=0
+ if use_cache and self.cpcache.has_key(mycp):
+ cpc=self.cpcache[mycp]
+ if cpc[0]==mystat:
+ return cpc[1]
+ list=listdir(self.root+VDB_PATH+"/"+mysplit[0],EmptyOnError=1)
+
+ if (list is None):
+ return []
+ returnme=[]
+ for x in list:
+ if x.startswith("."):
+ continue
+ if x[0] == '-':
+ #writemsg(red("INCOMPLETE MERGE:")+str(x[len("-MERGING-"):])+"\n")
+ continue
+ ps=pkgsplit(x)
+ if not ps:
+ self.invalidentry(self.root+VDB_PATH+"/"+mysplit[0]+"/"+x)
+ continue
+ if len(mysplit) > 1:
+ if ps[0]==mysplit[1]:
+ returnme.append(mysplit[0]+"/"+x)
+ if use_cache:
+ self.cpcache[mycp]=[mystat,returnme]
+ elif self.cpcache.has_key(mycp):
+ del self.cpcache[mycp]
+ return returnme
+
+ def cpv_all(self,use_cache=1):
+ returnme=[]
+ basepath = self.root+VDB_PATH+"/"
+
+ for x in self.categories:
+ for y in listdir(basepath+x,EmptyOnError=1):
+ if y.startswith("."):
+ continue
+ subpath = x+"/"+y
+ # -MERGING- should never be a cpv, nor should files.
+ if os.path.isdir(basepath+subpath) and (pkgsplit(y) is not None):
+ returnme += [subpath]
+ return returnme
+
+ def cp_all(self,use_cache=1):
+ mylist = self.cpv_all(use_cache=use_cache)
+ d={}
+ for y in mylist:
+ if y[0] == '*':
+ y = y[1:]
+ mysplit=catpkgsplit(y)
+ if not mysplit:
+ self.invalidentry(self.root+VDB_PATH+"/"+y)
+ continue
+ d[mysplit[0]+"/"+mysplit[1]] = None
+ return d.keys()
+
+ def checkblockers(self,origdep):
+ pass
+
+ def match(self,origdep,use_cache=1):
+ "caching match function"
+ mydep = dep_expand(
+ origdep, mydb=self, use_cache=use_cache, settings=self.settings)
+ mykey=dep_getkey(mydep)
+ mycat=mykey.split("/")[0]
+ if not use_cache:
+ if self.matchcache.has_key(mycat):
+ del self.mtdircache[mycat]
+ del self.matchcache[mycat]
+ mymatch = match_from_list(mydep,
+ self.cp_list(mykey, use_cache=use_cache))
+ myslot = dep_getslot(mydep)
+ if myslot is not None:
+ mymatch = [cpv for cpv in mymatch \
+ if self.aux_get(cpv, ["SLOT"])[0] == myslot]
+ return mymatch
+ try:
+ curmtime=os.stat(self.root+VDB_PATH+"/"+mycat)[stat.ST_MTIME]
+ except SystemExit, e:
+ raise
+ except:
+ curmtime=0
+
+ if not self.matchcache.has_key(mycat) or not self.mtdircache[mycat]==curmtime:
+ # clear cache entry
+ self.mtdircache[mycat]=curmtime
+ self.matchcache[mycat]={}
+ if not self.matchcache[mycat].has_key(mydep):
+ mymatch=match_from_list(mydep,self.cp_list(mykey,use_cache=use_cache))
+ myslot = dep_getslot(mydep)
+ if myslot is not None:
+ mymatch = [cpv for cpv in mymatch \
+ if self.aux_get(cpv, ["SLOT"])[0] == myslot]
+ self.matchcache[mycat][mydep]=mymatch
+ return self.matchcache[mycat][mydep][:]
+
+ def findname(self, mycpv):
+ return self.root+VDB_PATH+"/"+str(mycpv)+"/"+mycpv.split("/")[1]+".ebuild"
+
+ def aux_get(self, mycpv, wants):
+ mydir = os.path.join(self.root, VDB_PATH, mycpv)
+ if not os.path.isdir(mydir):
+ raise KeyError(mycpv)
+ results = []
+ for x in wants:
+ try:
+ myf = open(os.path.join(mydir, x), "r")
+ try:
+ myd = myf.read()
+ finally:
+ myf.close()
+ myd = " ".join(myd.split())
+ except IOError:
+ myd = ""
+ if x == "EAPI" and not myd:
+ results.append("0")
+ else:
+ results.append(myd)
+ return results
+
+ def aux_update(self, cpv, values):
+ cat, pkg = cpv.split("/")
+ mylink = dblink(cat, pkg, self.root, self.settings,
+ treetype="vartree", vartree=self.vartree)
+ if not mylink.exists():
+ raise KeyError(cpv)
+ for k, v in values.iteritems():
+ mylink.setfile(k, v)
+
+ def counter_tick(self,myroot,mycpv=None):
+ return self.counter_tick_core(myroot,incrementing=1,mycpv=mycpv)
+
+ def get_counter_tick_core(self,myroot,mycpv=None):
+ return self.counter_tick_core(myroot,incrementing=0,mycpv=mycpv)+1
+
+ def counter_tick_core(self,myroot,incrementing=1,mycpv=None):
+ "This method will grab the next COUNTER value and record it back to the global file. Returns new counter value."
+ cpath=myroot+"var/cache/edb/counter"
+ changed=0
+ min_counter = 0
+ if mycpv:
+ mysplit = pkgsplit(mycpv)
+ for x in self.match(mysplit[0],use_cache=0):
+ if x==mycpv:
+ continue
+ try:
+ old_counter = long(self.aux_get(x,["COUNTER"])[0])
+ writemsg("COUNTER '%d' '%s'\n" % (old_counter, x),1)
+ except SystemExit, e:
+ raise
+ except:
+ old_counter = 0
+ writemsg("!!! BAD COUNTER in '%s'\n" % (x), noiselevel=-1)
+ if old_counter > min_counter:
+ min_counter = old_counter
+
+ # We write our new counter value to a new file that gets moved into
+ # place to avoid filesystem corruption.
+ find_counter = ("find '%s' -type f -name COUNTER | " + \
+ "while read f; do echo $(<\"${f}\"); done | " + \
+ "sort -n | tail -n1") % os.path.join(self.root, VDB_PATH)
+ if os.path.exists(cpath):
+ cfile=open(cpath, "r")
+ try:
+ counter=long(cfile.readline())
+ except (ValueError,OverflowError):
+ try:
+ counter = long(commands.getoutput(find_counter).strip())
+ writemsg("!!! COUNTER was corrupted; resetting to value of %d\n" % counter,
+ noiselevel=-1)
+ changed=1
+ except (ValueError,OverflowError):
+ writemsg("!!! COUNTER data is corrupt in pkg db. The values need to be\n",
+ noiselevel=-1)
+ writemsg("!!! corrected/normalized so that portage can operate properly.\n",
+ noiselevel=-1)
+ writemsg("!!! A simple solution is not yet available so try #gentoo on IRC.\n")
+ sys.exit(2)
+ cfile.close()
+ else:
+ try:
+ counter = long(commands.getoutput(find_counter).strip())
+ writemsg("!!! Global counter missing. Regenerated from counter files to: %s\n" % counter,
+ noiselevel=-1)
+ except SystemExit, e:
+ raise
+ except:
+ writemsg("!!! Initializing global counter.\n", noiselevel=-1)
+ counter=long(0)
+ changed=1
+
+ if counter < min_counter:
+ counter = min_counter+1000
+ changed = 1
+
+ if incrementing or changed:
+
+ #increment counter
+ counter += 1
+ # update new global counter file
+ write_atomic(cpath, str(counter))
+ return counter