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("", "--command", help=_("command to select"), metavar
='COMMAND')
28 parser
.add_option("-d", "--download-only", help=_("fetch but don't run"), action
='store_true')
29 parser
.add_option("", "--message", help=_("message to display when interacting with user"))
30 parser
.add_option("", "--not-before", help=_("minimum version to choose"), metavar
='VERSION')
31 parser
.add_option("", "--os", help=_("target operation system type"), metavar
='OS')
32 parser
.add_option("-r", "--refresh", help=_("check for updates of all interfaces"), action
='store_true')
33 parser
.add_option("", "--select-only", help=_("only download the feeds"), action
='store_true')
34 parser
.add_option("-s", "--source", help=_("select source code"), action
='store_true')
35 parser
.add_option("", "--systray", help=_("download in the background"), action
='store_true')
36 parser
.add_option("-v", "--verbose", help=_("more verbose output"), action
='count')
37 parser
.add_option("-V", "--version", help=_("display version information"), action
='store_true')
38 parser
.add_option("", "--with-store", help=_("add an implementation cache"), action
='append', metavar
='DIR')
40 parser
.disable_interspersed_args()
42 (options
, args
) = parser
.parse_args(args
)
46 logger
= logging
.getLogger()
47 if options
.verbose
== 1:
48 logger
.setLevel(logging
.INFO
)
50 logger
.setLevel(logging
.DEBUG
)
53 # Must fork before importing gtk, or ATK dies
55 # We exit, so our parent can call waitpid and unblock.
57 # The grandchild continues...
59 if options
.with_store
:
60 from zeroinstall
import zerostore
61 for x
in options
.with_store
:
62 iface_cache
.stores
.stores
.append(zerostore
.Store(os
.path
.abspath(x
)))
67 print "0launch-gui (zero-install) " + gui
.version
68 print "Copyright (C) 2010 Thomas Leonard"
69 print _("This program comes with ABSOLUTELY NO WARRANTY,"
70 "\nto the extent permitted by law."
71 "\nYou may redistribute copies of this program"
72 "\nunder the terms of the GNU Lesser General Public License."
73 "\nFor more information about these matters, see the file named COPYING.")
77 if gtk
.gdk
.get_display() is None:
78 print >>sys
.stderr
, "Failed to connect to display. Aborting."
81 if not hasattr(gtk
, 'combo_box_new_text'):
86 cache_explorer
= cache
.CacheExplorer()
88 cache_explorer
.window
.set_cursor(gtk
.gdk
.Cursor(gtk
.gdk
.WATCH
))
90 cache_explorer
.populate_model()
91 cache_explorer
.window
.set_cursor(None)
95 handler
= gui
.GUIHandler()
99 # Once we separate configuration from Policy, this hack can go away
100 class DummyPolicy(Policy
):
101 def recalculate(fetch_stale_interfaces
= True):
103 def solve_with_downloads(force
= False):
105 box
= preferences
.show_preferences(DummyPolicy('http://localhost/dummy', handler
))
106 box
.connect('destroy', gtk
.main_quit
)
110 interface_uri
= args
[0]
116 import mainwindow
, dialog
119 if options
.before
or options
.not_before
:
120 restrictions
.append(model
.VersionRangeRestriction(model
.parse_version(options
.before
),
121 model
.parse_version(options
.not_before
)))
123 widgets
= dialog
.Template('main')
125 policy
= Policy(interface_uri
, handler
, src
= bool(options
.source
), command
= options
.command
)
126 policy
.target_arch
= arch
.get_architecture(options
.os
, options
.cpu
)
127 root_iface
= iface_cache
.get_interface(interface_uri
)
128 policy
.solver
.extra_restrictions
[root_iface
] = restrictions
129 policy
.solver
.record_details
= True
131 window
= mainwindow
.MainWindow(policy
, widgets
, download_only
= bool(options
.download_only
), select_only
= bool(options
.select_only
))
132 handler
.mainwindow
= window
135 window
.set_message(options
.message
)
137 root
= iface_cache
.get_interface(policy
.root
)
138 window
.browser
.set_root(root
)
140 window
.window
.connect('destroy', lambda w
: handler
.abort_all_downloads())
143 window
.use_systray_icon()
147 force_refresh
= bool(options
.refresh
)
149 window
.refresh_button
.set_sensitive(False)
150 window
.browser
.set_update_icons(force_refresh
)
152 solved
= policy
.solve_with_downloads(force
= force_refresh
, update_local
= True)
154 if not window
.systray_icon
:
158 window
.refresh_button
.set_sensitive(True)
160 except Exception, ex
:
161 window
.report_exception(ex
)
163 if window
.systray_icon
and window
.systray_icon
.get_visible() and \
164 window
.systray_icon
.is_embedded():
166 window
.systray_icon
.set_tooltip(_('Downloading updates for %s') % root_iface
.get_name())
167 window
.run_button
.set_active(True)
169 # Should already be reporting an error, but
170 # blink it again just in case
171 window
.systray_icon
.set_blinking(True)
173 refresh_clicked
= dialog
.ButtonClickedBlocker(window
.refresh_button
)
174 yield refresh_clicked
, _recalculate
176 if refresh_clicked
.happened
:
179 handler
.wait_for_blocker(main())