#!/usr/bin/python
# Copyright 1999-2004 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Id: /var/cvsroot/gentoo-src/portage/bin/fix-db.py,v 1.8 2004/10/11 04:01:00 jstubbs Exp $

import os,sys,re
sys.path = ["/usr/lib/portage/pym"]+sys.path

from stat import *
from output import *
from portage import lockfile,unlockfile,VDB_PATH,root


mylog = open("/var/log/emerge_fix-db.log", "a")
def writemsg(msg):
	if msg[-1] != '\n':
		msg += "\n"
	sys.stderr.write(msg)
	sys.stderr.flush()
	mylog.write(msg)
	mylog.flush()

def fix_global_counter(value):
	myf = open("/var/cache/edb/counter")
	newvalue = value+1000
	myf.write(str(newvalue))
	myf.flush()
	myf.close()
	return newvalue

bad = {}
counters = {}
times = {}

try:
	real_counter = long(open("/var/cache/edb/counter").read())
except SystemExit, e:
	raise  # This needs to be propogated
except:
	writemsg("ERROR: Real counter is invalid.\n")
	real_counter = 0

vardbdir = root+VDB_PATH+"/"
for cat in os.listdir(vardbdir):
	catdir = vardbdir+cat+"/"
	if not os.path.isdir(catdir):
		writemsg("Invalid file: '%s'\n" % catdir[:-1])
		continue
	for pkg in os.listdir(catdir):
		pkgdir = catdir+pkg+"/"
		catpkg = cat+"/"+pkg

		if not os.path.isdir(catdir):
			writemsg("Invalid file: '%s'\n" % pkgdir)
			continue
			
		bad[catpkg] = []
		
		pkgdirlist = os.listdir(pkgdir)
		if not pkgdirlist:
			writemsg("ERROR: Package directory is empty for '%s'\n" % catpkg)
			writemsg("       Deleting this directory. Remerge if you want it back.\n")
			os.rmdir(pkgdir)
			del bad[catpkg]
			continue
		
		if "CONTENTS" not in pkgdirlist:
			bad[catpkg] += ["CONTENTS is missing"]
			times[catpkg] = -1
			writemsg("ERROR: Contents file is missing from the package directory.\n")
			writemsg("       '%s' is corrupt and should be deleted.\n" % catpkg)
		else:
			times[catpkg] = None
			for line in open(pkgdir+"CONTENTS").readlines():
				mysplit = line.split()
				if mysplit[0] == "obj":
					try:
						times[catpkg] = long(mysplit[-1])
					except SystemExit, e:
						raise  # This needs to be propogated
					except:
						times[catpkg] = -1
						bad[catpkg] += ["CONTENTS is corrupt"]
						writemsg("ERROR: Corrupt CONTENTS file in '%s'\n" % catpkg)
						writemsg("       This package should be deleted.\n")
					break
			if times[catpkg] == None:
				times[catpkg] = os.stat(pkgdir+"CONTENTS")[ST_MTIME]

		if "COUNTER" not in pkgdirlist:
			bad[catpkg] += ["COUNTER is missing"]
			writemsg("ERROR: COUNTER file missing from '%s'.\n" % catpkg)
			counters[catpkg] = -1
		else:
			try:
				counters[catpkg] = long(open(pkgdir+"COUNTER").read().strip())
				if counters[catpkg] > real_counter:
					writemsg("ERROR: Global counter is lower than the '%s' COUNTER." % catpkg)
					real_counter = fix_global_counter(counters[catpkg])
			except SystemExit, e:
				raise  # This needs to be propogated
			except:
				bad[catpkg] += ["COUNTER is corrupt"]
				counters[catpkg] = -1

		if "SLOT" not in pkgdirlist:
			writemsg("ERROR: SLOT file missing from '%s'.\n" % catpkg)
			writemsg("       RE-MERGE this exact package version or unmerge and remerge.\n")
			bad[catpkg] += ["SLOT is missing"]
		else:
			myslot = open(pkgdir+"SLOT").read()
			if myslot and myslot[-1]=="\n":
				#writemsg("WARN: SLOT file has a newline. '%s'\n" % catpkg)
				myslot = myslot[:-1]
			if not myslot:
				bad[catpkg] += ["SLOT is empty"]
				writemsg("ERROR: SLOT file is empty for '%s'.\n" % catpkg)
				writemsg("       RE-MERGE this exact package version or unmerge and remerge it.\n")
			elif re.search("[^-a-zA-Z0-9\._]", myslot):
				bad[catpkg] += ["SLOT is corrupt"]
				writemsg("ERROR: SLOT file is corrupt for '%s'.\n" % catpkg)
				writemsg("       RE-MERGE this exact package version or unmerge and remerge it.\n")
			elif myslot.strip() != myslot:
				writemsg("WARN: SLOT file has invalid characters. '%s'\n" % catpkg)
				bad[catpkg] += ["SLOT is invalid"]

		if not bad[catpkg]:
			del bad[catpkg]


actions = {}
writemsg("\n\n")
for catpkg in bad.keys():
	bad[catpkg].sort()

	mystr = ""
	for x in bad[catpkg]:
		mystr += "   "+str(x)+"\n"

	if bad[catpkg] == ["CONTENTS is missing", "SLOT is missing"]:
		writemsg("%s: (possibly injected)\n%s\n" % (green(catpkg), mystr))
		actions[catpkg] = ["ignore"]
	elif bad[catpkg] == ["SLOT is empty"]:
		writemsg("%s: (old package) []\n%s\n" % (yellow(catpkg), mystr))
		actions[catpkg] = ["remerge"]
	else:
		writemsg("%s: (damaged/invalid) []\n%s\n" % (red(catpkg), mystr))
		actions[catpkg] = ["merge exact"]

if (len(sys.argv) > 1) and (sys.argv[1] == "--fix"):
	writemsg("These are only directions, at the moment.")
	for catpkg in actions.keys():
		action = actions[catpkg]
		writemsg("We will now '%s' '%s'..." % (action, catpkg))
		#if action == 
else:
	#writemsg("Run with '--fix' to attempt automatic correction.")
	pass

















