Files
entropy/client/text_rescue.py

877 lines
30 KiB
Python

# -*- coding: utf-8 -*-
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@license: GPL-2
B{Entropy Package Manager Client}.
"""
import os
import sys
import shutil
import tempfile
from entropy.const import etpConst, etpSys, etpUi
from entropy.output import red, bold, brown, blue, darkred, darkgreen, purple, \
print_info, print_warning, print_error
from entropy.exceptions import SystemDatabaseError
from entropy.db.exceptions import OperationalError, DatabaseError
import entropy.dep
import entropy.tools
from entropy.client.interfaces import Client
from entropy.i18n import _
# strictly depending on Portage atm
from entropy.spm.plugins.interfaces.portage_plugin import xpaktools
def _backup_client_repository(entropy_client):
"""
docstring_title
@return:
@rtype:
"""
dbpath = etpConst['etpdatabaseclientfilepath']
if not os.path.isfile(dbpath):
return True
# make sure to commit any transaction before backing-up
entropy_client.installed_repository().commit()
backed_up, msg = entropy_client.backup_repository(etpConst['clientdbid'],
os.path.dirname(dbpath))
return backed_up
def test_spm(entropy_client):
# test if portage is available
try:
return entropy_client.Spm()
except Exception as err:
entropy.tools.print_traceback()
mytxt = _("Source Package Manager backend not available")
print_error(darkred(" * ")+red("%s: %s" % (mytxt, err,)))
return None
def test_clientdb(entropy_client):
try:
entropy_client.installed_repository().validate()
except SystemDatabaseError:
mytxt = _("Installed packages database not available")
print_error(darkred(" * ")+red("%s !" % (mytxt,)))
return 1
def database(options):
if not options:
return -10
# check if I am root
if not entropy.tools.is_root():
mytxt = _("You are not root")
print_error(red(mytxt+"."))
return 1
cmd = options[0]
etp_client = None
acquired = False
try:
etp_client = Client(installed_repo = False)
acquired = entropy.tools.acquire_entropy_locks(etp_client)
if not acquired:
print_error(darkgreen(
_("Another Entropy is currently running.")))
return 1
if cmd == "generate":
return _database_generate(etp_client)
elif cmd == "check":
return _database_check(etp_client)
elif cmd == "resurrect":
return _database_resurrect(etp_client)
elif cmd in ("counters", "spmuids",):
if cmd == "counters":
print_warning("")
print_warning("'%s' %s: '%s'" % (
purple("equo database counters"),
blue(_("is deprecated, please use")),
darkgreen("equo database spmuids"),))
print_warning("")
return _database_counters(etp_client)
elif cmd in ("gentoosync", "spmsync",):
if cmd == "gentoosync":
print_warning("")
print_warning("'%s' %s: '%s'" % (
purple("equo database gentoosync"),
blue(_("is deprecated, please use")),
darkgreen("equo database spmsync"),))
print_warning("")
return _database_spmsync(etp_client)
elif cmd == "backup":
status, err_msg = etp_client.backup_repository(
etpConst['clientdbid'],
os.path.dirname(etpConst['etpdatabaseclientfilepath']))
if status:
return 0
return 1
elif cmd == "restore":
return _database_restore(etp_client)
elif cmd == "vacuum":
return _database_vacuum(etp_client)
elif cmd == "info":
return _getinfo(etp_client)
finally:
if acquired and (etp_client is not None):
entropy.tools.release_entropy_locks(etp_client)
if etp_client is not None:
etp_client.shutdown()
return -10
def _database_vacuum(entropy_client):
if entropy_client.installed_repository() is not None:
print_info(red(" @@ ")+"%s..." % (blue(_("Vacuum cleaning System Database")),), back = True)
entropy_client.installed_repository().dropAllIndexes()
entropy_client.installed_repository().vacuum()
entropy_client.installed_repository().commit()
print_info(red(" @@ ")+"%s." % (brown(_("Vacuum cleaned System Database")),))
return 0
print_warning(darkred(" !!! ")+blue("%s." % (_("No System Databases found"),)))
return 1
def _database_restore(entropy_client):
dblist = entropy_client.installed_repository_backups()
if not dblist:
print_info(brown(" @@ ")+blue("%s." % (
_("No backed up databases found"),)))
return 1
mydblist = []
db_data = []
for mydb in dblist:
ts = os.path.getmtime(mydb)
mytime = entropy.tools.convert_unix_time_to_human_time(ts)
mydblist.append("[%s] %s" % (mytime, mydb,))
db_data.append(mydb)
def fake_cb(s):
return s
input_params = [
('db', ('combo', (_('Select the database you want to restore'),
mydblist),), fake_cb, True)
]
while True:
data = entropy_client.input_box(
red(_("Entropy installed packages database restore tool")),
input_params, cancel_button = True)
if data is None:
return 1
myid, dbx = data['db']
try:
backup_path = db_data.pop(myid-1)
except IndexError:
continue
if not os.path.isfile(backup_path):
continue
break
# make sure to commit any transaction before restoring
entropy_client.installed_repository().commit()
status, err_msg = entropy_client.restore_repository(backup_path,
etpConst['etpdatabaseclientfilepath'], etpConst['clientdbid'])
if status:
return 0
return 1
def _database_counters(entropy_client):
Spm = test_spm(entropy_client)
if Spm is None:
return 1
rc = test_clientdb(entropy_client)
if rc is not None:
return rc
print_info(red(" %s..." % (_("Regenerating counters table"),) ))
entropy_client.installed_repository().regenerateSpmUidMapping()
print_info(red(" %s" % (
_("Counters table regenerated. Look above for errors."),) ))
return 0
def _database_resurrect(entropy_client):
mytxt = "####### %s: %s" % (
bold(_("ATTENTION")),
red(_("The installed package database will be resurrected, this will take a LOT of time.")),
)
print_warning(mytxt)
mytxt = "####### %s: %s" % (
bold(_("ATTENTION")),
red(_("Please use this function ONLY if you are using an Entropy-aware distribution.")),
)
print_warning(mytxt)
rc = entropy_client.ask_question(" %s" % (
_("Can I continue ?"),) )
if rc == _("No"):
return 0
rc = entropy_client.ask_question(" %s" % (
_("Are you REALLY sure ?"),) )
if rc == _("No"):
return 0
rc = entropy_client.ask_question(" %s" % (
_("Do you even know what you're doing ?"),) )
if rc == _("No"):
return 0
# clean caches
entropy_client.clear_cache()
# ok, he/she knows it... hopefully
# if exist, copy old database
print_info(red(" @@ ") + \
blue(_("Creating backup of the previous database, if exists.")))
_backup_client_repository(entropy_client)
try:
os.remove(etpConst['etpdatabaseclientfilepath'])
except OSError:
pass
# Now reinitialize it
mytxt = " %s %s" % (
darkred(_("Initializing the new database at")),
bold(etpConst['etpdatabaseclientfilepath']),
)
print_info(mytxt, back = True)
entropy_client.reopen_installed_repository()
entropy_client.installed_repository().initializeRepository()
entropy_client.installed_repository().commit()
mytxt = " %s %s" % (
darkgreen(_("Database reinitialized correctly at")),
bold(etpConst['etpdatabaseclientfilepath']),
)
print_info(mytxt)
mytxt = red(" %s. %s. %s ...") % (
_("Collecting installed files"),
_("Writing to temporary file"),
_("Please wait"),
)
print_info(mytxt, back = True)
# since we use find, see if it's installed
find = os.system("which find &> /dev/null")
if find != 0:
mytxt = "%s: %s!" % (
darkred(_("Attention")),
red(_("You must have 'find' installed")),
)
print_error(mytxt)
return
# spawn process
rnd_num = entropy.tools.get_random_number()
tmpfile = os.path.join(etpConst['packagestmpdir'], "%s" % (rnd_num,))
if os.path.isfile(tmpfile):
os.remove(tmpfile)
os.system("find "+etpConst['systemroot']+"/ -mount 1> "+tmpfile)
if not os.path.isfile(tmpfile):
mytxt = "%s: %s!" % (
darkred(_("Attention")),
red(_("'find' couldn't generate an output file")),
)
print_error(mytxt)
return
f = open(tmpfile, "r")
# creating list of files
filelist = set()
item = f.readline().strip()
while item:
filelist.add(item)
item = f.readline().strip()
f.close()
entries = len(filelist)
mytxt = red(" %s...") % (
_("Found %s files on the system. Assigning packages" % (entries,) ),)
print_info(mytxt)
atoms = {}
pkgsfound = set()
repos_data = entropy_client.Settings()['repositories']
for repo in repos_data['order']:
mytxt = red(" %s: %s") % (_("Matching in repository"),
repos_data['available'][repo]['description'],)
print_info(mytxt)
# get all idpackages
dbconn = entropy_client.open_repository(repo)
idpackages = dbconn.listAllPackageIds()
count = str(len(idpackages))
cnt = 0
for idpackage in idpackages:
cnt += 1
idpackageatom = dbconn.retrieveAtom(idpackage)
mytxt = " (%s/%s) %s ..." % (
cnt,
count,
red(_("Matching files from packages")),
)
print_info(mytxt, back = True)
# content
content = dbconn.retrieveContent(idpackage)
for item in content:
if etpConst['systemroot']+item in filelist:
pkgsfound.add((idpackage, repo))
atoms[(idpackage, repo)] = idpackageatom
filelist.difference_update(
set([etpConst['systemroot']+x for x in content]))
break
mytxt = red(" %s. %s...") % (
_("Found %s packages") % (bold(str(len(pkgsfound))),),
_("Filling database"),
)
print_info(mytxt)
count = str(len(pkgsfound))
cnt = 0
os.remove(tmpfile)
for pkgfound in pkgsfound:
cnt += 1
print_info(" ("+str(cnt)+"/"+count+") "+red(
"%s: " % (_("Adding"),))+atoms[pkgfound], back = True)
etp_pkg = entropy_client.Package()
etp_pkg.prepare(tuple(pkgfound), "install", {})
etp_pkg.add_installed_package()
etp_pkg.kill()
del etp_pkg
print_info(red(" %s." % (_("Database resurrected successfully"),)))
print_info(red(" %s..." % (_("Now indexing tables"),)))
entropy_client.installed_repository().createAllIndexes()
print_info(red(" %s." % (_("Database reinitialized successfully"),)))
print_warning(red(" %s" % (_("Keep in mind that virtual packages couldn't be matched. They don't own any files."),) ))
return 0
def _database_spmsync(entropy_client):
Spm = test_spm(entropy_client)
if Spm is None:
return 1
rc = test_clientdb(entropy_client)
if rc is not None:
return rc
print_info(red(" %s..." % (
_("Scanning Source Package Manager and Entropy databases for differences"),)))
# make it crash
entropy_client._installed_repo_enable = True
entropy_client.reopen_installed_repository()
entropy_client.close_repositories()
print_info(red(" %s..." % (
_("Collecting Source Package Manager metadata"),) ), back = True)
spm_packages = Spm.get_installed_packages()
installed_packages = []
for spm_package in spm_packages:
try:
pkg_counter = Spm.get_installed_package_metadata(spm_package,
"COUNTER")
except KeyError:
print_error("cannot get COUNTER for %s" % (spm_package,))
continue
try:
pkg_counter = int(pkg_counter)
except ValueError:
print_error("cannot convert COUNTER for %s, %s" % (
spm_package, pkg_counter,))
continue
installed_packages.append((spm_package, pkg_counter,))
print_info(red(" %s..." % (
_("Collecting Entropy packages"),) ), back = True)
installed_spm_uids = set()
to_be_added = set()
to_be_removed = set()
print_info(red(" %s..." % (_("Differential Scan"),)), back = True)
# packages to be added/updated (handle add/update later)
for x in installed_packages:
installed_spm_uids.add(x[1])
counter = entropy_client.installed_repository().isSpmUidAvailable(x[1])
if (not counter):
to_be_added.add(tuple(x))
# packages to be removed from the database
repo_spm_uids = entropy_client.installed_repository().listAllSpmUids()
for x in repo_spm_uids:
if x[0] < 0: # skip packages without valid counter
continue
if x[0] not in installed_spm_uids:
# check if the package is in to_be_added
if to_be_added:
atom = entropy_client.installed_repository().retrieveAtom(x[1])
add = True
if atom:
atomkey = entropy.dep.dep_getkey(atom)
atomslot = entropy_client.installed_repository().retrieveSlot(x[1])
add = True
for pkgdata in to_be_added:
try:
addslot = Spm.get_installed_package_metadata(
pkgdata[0], "SLOT")
except KeyError:
continue
addkey = entropy.dep.dep_getkey(pkgdata[0])
# workaround for ebuilds not having slot
if addslot is None:
addslot = '0'
if (atomkey == addkey) and (str(atomslot) == str(addslot)):
# do not add to to_be_removed
add = False
break
if add:
to_be_removed.add(x[1])
else:
to_be_removed.add(x[1])
if (not to_be_removed) and (not to_be_added):
print_info(red(" %s." % (_("Databases already synced"),)))
# then exit gracefully
return 0
# check lock file
gave_up = entropy_client.wait_resources()
if gave_up:
print_info(red(" %s." % (_("Entropy locked, giving up"),)))
return 2
acquired = entropy_client.lock_resources()
if not acquired:
print_info(red(" %s." % (_("Entropy locked during lock acquire"),)))
return 2
if to_be_removed:
mytxt = blue("%s. %s:") % (
_("Someone removed these packages"),
_("They would be removed from the system database"),
)
print_info(brown(" @@ ")+mytxt)
broken = set()
for x in to_be_removed:
atom = entropy_client.installed_repository().retrieveAtom(x)
if not atom:
broken.add(x)
continue
print_info(brown(" # ")+red(atom))
to_be_removed -= broken
if to_be_removed:
rc = _("Yes")
if etpUi['ask']:
rc = entropy_client.ask_question(">> %s" % (
_("Continue with removal ?"),))
if rc == _("Yes"):
queue = 0
totalqueue = str(len(to_be_removed))
for x in to_be_removed:
queue += 1
atom = entropy_client.installed_repository().retrieveAtom(x)
mytxt = " %s (%s/%s) %s %s %s" % (
red("--"),
blue(str(queue)),
red(totalqueue),
brown(">>>"),
_("Removing"),
darkgreen(atom),
)
print_info(mytxt)
entropy_client.installed_repository().removePackage(x)
print_info(brown(" @@ ") + \
blue("%s." % (_("Database removal complete"),) ))
if to_be_added:
mytxt = blue("%s. %s:") % (
_("Someone added these packages"),
_("They would be added to the system database"),
)
print_info(brown(" @@ ")+mytxt)
for x in to_be_added:
print_info(darkgreen(" # ")+red(x[0]))
rc = _("Yes")
if etpUi['ask']:
rc = entropy_client.ask_question(">> %s" % (
_("Continue with adding ?"),) )
if rc == _("No"):
entropy_client.unlock_resources()
return 0
# now analyze
totalqueue = str(len(to_be_added))
queue = 0
for atom, counter in to_be_added:
queue += 1
mytxt = " %s (%s/%s) %s %s %s" % (
red("++"),
blue(str(queue)),
red(totalqueue),
brown(">>>"),
_("Adding"),
darkgreen(atom),
)
print_info(mytxt)
tmp_fd, temp_pkg_path = tempfile.mkstemp()
os.close(tmp_fd)
xpaktools.append_xpak(temp_pkg_path, atom)
# now extract info
try:
mydata = Spm.extract_package_metadata(temp_pkg_path)
except Exception as err:
entropy.tools.print_traceback()
entropy_client.logger.log(
"[spm sync]",
etpConst['logging']['normal_loglevel_id'],
"Database spmsync: Exception caught: %s" % (
str(err),
)
)
print_warning(red("!!! %s: " % (
_("An error occured while analyzing")) ) + blue(atom))
print_warning("%s: %s" % (_("Exception"), str(err),))
continue
# create atom string
myatom = entropy.dep.create_package_atom_string(mydata['category'],
mydata['name'], mydata['version'], mydata['versiontag'])
# look for atom in client database
idpkgs = entropy_client.installed_repository().getPackageIds(myatom)
oldidpackages = sorted(idpkgs)
oldidpackage = None
if oldidpackages:
oldidpackage = oldidpackages[-1]
mydata['revision'] = 9999 # can't do much more
if oldidpackage:
mydata['revision'] = \
entropy_client.installed_repository().retrieveRevision(
oldidpackage)
if "original_repository" in mydata:
del mydata['original_repository']
idpk = entropy_client.installed_repository().handlePackage(mydata,
forcedRevision = mydata['revision'])
entropy_client.installed_repository().storeInstalledPackage(idpk,
"spm-db")
os.remove(temp_pkg_path)
print_info(brown(" @@ ") + \
blue("%s." % (_("Database update completed"),)))
entropy_client.unlock_resources()
return 0
def _database_generate(entropy_client):
Spm = test_spm(entropy_client)
if Spm is None:
return 1
mytxt = "%s: %s." % (
bold(_("ATTENTION")),
red(_("The installed package repository will be regenerated using Source Package Manager")),
)
print_warning(mytxt)
print_warning(red(_("If you dont know what you're doing just, don't do this. Really. I'm not joking.")))
rc = entropy_client.ask_question(" %s" % (_("Understood ?"),))
if rc == _("No"):
return 0
rc = entropy_client.ask_question(" %s" % (_("Really ?"),) )
if rc == _("No"):
return 0
rc = entropy_client.ask_question(" %s. %s" % (
_("This is your last chance"), _("Ok?"),) )
if rc == _("No"):
return 0
# clean caches
entropy_client.clear_cache()
# try to collect current installed revisions if possible
revisions_match = {}
try:
myids = entropy_client.installed_repository().listAllPackageIds()
for myid in myids:
myatom = entropy_client.installed_repository().retrieveAtom(myid)
myrevision = entropy_client.installed_repository().retrieveRevision(myid)
revisions_match[myatom] = myrevision
except:
pass
# ok, he/she knows it... hopefully
# if exist, copy old database
print_info(red(" @@ ") + \
blue(_("Creating backup of the previous database, if exists.")) + \
red(" @@"))
_backup_client_repository(entropy_client)
try:
os.remove(etpConst['etpdatabaseclientfilepath'])
except OSError:
pass
# Now reinitialize it
mytxt = darkred(" %s %s") % (
_("Initializing the new database at"),
bold(etpConst['etpdatabaseclientfilepath']),
)
print_info(mytxt, back = True)
entropy_client.reopen_installed_repository()
entropy_client.installed_repository().initializeRepository()
entropy_client.installed_repository().commit()
mytxt = darkred(" %s %s") % (
_("Database reinitialized correctly at"),
bold(etpConst['etpdatabaseclientfilepath']),
)
print_info(mytxt)
# now collect packages in the system
print_info(red(" %s..." % (
_("Transductingactioningintactering databases"),) ))
spm_packages = Spm.get_installed_packages()
# do for each database
maxcount = str(len(spm_packages))
count = 0
for spm_package in spm_packages:
count += 1
print_info(blue("(") + darkgreen(str(count)) + "/" + \
darkred(maxcount) + blue(")") + red(" :: ") + brown(spm_package),
back = True)
tmp_fd, temp_pkg_path = tempfile.mkstemp()
os.close(tmp_fd)
xpaktools.append_xpak(temp_pkg_path, spm_package)
# now extract info
try:
mydata = Spm.extract_package_metadata(temp_pkg_path)
except Exception as err:
entropy.tools.print_traceback()
entropy_client.logger.log(
"[spm sync]",
etpConst['logging']['normal_loglevel_id'],
"Database generation: Exception caught: %s" % (str(err),)
)
print_warning( red("!!! %s: %s") % (
_("An error occured while analyzing"), blue(spm_package),) )
print_warning("%s: %s: %s" % (
_("Exception"), str(Exception), err,))
continue
# Try to see if it's possible to use the revision of a possible old db
mydata['revision'] = 9999
# create atom string
myatom = entropy.dep.create_package_atom_string(mydata['category'],
mydata['name'], mydata['version'], mydata['versiontag'])
# now see if a revision is available
saved_rev = revisions_match.get(myatom)
if saved_rev is not None:
saved_rev = saved_rev
mydata['revision'] = saved_rev
idpk = entropy_client.installed_repository().addPackage(mydata,
revision = mydata['revision'], do_commit = False)
entropy_client.installed_repository().storeInstalledPackage(idpk,
"spm-db")
os.remove(temp_pkg_path)
print_info(red(" %s." % (_("All the Source Package Manager packages have been injected into Entropy database"),) ))
print_info(red(" %s...") % (_("Now indexing tables"),) )
entropy_client.installed_repository().createAllIndexes()
print_info(red(" %s." % (_("Database reinitialized successfully"),) ))
return 0
def _database_check(entropy_client):
def client_repository_sanity_check():
entropy_client.output(
"%s: %s" % (
brown(_("Sanity Check")),
darkgreen(_("installed packages repository")),
),
importance = 2,
level = "warning"
)
count = 0
errors = False
scanning_txt = _("Scanning...")
length = 0
idpkgs = []
try:
idpkgs = entropy_client.installed_repository().listAllPackageIds()
length = len(idpkgs)
except DatabaseError as err:
entropy.tools.print_traceback()
errors = True
entropy_client.output(
"%s: %s" % (darkred(_("Error")), err,),
importance = 1,
level = "warning"
)
if not errors:
for x in idpkgs:
count += 1
entropy_client.output(
darkgreen(scanning_txt),
importance = 0,
level = "info",
back = True,
count = (count, length),
percent = True
)
try:
entropy_client.installed_repository().getPackageData(x)
except Exception as err:
entropy.tools.print_traceback()
errors = True
entropy_client.output(
"%s: %s" % (
darkred(_("Error checking package")),
err,
),
importance = 0,
level = "warning"
)
if not errors:
entropy_client.output(
"%s: %s" % (brown(_("Sanity Check")), bold(_("passed"))),
importance = 2,
level = "warning"
)
return 0
else:
entropy_client.output(
"%s: %s" % (brown(_("Sanity Check")), bold(_("corrupted"))),
importance = 2,
level = "warning"
)
return -1
valid = True
try:
entropy_client.installed_repository().validate()
entropy_client.installed_repository().integrity_check()
except SystemDatabaseError as err:
print_error(repr(err))
valid = False
if valid:
client_repository_sanity_check()
else:
mytxt = "# %s: %s" % (bold(_("ATTENTION")),
red(_("database does not exist or is badly broken")),)
print_warning(mytxt)
return 1
return 0
def _getinfo(entropy_client):
# sysinfo
info = {}
osinfo = os.uname()
info['OS'] = osinfo[0]
info['Kernel'] = osinfo[2]
info['Architecture'] = osinfo[4]
info['Entropy version'] = etpConst['entropyversion']
from entropy.core.settings.base import SystemSettings
SysSettings = SystemSettings()
sys_set_client_plg_id = \
etpConst['system_settings_plugins_ids']['client_plugin']
# variables
info['User protected directories'] = SysSettings[sys_set_client_plg_id]['misc']['configprotect']
info['Collision Protection'] = SysSettings[sys_set_client_plg_id]['misc']['collisionprotect']
info['Entropy Log Level'] = SysSettings['system']['log_level']
info['Current branch'] = SysSettings['repositories']['branch']
info['Entropy configuration directory'] = etpConst['confdir']
info['Entropy work directory'] = etpConst['entropyworkdir']
info['Entropy packages directory'] = etpConst['entropypackagesworkdir']
info['Entropy unpack directory'] = etpConst['entropyunpackdir']
info['Entropy logging directory'] = etpConst['logdir']
info['Entropy Official Repository identifier'] = SysSettings['repositories']['default_repository']
info['Entropy API'] = etpConst['etpapi']
info['Entropy pidfile'] = etpConst['pidfile']
info['Entropy database tag'] = etpConst['databasestarttag']
info['Repositories'] = SysSettings['repositories']['available']
info['System Config'] = etpSys
info['UI Config'] = etpUi
# client database info
cdbconn = entropy_client.installed_repository()
info['Installed database'] = cdbconn
if cdbconn is not None:
# print db info
info['Removal internal protected directories'] = cdbconn.listConfigProtectEntries()
info['Removal internal protected directory masks'] = cdbconn.listConfigProtectEntries(mask = True)
info['Total installed packages'] = len(cdbconn.listAllPackageIds())
# repository databases info (if found on the system)
info['Repository databases'] = {}
for x in SysSettings['repositories']['order']:
dbfile = SysSettings['repositories']['available'][x]['dbpath']+"/"+etpConst['etpdatabasefile']
if os.path.isfile(dbfile):
# print info about this database
dbconn = entropy_client.open_repository(x)
info['Repository databases'][x] = {}
info['Repository databases'][x]['Installation internal protected directories'] = dbconn.listConfigProtectEntries()
info['Repository databases'][x]['Installation internal protected directory masks'] = dbconn.listConfigProtectEntries(mask = True)
info['Repository databases'][x]['Total available packages'] = len(dbconn.listAllPackageIds())
info['Repository databases'][x]['Database revision'] = entropy_client.get_repository(x).revision(x)
keys = sorted(info)
for x in keys:
#print type(info[x])
if isinstance(info[x], dict):
toptext = x
ykeys = sorted(info[x].keys())
for y in ykeys:
if isinstance(info[x][y], dict):
topsubtext = y
zkeys = sorted(info[x][y].keys())
for z in zkeys:
sys.stdout.write(red(toptext) + ": " + \
blue(topsubtext) + " => " + darkgreen(z) + \
" => " + str(info[x][y][z]) + "\n")
else:
sys.stdout.write(red(toptext) + ": "+blue(y) + " => " + \
str(info[x][y]) + "\n")
else:
sys.stdout.write(red(x) + ": " + str(info[x]) + "\n")