Added update_local attribute to solve_with_downloads
[zeroinstall/zeroinstall-afb.git] / zeroinstall / 0launch-gui / main.py
blobb718aaa527338d44f7bcffcdf77b9894162f6216
1 # Copyright (C) 2009, Thomas Leonard
2 # See the README file for details, or visit http://0install.net.
4 import os, sys
6 from optparse import OptionParser
8 from zeroinstall.injector import model, arch
9 from zeroinstall.injector.policy import Policy
10 from zeroinstall.injector.iface_cache import iface_cache
11 from zeroinstall.support import tasks
13 _recalculate = tasks.Blocker('recalculate')
15 def recalculate():
16 """Ask the mainloop to recalculate. If we're already recalculating, wait for that to finish
17 and then do it again."""
18 global _recalculate
19 _recalculate.trigger()
20 _recalculate = tasks.Blocker('recalculate')
22 def run_gui(args):
23 parser = OptionParser(usage=_("usage: %prog [options] interface"))
24 parser.add_option("", "--before", help=_("choose a version before this"), metavar='VERSION')
25 parser.add_option("", "--cpu", help=_("target CPU type"), metavar='CPU')
26 parser.add_option("-c", "--cache", help=_("show the cache"), action='store_true')
27 parser.add_option("-d", "--download-only", help=_("fetch but don't run"), action='store_true')
28 parser.add_option("", "--message", help=_("message to display when interacting with user"))
29 parser.add_option("", "--not-before", help=_("minimum version to choose"), metavar='VERSION')
30 parser.add_option("", "--os", help=_("target operation system type"), metavar='OS')
31 parser.add_option("-r", "--refresh", help=_("check for updates of all interfaces"), action='store_true')
32 parser.add_option("", "--select-only", help=_("only download the feeds"), action='store_true')
33 parser.add_option("-s", "--source", help=_("select source code"), action='store_true')
34 parser.add_option("", "--systray", help=_("download in the background"), action='store_true')
35 parser.add_option("-v", "--verbose", help=_("more verbose output"), action='count')
36 parser.add_option("-V", "--version", help=_("display version information"), action='store_true')
37 parser.add_option("", "--with-store", help=_("add an implementation cache"), action='append', metavar='DIR')
39 parser.disable_interspersed_args()
41 (options, args) = parser.parse_args(args)
43 if options.verbose:
44 import logging
45 logger = logging.getLogger()
46 if options.verbose == 1:
47 logger.setLevel(logging.INFO)
48 else:
49 logger.setLevel(logging.DEBUG)
51 if options.cache:
52 # Must fork before importing gtk, or ATK dies
53 if os.fork():
54 # We exit, so our parent can call waitpid and unblock.
55 sys.exit(0)
56 # The grandchild continues...
58 if options.with_store:
59 from zeroinstall import zerostore
60 for x in options.with_store:
61 iface_cache.stores.stores.append(zerostore.Store(os.path.abspath(x)))
63 import gui
65 if options.version:
66 print "0launch-gui (zero-install) " + gui.version
67 print "Copyright (C) 2009 Thomas Leonard"
68 print _("This program comes with ABSOLUTELY NO WARRANTY,"
69 "\nto the extent permitted by law."
70 "\nYou may redistribute copies of this program"
71 "\nunder the terms of the GNU Lesser General Public License."
72 "\nFor more information about these matters, see the file named COPYING.")
73 sys.exit(0)
75 import gtk
76 if gtk.gdk.get_display() is None:
77 print >>sys.stderr, "Failed to connect to display. Aborting."
78 sys.exit(1)
80 if not hasattr(gtk, 'combo_box_new_text'):
81 import combo_compat
83 if options.cache:
84 import cache
85 cache_explorer = cache.CacheExplorer()
86 cache_explorer.show()
87 cache_explorer.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
88 gtk.gdk.flush()
89 cache_explorer.populate_model()
90 cache_explorer.window.set_cursor(None)
91 gtk.main()
92 sys.exit(0)
94 handler = gui.GUIHandler()
96 if len(args) < 1:
97 import preferences
98 # Once we separate configuration from Policy, this hack can go away
99 class DummyPolicy(Policy):
100 def recalculate(fetch_stale_interfaces = True):
101 pass
102 def solve_with_downloads(force = False):
103 pass
104 box = preferences.show_preferences(DummyPolicy('http://localhost/dummy', handler))
105 box.connect('destroy', gtk.main_quit)
106 gtk.main()
107 sys.exit(0)
109 interface_uri = args[0]
111 if len(args) > 1:
112 parser.print_help()
113 sys.exit(1)
115 import mainwindow, dialog
117 restrictions = []
118 if options.before or options.not_before:
119 restrictions.append(model.VersionRangeRestriction(model.parse_version(options.before),
120 model.parse_version(options.not_before)))
122 widgets = dialog.Template('main')
124 policy = Policy(interface_uri, handler, src = bool(options.source))
125 policy.target_arch = arch.get_architecture(options.os, options.cpu)
126 root_iface = iface_cache.get_interface(interface_uri)
127 policy.solver.extra_restrictions[root_iface] = restrictions
128 policy.solver.record_details = True
130 window = mainwindow.MainWindow(policy, widgets, download_only = bool(options.download_only), select_only = bool(options.select_only))
131 handler.mainwindow = window
133 if options.message:
134 window.set_message(options.message)
136 root = iface_cache.get_interface(policy.root)
137 window.browser.set_root(root)
139 window.window.connect('destroy', lambda w: handler.abort_all_downloads())
141 if options.systray:
142 window.use_systray_icon()
144 @tasks.async
145 def main():
146 force_refresh = bool(options.refresh)
147 while True:
148 window.refresh_button.set_sensitive(False)
149 window.browser.set_update_icons(force_refresh)
151 solved = policy.solve_with_downloads(force = force_refresh, update_local = True)
153 if not window.systray_icon:
154 window.show()
155 yield solved
156 try:
157 window.refresh_button.set_sensitive(True)
158 tasks.check(solved)
159 except Exception, ex:
160 window.report_exception(ex)
162 if window.systray_icon and window.systray_icon.get_visible() and \
163 window.systray_icon.is_embedded():
164 if policy.ready:
165 window.systray_icon.set_tooltip(_('Downloading updates for %s') % root_iface.get_name())
166 window.run_button.set_active(True)
167 else:
168 # Should already be reporting an error, but
169 # blink it again just in case
170 window.systray_icon.set_blinking(True)
172 refresh_clicked = dialog.ButtonClickedBlocker(window.refresh_button)
173 yield refresh_clicked, _recalculate
175 if refresh_clicked.happened:
176 force_refresh = True
178 handler.wait_for_blocker(main())