use git-archive instead for creating the archive
[yum-updatesd.git] / yumd
1 #!/usr/bin/python -tt
2 #
3 # Proof of concept yumd implementation
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of version 2 of the GNU General Public License
7 # as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 #
18 # Copyright 2007 Red Hat, Inc.
19 # Jeremy Katz <katzj@redhat.com>
20 #
21 # since it takes me time everytime to figure this out again, here's how to
22 # queue a check with dbus-send.  adjust appropriately for other methods
23 # $ dbus-send --system --print-reply --type=method_call \
24 #   --dest=edu.duke.linux.yum /Updatesd edu.duke.linux.yum.CheckNow
25
26 import os, sys
27 import syslog
28 import subprocess
29 import time
30
31 from optparse import OptionParser
32
33 import dbus
34 import dbus.service
35 import dbus.glib
36 import gobject
37
38 sys.path.append('/usr/share/yum-updatesd')
39 import yumdconfig
40
41 updateInfoDone = False
42 updateInfo = []
43 helperProcess = None
44
45 class YumDbusListener(dbus.service.Object):
46     def __init__(self, bus_name, object_path='/Updatesd',
47                  allowshutdown = False, config = None):
48         dbus.service.Object.__init__(self, bus_name, object_path)
49         self.allowshutdown = allowshutdown
50         self.yumdconfig = config
51
52     def doCheck(self):
53         checkUpdates(self.yumdconfig)
54         return False
55
56     @dbus.service.method("edu.duke.linux.yum", in_signature="")
57     def CheckNow(self):
58         # make updating checking asynchronous since we discover whether
59         # or not there are updates via a callback signal anyway
60         gobject.idle_add(self.doCheck)
61         return "check queued"
62
63     @dbus.service.method("edu.duke.linux.yum", in_signature="")
64     def ShutDown(self):
65         if not self.allowshutdown:
66             return False
67         
68         # we have to do this in a callback so that it doesn't get
69         # sent back to the caller
70         gobject.idle_add(shutDown)
71         return True
72
73     @dbus.service.method("edu.duke.linux.yum", in_signature="", out_signature="a(a{ss}a{ss})")
74     def GetUpdateInfo(self):
75         # FIXME: this call is deprecated.  things should watch for the update
76         # info signals
77         global updateInfoDone, updateInfo
78
79         if not updateInfoDone:
80             # FIXME: this isn't synchronous anymore.  but it should be
81             # reasonable enough given the users
82             gobject.idle_add(checkUpdates)
83             return []
84
85         return updateInfo
86
87 def shutDown():
88     sys.exit(0)
89
90 def restart():
91     os.chdir(initial_directory)
92     os.execve(sys.argv[0], sys.argv, os.environ)
93
94 def checkHelperStatus():
95     global helperProcess
96     if helperProcess.poll() is not None:
97         helperProcess = None
98         return False
99     return True
100
101 def checkUpdates(opts):
102     global helperProcess
103     if helperProcess is not None:
104         print >> sys.stderr, "Helper process already running"
105         return
106     args = ["./yum-updatesd-helper", "--check"]
107     if opts.do_download:
108         args.append("--download")
109     if opts.do_download_deps:
110         args.append("--deps")
111     if opts.do_update:
112         args.append("--apply")
113     if opts.debug:
114         args.append("--debug")
115     helperProcess = subprocess.Popen(args, close_fds = True)
116     gobject.timeout_add(4 * 1000, checkHelperStatus)
117
118 def add_update(update):
119     global updateInfo, updateInfoDone
120     if updateInfoDone:
121         updateInfo = []
122         updateInfoDone = False
123     updateInfo.append(update)
124
125 def updates_done(num):
126     global updateInfoDone, updateInfo
127     # if we received all the updates, we're good.  otherwise, we need to
128     # clear the info out
129     if int(num) != len(updateInfo):
130         updateInfo = []
131     else:
132         updateInfoDone = True
133
134 def main(options = None):
135     if options is None:
136         parser = OptionParser()
137         parser.add_option("-f", "--no-fork", action="store_true", default=False, dest="nofork")
138         parser.add_option("-r", "--remote-shutdown", action="store_true", default=False, dest="remoteshutdown")    
139         (options, args) = parser.parse_args()
140
141         if not options.nofork:
142             if os.fork():
143                 sys.exit()
144             fd = os.open("/dev/null", os.O_RDWR)
145             os.dup2(fd, 0)
146             os.dup2(fd, 1)
147             os.dup2(fd, 2)
148             os.close(fd)
149
150     syslog.openlog("yum-updatesd", 0, syslog.LOG_DAEMON)
151
152     opts = yumdconfig.read_config()
153
154     if opts.dbus_listener:
155         bus = dbus.SystemBus()
156         name = dbus.service.BusName("edu.duke.linux.yum", bus=bus)
157         YumDbusListener(name, allowshutdown = options.remoteshutdown,
158                         config = opts)
159
160         bus.add_signal_receiver(add_update, "UpdateInfoSignal", dbus_interface="edu.duke.linux.yum")
161         bus.add_signal_receiver(updates_done, "UpdatesAvailableSignal", dbus_interface="edu.duke.linux.yum")        
162     
163     run_interval_ms = opts.run_interval * 1000 # needs to be in ms
164     gobject.timeout_add(run_interval_ms, checkUpdates)
165
166     mainloop = gobject.MainLoop()
167     mainloop.run()
168
169
170 if __name__ == "__main__":
171     main()