1 # Copyright (C) 2009, Thomas Leonard
2 # See the README file for details, or visit http://0install.net.
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')
16 """Ask the mainloop to recalculate. If we're already recalculating, wait for that to finish
17 and then do it again."""
19 _recalculate
.trigger()
20 _recalculate
= tasks
.Blocker('recalculate')
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
)
45 logger
= logging
.getLogger()
46 if options
.verbose
== 1:
47 logger
.setLevel(logging
.INFO
)
49 logger
.setLevel(logging
.DEBUG
)
52 # Must fork before importing gtk, or ATK dies
54 # We exit, so our parent can call waitpid and unblock.
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
)))
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.")
76 if gtk
.gdk
.get_display() is None:
77 print >>sys
.stderr
, "Failed to connect to display. Aborting."
80 if not hasattr(gtk
, 'combo_box_new_text'):
85 cache_explorer
= cache
.CacheExplorer()
87 cache_explorer
.window
.set_cursor(gtk
.gdk
.Cursor(gtk
.gdk
.WATCH
))
89 cache_explorer
.populate_model()
90 cache_explorer
.window
.set_cursor(None)
94 handler
= gui
.GUIHandler()
98 # Once we separate configuration from Policy, this hack can go away
99 class DummyPolicy(Policy
):
100 def recalculate(fetch_stale_interfaces
= True):
102 def solve_with_downloads(force
= False):
104 box
= preferences
.show_preferences(DummyPolicy('http://localhost/dummy', handler
))
105 box
.connect('destroy', gtk
.main_quit
)
109 interface_uri
= args
[0]
115 import mainwindow
, dialog
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
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())
142 window
.use_systray_icon()
146 force_refresh
= bool(options
.refresh
)
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
:
157 window
.refresh_button
.set_sensitive(True)
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():
165 window
.systray_icon
.set_tooltip(_('Downloading updates for %s') % root_iface
.get_name())
166 window
.run_button
.set_active(True)
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
:
178 handler
.wait_for_blocker(main())