blob: 43483c85ba9ea565fe00f485ea0fc489917918bd [file] [log] [blame]
#!/usr/bin/python2.6
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Perform various tasks related to updating Portage packages."""
import logging
import optparse
import os
import parallel_emerge
import portage
import re
import shutil
import sys
import tempfile
import chromite.lib.table as table
class UpgradeTable(table.Table):
"""Class to represent upgrade data in memory, can be written to csv/html."""
# TODO(mtennant): Remove html output - it isn't used.
# Column names. Note that 'ARCH' is replaced with a real arch name when
# these are accessed as attributes off an UpgradeTable object.
COL_PACKAGE = 'Package'
COL_SLOT = 'Slot'
COL_OVERLAY = 'Overlay'
COL_CURRENT_VER = 'Current ARCH Version'
COL_STABLE_UPSTREAM_VER = 'Stable Upstream ARCH Version'
COL_LATEST_UPSTREAM_VER = 'Latest Upstream ARCH Version'
COL_STATE = 'State On ARCH'
COL_DEPENDS_ON = 'Dependencies On ARCH'
COL_TARGET = 'Root Target'
COL_UPGRADED = 'Upgraded ARCH Version'
# COL_STATE values should be one of the following:
STATE_UNKNOWN = 'unknown'
STATE_NEEDS_UPGRADE = 'needs upgrade'
STATE_PATCHED = 'patched locally'
STATE_DUPLICATED = 'duplicated locally'
STATE_NEEDS_UPGRADE_AND_PATCHED = 'needs upgrade and patched locally'
STATE_NEEDS_UPGRADE_AND_DUPLICATED = 'needs upgrade and duplicated locally'
STATE_CURRENT = 'current'
@staticmethod
def GetColumnName(col, arch=None):
"""Translate from generic column name to specific given |arch|."""
if arch:
return col.replace('ARCH', arch)
return col
def __init__(self, arch, upgrade=False, name=None):
self._arch = arch
# These constants serve two roles, for both csv and html table output:
# 1) Restrict which column names are valid.
# 2) Specify the order of those columns.
columns = [self.COL_PACKAGE,
self.COL_SLOT,
self.COL_OVERLAY,
self.COL_CURRENT_VER,
self.COL_STABLE_UPSTREAM_VER,
self.COL_LATEST_UPSTREAM_VER,
self.COL_STATE,
self.COL_DEPENDS_ON,
self.COL_TARGET,
]
if upgrade:
columns.append(self.COL_UPGRADED)
table.Table.__init__(self, columns, name=name)
def __getattribute__(self, name):
"""When accessing self.COL_*, substitute ARCH name."""
if name.startswith('COL_'):
text = getattr(UpgradeTable, name)
return UpgradeTable.GetColumnName(text, arch=self._arch)
else:
return object.__getattribute__(self, name)
def GetArch(self):
"""Get the architecture associated with this UpgradeTable."""
return self._arch
def WriteHTML(self, filehandle):
"""Write table out as a custom html table to |filehandle|."""
# Basic HTML, up to and including start of table and table headers.
filehandle.write('<html>\n')
filehandle.write(' <table border="1" cellspacing="0" cellpadding="3">\n')
filehandle.write(' <caption>Portage Package Status</caption>\n')
filehandle.write(' <thead>\n')
filehandle.write(' <tr>\n')
filehandle.write(' <th>%s</th>\n' %
'</th>\n <th>'.join(self._columns))
filehandle.write(' </tr>\n')
filehandle.write(' </thead>\n')
filehandle.write(' <tbody>\n')
# Now write out the rows.
for row in self._rows:
filehandle.write(' <tr>\n')
for col in self._columns:
val = row.get(col, "")
# Add color to the text in specific cases.
if val and col == self.COL_STATE:
# Add colors for state column.
if val == self.STATE_NEEDS_UPGRADE or val == self.STATE_UNKNOWN:
val = '<span style="color:red">%s</span>' % val
elif (val == self.STATE_NEEDS_UPGRADE_AND_DUPLICATED or
val == self.STATE_NEEDS_UPGRADE_AND_PATCHED):
val = '<span style="color:red">%s</span>' % val
elif val == self.STATE_CURRENT:
val = '<span style="color:green">%s</span>' % val
if val and col == self.COL_DEPENDS_ON:
# Add colors for dependencies column. If a dependency is itself
# out of date, then make it red.
vallist = []
for cpv in val.split(' '):
# Get category/packagename from cpv, in order to look up row for
# the dependency. Then see if that pkg is red in its own row.
catpkg = Upgrader._GetCatPkgFromCpv(cpv)
deprow = self.GetRowsByValue({self.COL_PACKAGE: catpkg})[0]
if (deprow[self.COL_STATE] == self.STATE_NEEDS_UPGRADE or
deprow[self.COL_STATE] == self.STATE_UNKNOWN):
vallist.append('<span style="color:red">%s</span>' % cpv)
else:
vallist.append(cpv)
val = ' '.join(vallist)
filehandle.write(' <td>%s</td>\n' % val)
filehandle.write(' </tr>\n')
# Finish the table and html
filehandle.write(' </tbody>\n')
filehandle.write(' </table>\n')
filehandle.write('</html>\n')