[yum-cvs] Makefile docs/Makefile docs/yum-updatesd.8 docs/yum-updatesd.conf.5 etc/Makefile etc/yum-updatesd.init yum-updatesd.py yum.spec
James Bowes
jbowes at linux.duke.edu
Mon Oct 1 12:21:57 UTC 2007
Makefile | 7
docs/Makefile | 2
docs/yum-updatesd.8 | 18 +
docs/yum-updatesd.conf.5 | 70 +++++
etc/Makefile | 10
etc/yum-updatesd.init | 63 ++++
yum-updatesd.py | 654 +++++++++++++++++++++++++++++++++++++++++++++++
yum.spec | 37 ++
8 files changed, 855 insertions(+), 6 deletions(-)
New commits:
commit a5ca701944afd5b870d8273752eafc0051993beb
Author: James Bowes <jbowes at redhat.com>
Date: Mon Oct 1 08:20:12 2007 -0400
Revert "Remove yum-updatesd, as it's a distinct project now."
yum-updatesd is still needed for F7.
This reverts commit bab47e934196b94a8afdca6d306806e46e73f4e3.
diff --git a/Makefile b/Makefile
index 9d9730b..62121e3 100644
--- a/Makefile
+++ b/Makefile
@@ -21,10 +21,12 @@ install:
for p in $(PYFILES) ; do \
install -m 644 $$p $(DESTDIR)/usr/share/yum-cli/$$p; \
done
+ mv $(DESTDIR)/usr/share/yum-cli/yum-updatesd.py $(DESTDIR)/usr/share/yum-cli/yumupd.py
$(PYTHON) -c "import compileall; compileall.compile_dir('$(DESTDIR)/usr/share/yum-cli', 1, '$(PYDIR)', 1)"
mkdir -p $(DESTDIR)/usr/bin $(DESTDIR)/usr/sbin
install -m 755 bin/yum.py $(DESTDIR)/usr/bin/yum
+ install -m 755 bin/yum-updatesd.py $(DESTDIR)/usr/sbin/yum-updatesd
mkdir -p $(DESTDIR)/var/cache/yum
mkdir -p $(DESTDIR)/var/lib/yum
@@ -34,8 +36,9 @@ install:
.PHONY: docs test
docs:
epydoc -n yum -o docs/epydoc -u http://linux.duke.edu/projects/yum \
- yum rpmUtils callback.py progress_meter.py yumcommands.py \
- shell.py translate.py output.py i18n.py cli.py yummain.py
+ yum yum-updatesd.py rpmUtils callback.py progress_meter.py \
+ yumcommands.py shell.py translate.py output.py i18n.py cli.py \
+ yummain.py
test:
python test/alltests.py
diff --git a/docs/Makefile b/docs/Makefile
index 1fc653f..379ba2b 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -10,3 +10,5 @@ install:
install -m 644 yum.8 $(DESTDIR)/usr/share/man/man8/yum.8
install -m 644 yum-shell.8 $(DESTDIR)/usr/share/man/man8/yum-shell.8
install -m 644 yum.conf.5 $(DESTDIR)/usr/share/man/man5/yum.conf.5
+ install -m 644 yum-updatesd.8 $(DESTDIR)/usr/share/man/man8/yum-updatesd.8
+ install -m 644 yum-updatesd.conf.5 $(DESTDIR)/usr/share/man/man5/yum-updatesd.conf.5
diff --git a/docs/yum-updatesd.8 b/docs/yum-updatesd.8
new file mode 100644
index 0000000..be0d346
--- /dev/null
+++ b/docs/yum-updatesd.8
@@ -0,0 +1,18 @@
+.TH "yum-updatesd" "8" "" "Jeremy Katz" ""
+.SH "NAME"
+yum-updatesd \- Update notifier daemon
+.SH "SYNOPSIS"
+\fByum-updatesd\fP
+.SH "DESCRIPTION"
+.PP
+\fByum-updatesd\fP provides notification of updates which are
+available to be applied to your system. This notification can be done
+either via syslog, email or over dbus. Configuration is done via the
+\fByum-updatesd.conf(5) \fR file.
+.PP
+.SH "SEE ALSO"
+.nf
+.I yum(8)
+.I yum-updatesd.conf(5)
+http://linux.duke.edu/yum/
+.fi
diff --git a/docs/yum-updatesd.conf.5 b/docs/yum-updatesd.conf.5
new file mode 100644
index 0000000..ee6e7aa
--- /dev/null
+++ b/docs/yum-updatesd.conf.5
@@ -0,0 +1,70 @@
+.TH "yum-updatesd.conf" "5" "" "Jeremy Katz" "yum-updatesd configuration file"
+.SH "NAME"
+.LP
+\fByum-updatesd.conf\fR \- Configuration file for \fByum-updatesd(8)\fR.
+.SH "DESCRIPTION"
+.LP
+yum-updatesd uses a configuration file at \fB/etc/yum/yum-updatesd.conf\fR.
+.LP
+Additional configuration information is read from the main \fByum.conf
+(5)\fR configuration file.
+
+.SH "PARAMETERS"
+.LP
+There is one section in the yum-updatesd configuration file, main,
+which defines all of the global configuration options.
+
+.SH "[main] OPTIONS"
+.LP
+The [main] section must exist for yum-updatesd to do anything. It
+consists of the following options:
+
+.IP \fBrun_interval\fR
+Number of seconds to wait between checks for available updates.
+
+.IP \fBupdaterefresh\fR
+Minimum number of seconds between update information refreshes to
+avoid hitting the server too often.
+
+.IP \fBemit_via\fR
+List of ways to emit update notification. Valid values are `email',
+`dbus' and `syslog'.
+
+.IP \fBdo_update\fR
+Boolean option to decide whether or not updates should be
+automatically applied. Defaults to False.
+
+.IP \fBdo_download_deps\fR
+Boolean option to decide whether or not updates should be
+automatically downloaded. Defaults to False.
+
+.IP \fBdo_download_deps\fR
+Boolean option to automatically download dependencies of packages which need
+updating as well. Defaults to False.
+
+.SH "MAIL OPTIONS"
+.IP \fBemail_to\fR
+List of email addresses to send update notification to. Defaults to
+`root at localhost'.
+
+.IP \fBemail_from\fR
+Email address for update notifications to be from. Defaults to
+`yum-updatesd at localhost'.
+
+.SH "SYSLOG OPTIONS"
+.IP \fBsyslog_facility\fR
+What syslog facility should be used. Defaults to `DAEMON'.
+
+.IP \fBsyslog_level\fR
+Level of syslog messages. Defaults to `WARN'.
+
+
+.SH "FILES"
+.nf
+/etc/yum/yum-updatesd.conf
+
+.SH "SEE ALSO"
+.LP
+yum-updatesd(8)
+yum.conf(5)
+
diff --git a/etc/Makefile b/etc/Makefile
index 7124035..1ba5a1f 100644
--- a/etc/Makefile
+++ b/etc/Makefile
@@ -12,3 +12,13 @@ install:
mkdir -p $(DESTDIR)/etc/logrotate.d
install -m 644 yum.logrotate $(DESTDIR)/etc/logrotate.d/yum
+
+ mkdir -p $(DESTDIR)/etc/rc.d/init.d
+ install -m 755 yum-updatesd.init $(DESTDIR)/etc/rc.d/init.d/yum-updatesd
+
+ mkdir -p $(DESTDIR)/etc/dbus-1/system.d/
+ install -m 755 yum-updatesd-dbus.conf $(DESTDIR)/etc/dbus-1/system.d/yum-updatesd.conf
+
+ install -m 755 yum-updatesd.conf $(DESTDIR)/etc/yum/yum-updatesd.conf
+
+
diff --git a/etc/yum-updatesd.init b/etc/yum-updatesd.init
new file mode 100755
index 0000000..55f166d
--- /dev/null
+++ b/etc/yum-updatesd.init
@@ -0,0 +1,63 @@
+#!/bin/bash
+#
+# yum This shell script enables the yum-updates daemon
+#
+# Author: Jeremy Katz <katzj at redhat.com>
+#
+# chkconfig: 345 97 03
+#
+# description: This is a daemon which periodically checks for updates \
+# and can send notifications via mail, dbus or syslog.
+# processname: yum-updatesd
+# config: /etc/yum/yum-updatesd.conf
+# pidfile: /var/run/yum-updatesd.pid
+#
+
+# source function library
+. /etc/rc.d/init.d/functions
+
+RETVAL=0
+
+start() {
+ echo -n $"Starting yum-updatesd: "
+ daemon +19 yum-updatesd
+ RETVAL=$?
+ echo
+ [ $RETVAL -eq 0 ] && touch /var/lock/subsys/yum-updatesd
+}
+
+stop() {
+ echo -n $"Stopping yum-updatesd: "
+ killproc yum-updatesd
+ echo
+ [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/yum-updatesd
+}
+
+restart() {
+ stop
+ start
+}
+
+case "$1" in
+ start)
+ start
+ ;;
+ stop)
+ stop
+ ;;
+ restart|force-reload|reload)
+ restart
+ ;;
+ condrestart)
+ [ -f /var/lock/subsys/yum-updatesd ] && restart
+ ;;
+ status)
+ status yum-updatesd
+ RETVAL=$?
+ ;;
+ *)
+ echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}"
+ exit 1
+esac
+
+exit $RETVAL
diff --git a/yum-updatesd.py b/yum-updatesd.py
new file mode 100644
index 0000000..ac05f2b
--- /dev/null
+++ b/yum-updatesd.py
@@ -0,0 +1,654 @@
+#!/usr/bin/python -tt
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# (c)2006 Duke University, Red Hat, Inc.
+# Seth Vidal <skvidal at linux.duke.edu>
+# Jeremy Katz <katzj at redhat.com>
+
+#TODO:
+# - clean up config and work on man page for docs
+# - need to be able to cancel downloads. requires some work in urlgrabber
+# - what to do if we're asked to exit while updates are being applied?
+# - what to do with the lock around downloads/updates
+
+# since it takes me time everytime to figure this out again, here's how to
+# queue a check with dbus-send. adjust appropriately for other methods
+# $ dbus-send --system --print-reply --type=method_call \
+# --dest=edu.duke.linux.yum /Updatesd edu.duke.linux.yum.CheckNow
+
+import gettext
+import os
+import sys
+import time
+import gzip
+import dbus
+import dbus.service
+import dbus.glib
+import gobject
+import smtplib
+import threading
+from optparse import OptionParser
+from email.MIMEText import MIMEText
+
+
+
+import yum
+import yum.Errors
+import syslog
+from yum.config import BaseConfig, Option, IntOption, ListOption, BoolOption
+from yum.parser import ConfigPreProcessor
+from ConfigParser import ConfigParser, ParsingError
+from yum.constants import *
+from yum.update_md import UpdateMetadata
+
+# FIXME: is it really sane to use this from here?
+sys.path.append('/usr/share/yum-cli')
+import callback
+
+config_file = '/etc/yum/yum-updatesd.conf'
+initial_directory = os.getcwd()
+
+class UpdateEmitter(object):
+ """Abstract object for implementing different types of emitters."""
+ def __init__(self):
+ pass
+ def updatesAvailable(self, updateInfo):
+ """Emitted when there are updates available to be installed.
+ If not doing the download here, then called immediately on finding
+ new updates. If we do the download here, then called after the
+ updates have been downloaded."""
+ pass
+ def updatesDownloading(self, updateInfo):
+ """Emitted to give feedback of update download starting."""
+ pass
+ def updatesApplied(self, updateInfo):
+ """Emitted on successful installation of updates."""
+ pass
+ def updatesFailed(self, errmsgs):
+ """Emitted when an update has failed to install."""
+ pass
+ def checkFailed(self, error):
+ """Emitted when checking for updates failed."""
+ pass
+
+ def setupFailed(self, error, translation_domain):
+ """Emitted when plugin initialization failed."""
+ pass
+
+
+class SyslogUpdateEmitter(UpdateEmitter):
+ def __init__(self, syslog_facility, ident = "yum-updatesd",
+ level = "WARN"):
+ UpdateEmitter.__init__(self)
+ syslog.openlog(ident, 0, self._facilityMap(syslog_facility))
+ self.level = level
+
+ def updatesAvailable(self, updateInfo):
+ num = len(updateInfo)
+ level = self.level
+ if num > 1:
+ msg = "%d updates available" %(num,)
+ elif num == 1:
+ msg = "1 update available"
+ else:
+ msg = "No updates available"
+ level = syslog.LOG_DEBUG
+
+ syslog.syslog(self._levelMap(level), msg)
+
+ def _levelMap(self, lvl):
+ level_map = { "EMERG": syslog.LOG_EMERG,
+ "ALERT": syslog.LOG_ALERT,
+ "CRIT": syslog.LOG_CRIT,
+ "ERR": syslog.LOG_ERR,
+ "WARN": syslog.LOG_WARNING,
+ "NOTICE": syslog.LOG_NOTICE,
+ "INFO": syslog.LOG_INFO,
+ "DEBUG": syslog.LOG_DEBUG }
+ if type(lvl) == int:
+ return lvl
+ if level_map.has_key(lvl.upper()):
+ return level_map[lvl.upper()]
+ return syslog.LOG_INFO
+
+ def _facilityMap(self, facility):
+ facility_map = { "KERN": syslog.LOG_KERN,
+ "USER": syslog.LOG_USER,
+ "MAIL": syslog.LOG_MAIL,
+ "DAEMON": syslog.LOG_DAEMON,
+ "AUTH": syslog.LOG_AUTH,
+ "LPR": syslog.LOG_LPR,
+ "NEWS": syslog.LOG_NEWS,
+ "UUCP": syslog.LOG_UUCP,
+ "CRON": syslog.LOG_CRON,
+ "LOCAL0": syslog.LOG_LOCAL0,
+ "LOCAL1": syslog.LOG_LOCAL1,
+ "LOCAL2": syslog.LOG_LOCAL2,
+ "LOCAL3": syslog.LOG_LOCAL3,
+ "LOCAL4": syslog.LOG_LOCAL4,
+ "LOCAL5": syslog.LOG_LOCAL5,
+ "LOCAL6": syslog.LOG_LOCAL6,
+ "LOCAL7": syslog.LOG_LOCAL7,}
+ if type(facility) == int:
+ return facility
+ elif facility_map.has_key(facility.upper()):
+ return facility_map[facility.upper()]
+ return syslog.LOG_DAEMON
+
+
+class EmailUpdateEmitter(UpdateEmitter):
+ def __init__(self, sender, rcpt):
+ UpdateEmitter.__init__(self)
+ self.sender = sender
+ self.rcpt = rcpt
+
+ def updatesAvailable(self, updateInfo):
+ num = len(updateInfo)
+ if num < 1:
+ return
+
+ output = """
+ Hi,
+ There are %d package updates available. Please run the system
+ updater.
+
+ Thank You,
+ Your Computer
+ """ % num
+
+ msg = MIMEText(output)
+ msg['Subject'] = "%d Updates Available" %(num,)
+ msg['From'] = self.sender
+ msg['To'] = ",".join(self.rcpt)
+ s = smtplib.SMTP()
+ s.connect()
+ s.sendmail(self.sender, self.rcpt, msg.as_string())
+ s.close()
+
+class DbusUpdateEmitter(UpdateEmitter):
+ def __init__(self):
+ UpdateEmitter.__init__(self)
+ bus = dbus.SystemBus()
+ name = dbus.service.BusName('edu.duke.linux.yum', bus = bus)
+ yum_dbus = YumDbusInterface(name)
+ self.dbusintf = yum_dbus
+
+ def updatesAvailable(self, updateInfo):
+ num = len(updateInfo)
+ msg = "%d" %(num,)
+ if num > 0:
+ self.dbusintf.UpdatesAvailableSignal(msg)
+ else:
+ self.dbusintf.NoUpdatesAvailableSignal(msg)
+
+ def updatesFailed(self, errmsgs):
+ self.dbusintf.UpdatesFailedSignal(errmsgs)
+
+ def updatesApplied(self, updinfo):
+ self.dbusintf.UpdatesAppliedSignal(updinfo)
+
+ def checkFailed(self, error):
+ self.dbusintf.CheckFailedSignal(error)
+
+ def setupFailed(self, error, translation_domain):
+ self.dbusintf.SetupFailedSignal(error, translation_domain)
+
+
+class YumDbusInterface(dbus.service.Object):
+ def __init__(self, bus_name, object_path='/UpdatesAvail'):
+ dbus.service.Object.__init__(self, bus_name, object_path)
+
+ @dbus.service.signal('edu.duke.linux.yum')
+ def UpdatesAvailableSignal(self, message):
+ pass
+
+ @dbus.service.signal('edu.duke.linux.yum')
+ def NoUpdatesAvailableSignal(self, message):
+ pass
+
+ @dbus.service.signal('edu.duke.linux.yum')
+ def UpdatesFailedSignal(self, errmsgs):
+ pass
+
+ @dbus.service.signal('edu.duke.linux.yum')
+ def UpdatesAppliedSignal(self, updinfo):
+ pass
+
+ @dbus.service.signal('edu.duke.linux.yum')
+ def CheckFailedSignal(self, message):
+ pass
+
+ @dbus.service.signal('edu.duke.linux.yum')
+ def SetupFailedSignal(self, message, translation_domain=""):
+ pass
+
+
+class UDConfig(BaseConfig):
+ """Config format for the daemon"""
+ run_interval = IntOption(3600)
+ nonroot_workdir = Option("/var/tmp/yum-updatesd")
+ emit_via = ListOption(['dbus', 'email', 'syslog'])
+ email_to = ListOption(["root"])
+ email_from = Option("root")
+ dbus_listener = BoolOption(True)
+ do_update = BoolOption(False)
+ do_download = BoolOption(False)
+ do_download_deps = BoolOption(False)
+ updaterefresh = IntOption(3600)
+ syslog_facility = Option("DAEMON")
+ syslog_level = Option("WARN")
+ syslog_ident = Option("yum-updatesd")
+ yum_config = Option("/etc/yum/yum.conf")
+
+
+class UpdateBuildTransactionThread(threading.Thread):
+ def __init__(self, updd, name):
+ self.updd = updd
+ threading.Thread.__init__(self, name=name)
+
+ def run(self):
+ self.updd.tsInfo.makelists()
+ try:
+ (result, msgs) = self.updd.buildTransaction()
+ except yum.Errors.RepoError, errmsg: # error downloading hdrs
+ msgs = ["Error downloading headers"]
+ self.updd.emitUpdateFailed(msgs)
+ return
+
+ dlpkgs = map(lambda x: x.po, filter(lambda txmbr:
+ txmbr.ts_state in ("i", "u"),
+ self.updd.tsInfo.getMembers()))
+ self.updd.downloadPkgs(dlpkgs)
+ self.processPkgs(dlpkgs)
+
+
+class UpdateDownloadThread(UpdateBuildTransactionThread):
+ def __init__(self, updd):
+ UpdateBuildTransactionThread.__init__(self, updd,
+ name="UpdateDownloadThread")
+
+ def processPkgs(self, dlpkgs):
+ self.updd.emitAvailable()
+ self.updd.releaseLocks()
+
+
+class UpdateInstallThread(UpdateBuildTransactionThread):
+ def __init__(self, updd):
+ UpdateBuildTransactionThread.__init__(self, updd,
+ name="UpdateInstallThread")
+
+ def failed(self, msgs):
+ self.updd.emitUpdateFailed(msgs)
+ self.updd.releaseLocks()
+
+ def success(self):
+ self.updd.emitUpdateApplied()
+ self.updd.releaseLocks()
+
+ self.updd.updateInfo = None
+ self.updd.updateInfoTime = None
+
+ def processPkgs(self, dlpkgs):
+ for po in dlpkgs:
+ result, err = self.updd.sigCheckPkg(po)
+ if result == 0:
+ continue
+ elif result == 1:
+ try:
+ self.updd.getKeyForPackage(po)
+ except yum.Errors.YumBaseError, errmsg:
+ self.failed([str(errmsg)])
+
+ del self.updd.ts
+ self.updd.initActionTs() # make a new, blank ts to populate
+ self.updd.populateTs(keepold=0)
+ self.updd.ts.check() #required for ordering
+ self.updd.ts.order() # order
+ cb = callback.RPMInstallCallback(output = 0)
+ cb.filelog = True
+
+ cb.tsInfo = self.updd.tsInfo
+ try:
+ self.updd.runTransaction(cb=cb)
+ except yum.Errors.YumBaseError, err:
+ self.failed([str(err)])
+
+ self.success()
+
+class UpdatesDaemon(yum.YumBase):
+ def __init__(self, opts):
+ yum.YumBase.__init__(self)
+ self.opts = opts
+ self.didSetup = False
+
+ self.emitters = []
+ if 'dbus' in self.opts.emit_via:
+ self.emitters.append(DbusUpdateEmitter())
+ if 'email' in self.opts.emit_via:
+ self.emitters.append(EmailUpdateEmitter(self.opts.email_from,
+ self.opts.email_to))
+ if 'syslog' in self.opts.emit_via:
+ self.emitters.append(SyslogUpdateEmitter(self.opts.syslog_facility,
+ self.opts.syslog_ident,
+ self.opts.syslog_level))
+
+ self.updateInfo = []
+ self.updateInfoTime = None
+
+ def doSetup(self):
+ # if we are not root do the special subdir thing
+ if os.geteuid() != 0:
+ if not os.path.exists(self.opts.nonroot_workdir):
+ os.makedirs(self.opts.nonroot_workdir)
+ self.repos.setCacheDir(self.opts.nonroot_workdir)
+
+ self.doConfigSetup(fn=self.opts.yum_config)
+
+ def refreshUpdates(self):
+ self.doLock()
+ try:
+ self.doRepoSetup()
+ self.doSackSetup()
+ self.updateCheckSetup()
+ except Exception, e:
+ syslog.syslog(syslog.LOG_WARNING,
+ "error getting update info: %s" %(e,))
+ self.emitCheckFailed("%s" %(e,))
+ self.doUnlock()
+ return False
+ return True
+
+ def populateUpdateMetadata(self):
+ self.updateMetadata = UpdateMetadata()
+ repos = []
+
+ for (new, old) in self.up.getUpdatesTuples():
+ pkg = self.getPackageObject(new)
+ if pkg.repoid not in repos:
+ repo = self.repos.getRepo(pkg.repoid)
+ repos.append(repo.id)
+ try: # grab the updateinfo.xml.gz from the repodata
+ md = repo.retrieveMD('updateinfo')
+ except Exception: # can't find any; silently move on
+ continue
+ md = gzip.open(md)
+ self.updateMetadata.add(md)
+ md.close()
+
+ def populateUpdates(self):
+ def getDbusPackageDict(pkg):
+ """Returns a dictionary corresponding to the package object
+ in the form that we can send over the wire for dbus."""
+ pkgDict = {
+ "name": pkg.name,
+ "version": pkg.version,
+ "release": pkg.release,
+ "epoch": pkg.epoch,
+ "arch": pkg.arch,
+ "sourcerpm": pkg.sourcerpm,
+ "summary": pkg.summary or "",
+ }
+
+ # check if any updateinfo is available
+ md = self.updateMetadata.get_notice((pkg.name, pkg.ver, pkg.rel))
+ if md:
+ # right now we only want to know if it is a security update
+ pkgDict['type'] = md['type']
+
+ return pkgDict
+
+ if self.up is None:
+ # we're _only_ called after updates are setup
+ return
+
+ self.populateUpdateMetadata()
+
+ self.updateInfo = []
+ for (new, old) in self.up.getUpdatesTuples():
+ n = getDbusPackageDict(self.getPackageObject(new))
+ o = getDbusPackageDict(self.rpmdb.searchPkgTuple(old)[0])
+ self.updateInfo.append((n, o))
+
+ if self.conf.obsoletes:
+ for (obs, inst) in self.up.getObsoletesTuples():
+ n = getDbusPackageDict(self.getPackageObject(obs))
+ o = getDbusPackageDict(self.rpmdb.searchPkgTuple(inst)[0])
+ self.updateInfo.append((n, o))
+
+ self.updateInfoTime = time.time()
+
+ def populateTsInfo(self):
+ # figure out the updates
+ for (new, old) in self.up.getUpdatesTuples():
+ updating = self.getPackageObject(new)
+ updated = self.rpmdb.searchPkgTuple(old)[0]
+
+ self.tsInfo.addUpdate(updating, updated)
+
+ # and the obsoletes
+ if self.conf.obsoletes:
+ for (obs, inst) in self.up.getObsoletesTuples():
+ obsoleting = self.getPackageObject(obs)
+ installed = self.rpmdb.searchPkgTuple(inst)[0]
+
+ self.tsInfo.addObsoleting(obsoleting, installed)
+ self.tsInfo.addObsoleted(installed, obsoleting)
+
+ def updatesCheck(self):
+ if not self.didSetup:
+ try:
+ self.doSetup()
+ except Exception, e:
+ syslog.syslog(syslog.LOG_WARNING,
+ "error initializing: %s" % e)
+
+ if isinstance(e, yum.plugins.PluginYumExit):
+ self.emitSetupFailed(e.value, e.translation_domain)
+ else:
+ # if we don't know where the string is from, then assume
+ # it's not marked for translation (versus sending
+ # gettext.textdomain() and assuming it's from the default
+ # domain for this app)
+ self.emitSetupFailed(str(e))
+ # Setup failed, let's restart and try again after the update
+ # interval
+ restart()
+ else:
+ self.didSetup = True
+
+ try:
+ if not self.refreshUpdates():
+ return
+ except yum.Errors.LockError:
+ return True # just pass for now
+
+ try:
+ self.populateTsInfo()
+ self.populateUpdates()
+
+ if self.opts.do_update:
+ uit = UpdateInstallThread(self)
+ uit.start()
+ elif self.opts.do_download:
+ self.emitDownloading()
+ dl = UpdateDownloadThread(self)
+ dl.start()
+ else:
+ # just notify about things being available
+ self.emitAvailable()
+ self.releaseLocks()
+ except Exception, e:
+ self.emitCheckFailed("%s" %(e,))
+ self.doUnlock()
+
+ return True
+
+ def getUpdateInfo(self):
+ # if we have a cached copy, use it
+ if self.updateInfoTime and (time.time() - self.updateInfoTime <
+ self.opts.updaterefresh):
+ return self.updateInfo
+
+ # try to get the lock so we can update the info. fall back to
+ # cached if available or try a few times.
+ for i in range(10):
+ try:
+ self.doLock()
+ break
+ except yum.Errors.LockError:
+ # if we can't get the lock, return what we have if we can
+ if self.updateInfo:
+ return self.updateInfo
+ time.sleep(1)
+ else:
+ return []
+
+ try:
+ self.updateCheckSetup()
+
+ self.populateUpdates()
+
+ self.releaseLocks()
+ except:
+ self.doUnlock()
+
+ return self.updateInfo
+
+ def updateCheckSetup(self):
+ self.doTsSetup()
+ self.doRpmDBSetup()
+ self.doUpdateSetup()
+
+ def releaseLocks(self):
+ self.closeRpmDB()
+ self.doUnlock()
+
+ def emitAvailable(self):
+ """method to emit a notice about updates"""
+ map(lambda x: x.updatesAvailable(self.updateInfo), self.emitters)
+
+ def emitDownloading(self):
+ """method to emit a notice about updates downloading"""
+ map(lambda x: x.updatesDownloading(self.updateInfo), self.emitters)
+
+ def emitUpdateApplied(self):
+ """method to emit a notice when automatic updates applied"""
+ map(lambda x: x.updatesApplied(self.updateInfo), self.emitters)
+
+ def emitUpdateFailed(self, errmsgs):
+ """method to emit a notice when automatic updates failed"""
+ map(lambda x: x.updatesFailed(errmsgs), self.emitters)
+
+ def emitCheckFailed(self, error):
+ """method to emit a notice when checking for updates failed"""
+ map(lambda x: x.checkFailed(error), self.emitters)
+
+ def emitSetupFailed(self, error, translation_domain=""):
+ """method to emit a notice when checking for updates failed"""
+ map(lambda x: x.setupFailed(error, translation_domain), self.emitters)
+
+
+class YumDbusListener(dbus.service.Object):
+ def __init__(self, updd, bus_name, object_path='/Updatesd',
+ allowshutdown = False):
+ dbus.service.Object.__init__(self, bus_name, object_path)
+ self.updd = updd
+ self.allowshutdown = allowshutdown
+
+ def doCheck(self):
+ self.updd.updatesCheck()
+ return False
+
+ @dbus.service.method("edu.duke.linux.yum", in_signature="")
+ def CheckNow(self):
+ # make updating checking asynchronous since we discover whether
+ # or not there are updates via a callback signal anyway
+ gobject.idle_add(self.doCheck)
+ return "check queued"
+
+ @dbus.service.method("edu.duke.linux.yum", in_signature="")
+ def ShutDown(self):
+ if not self.allowshutdown:
+ return False
+
+ # we have to do this in a callback so that it doesn't get
+ # sent back to the caller
+ gobject.idle_add(shutDown)
+ return True
+
+ @dbus.service.method("edu.duke.linux.yum", in_signature="", out_signature="a(a{ss}a{ss})")
+ def GetUpdateInfo(self):
+ # FIXME: should this be async?
+ upds = self.updd.getUpdateInfo()
+ return upds
+
+
+def shutDown():
+ sys.exit(0)
+
+def restart():
+ os.chdir(initial_directory)
+ os.execve(sys.argv[0], sys.argv, os.environ)
+
+def main(options = None):
+ # we'll be threading for downloads/updates
+ gobject.threads_init()
+ dbus.glib.threads_init()
+
+ if options is None:
+ parser = OptionParser()
+ parser.add_option("-f", "--no-fork", action="store_true", default=False, dest="nofork")
+ parser.add_option("-r", "--remote-shutdown", action="store_true", default=False, dest="remoteshutdown")
+ (options, args) = parser.parse_args()
+
+ if not options.nofork:
+ if os.fork():
+ sys.exit()
+ fd = os.open("/dev/null", os.O_RDWR)
+ os.dup2(fd, 0)
+ os.dup2(fd, 1)
+ os.dup2(fd, 2)
+ os.close(fd)
+
+ confparser = ConfigParser()
+ opts = UDConfig()
+
+ if os.path.exists(config_file):
+ confpp_obj = ConfigPreProcessor(config_file)
+ try:
+ confparser.readfp(confpp_obj)
+ except ParsingError, e:
+ print >> sys.stderr, "Error reading config file: %s" % e
+ sys.exit(1)
+
+ syslog.openlog("yum-updatesd", 0, syslog.LOG_DAEMON)
+
+ opts.populate(confparser, 'main')
+ updd = UpdatesDaemon(opts)
+
+ if opts.dbus_listener:
+ bus = dbus.SystemBus()
+ name = dbus.service.BusName("edu.duke.linux.yum", bus=bus)
+ YumDbusListener(updd, name, allowshutdown = options.remoteshutdown)
+
+ run_interval_ms = opts.run_interval * 1000 # needs to be in ms
+ gobject.timeout_add(run_interval_ms, updd.updatesCheck)
+
+ mainloop = gobject.MainLoop()
+ mainloop.run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/yum.spec b/yum.spec
index c5406f8..f65248e 100644
--- a/yum.spec
+++ b/yum.spec
@@ -1,7 +1,7 @@
Summary: RPM installer/updater
Name: yum
Version: 3.2.5
-Release: 2
+Release: 1
License: GPL
Group: System Environment/Base
Source: %{name}-%{version}.tar.gz
@@ -25,6 +25,19 @@ Yum is a utility that can check for and automatically download and
install updated RPM packages. Dependencies are obtained and downloaded
automatically prompting the user as necessary.
+%package updatesd
+Summary: Update notification daemon
+Group: Applications/System
+Requires: yum = %{version}-%{release}
+Requires: dbus-python
+Requires: pygobject2
+Prereq: /sbin/chkconfig
+Prereq: /sbin/service
+
+%description updatesd
+yum-updatesd provides a daemon which checks for available updates and
+can notify you when they are available via email, syslog or dbus.
+
%prep
%setup -q
@@ -42,6 +55,18 @@ make DESTDIR=$RPM_BUILD_ROOT install
[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
+%post updatesd
+/sbin/chkconfig --add yum-updatesd
+/sbin/service yum-updatesd condrestart >/dev/null 2>&1
+exit 0
+
+%preun updatesd
+if [ $1 = 0 ]; then
+ /sbin/chkconfig --del yum-updatesd
+ /sbin/service yum-updatesd stop >/dev/null 2>&1
+fi
+exit 0
+
%files
%defattr(-, root, root)
%doc README AUTHORS COPYING TODO INSTALL ChangeLog PLUGINS
@@ -58,11 +83,15 @@ make DESTDIR=$RPM_BUILD_ROOT install
%{_mandir}/man*/yum.*
%{_mandir}/man*/yum-shell*
+%files updatesd
+%defattr(-, root, root)
+%config(noreplace) %{_sysconfdir}/yum/yum-updatesd.conf
+%config %{_sysconfdir}/rc.d/init.d/yum-updatesd
+%config %{_sysconfdir}/dbus-1/system.d/yum-updatesd.conf
+%{_sbindir}/yum-updatesd
+%{_mandir}/man*/yum-updatesd*
%changelog
-* Sun Sep 30 2007 James Bowes <jbowes at redhat.com> 3.2.5-2
-- remove yum-updatesd (it's external now)
-
* Mon Sep 10 2007 Seth Vidal <skvidal at fedoraproject.org>
- 3.2.5
More information about the Yum-cvs-commits
mailing list