# vim:set fileencoding=utf-8 et ts=4 sts=4 sw=4:
#
# apt-listchanges - Show changelog entries between the installed versions
# of a set of packages and the versions contained in
# corresponding .deb files
#
# Copyright (C) 2000-2006 Matt Zimmerman <mdz@debian.org>
# Copyright (C) 2006 Pierre Habouzit <madcoder@debian.org>
# Copyright (C) 2016 Robert Luberda <robert@debian.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#
from dbm import ndbm
from ALChacks import _
import os
import shutil
class DbError(Exception):
pass
class seendb_dummy(object):
'''Interface for seen database.
Also used when path to the database is not configured'''
def __contains__(self, srcpackage):
return False
def __getitem__(self, srcpackage):
pass
def __setitem__(self, srcpackage, version):
pass
def close_db(self):
pass
def apply_changes(self):
pass
def dump(self):
raise DbError(_("Path to the seen database is unknown.\n"
"Please either specify it with --save-seen option\n"
"or pass --profile=apt to have it read from the configuration file."))
class seendb(seendb_dummy):
'''Class to manage the seen database'''
def __init__(self, path, readOnly = False):
super().__init__()
self._extension = '.db'
if path[-3:] != self._extension:
raise DbError(_("Database %(db)s does not end with %(ext)s")
% {'db': path, 'ext': self._extension})
self._dbpath = path[:-3] # strip the .db suffix
try:
mode = 'r' if readOnly else 'c'
self._seen = ndbm.open(self._dbpath, mode, 0o644)
'foo%0' in self._seen
except Exception as ex:
raise DbError(_("Database %(db)s failed to load: %(errmsg)s")
% {'db': path, 'errmsg': str(ex)}) from ex
# Will replace seen after changes have actually been seen
self._seen_new = {}
def __contains__(self, srcpackage):
return srcpackage in self._seen
def __getitem__(self, srcpackage):
return self._seen[srcpackage].decode()
def __setitem__(self, srcpackage, version):
if self._seen.get(srcpackage, b'').decode() != version:
# Note: updating _seen_new, not _seen
self._seen_new[srcpackage] = version
def close_db(self):
self._seen.close()
self._seen = None
def apply_changes(self):
if not self._seen_new:
# Nothing to update
return
def mk(arg):
return self._dbpath + arg + self._extension
old, cur, new = (mk('-old'), mk(''), mk('-new'))
# For reliability and to have backup of the database,
# it is updated in the following steps:
# 1. copy current version to new
if os.path.isfile(cur):
shutil.copy(cur, new)
# 2. apply the changes to new
seen = ndbm.open(self._dbpath + '-new', 'c', 0o644)
for (key, value) in self._seen_new.items():
seen[key] = value
seen.close()
# 3. save current as old, and rename new to current
if os.path.isfile(old):
os.unlink(old)
if os.path.isfile(cur):
os.link(cur, old)
os.rename(new, cur)
def dump(self):
for key in sorted(self._seen.keys()):
value = self._seen[key]
print("%s %s" % (key.decode(), value.decode()))
def make_seen_db(config, readOnly = False):
if config.save_seen:
return seendb(config.save_seen, readOnly)
return seendb_dummy()
|