2 Convenience routines for performing common operations.
6 # Copyright (C) 2007, Thomas Leonard
7 # See the README file for details, or visit http://0install.net.
9 import os
, sys
, logging
10 from zeroinstall
import support
12 def get_selections_gui(iface_uri
, gui_args
, test_callback
= None):
13 """Run the GUI to choose and download a set of implementations.
14 If the GUI itself is due for a check, refresh it first.
15 The user may ask the GUI to submit a bug report about the program. In that case,
16 the GUI may ask us to test it. test_callback is called in that case with the implementations
17 to be tested; the callback will typically call L{run.test_selections} and return the result of that.
18 @param iface_uri: the required program
20 @param gui_args: any additional arguments for the GUI itself
22 @param test_callback: function to use to try running the program
23 @type test_callback: L{selections.Selections} -> str
26 from zeroinstall
.injector
import selections
, autopolicy
, namespaces
, model
, run
, qdom
27 from StringIO
import StringIO
29 gui_policy
= autopolicy
.AutoPolicy(namespaces
.injector_gui_uri
)
30 if iface_uri
!= namespaces
.injector_gui_uri
and (gui_policy
.need_download() or gui_policy
.stale_feeds
):
31 # The GUI itself needs updating. Do that first.
32 logging
.info("The GUI could do with updating first.")
33 gui_sel
= get_selections_gui(namespaces
.injector_gui_uri
, ['--refresh'])
35 logging
.info("Aborted at user request")
36 return None # Aborted by user
38 # Try to start the GUI without using the network.
39 gui_policy
.freshness
= 0
40 gui_policy
.network_use
= model
.network_offline
41 gui_policy
.recalculate()
42 assert gui_policy
.ready
# Should always be some version available
43 gui_sel
= selections
.Selections(gui_policy
)
45 cli_from_gui
, gui_to_cli
= os
.pipe() # socket.socketpair() not in Python 2.3 :-(
46 gui_from_cli
, cli_to_gui
= os
.pipe()
53 os
.close(cli_from_gui
)
55 os
.dup2(gui_to_cli
, 1)
56 os
.dup2(gui_from_cli
, 0)
57 run
.execute_selections(gui_sel
, gui_args
+ ['--', iface_uri
])
60 traceback
.print_exc(file = sys
.stderr
)
64 os
.close(gui_from_cli
)
70 logging
.info("Waiting for selections from GUI...")
72 reply
= support
.read_bytes(cli_from_gui
, len('Length:') + 9, null_ok
= True)
74 if not reply
.startswith('Length:'):
75 raise Exception("Expected Length:, but got %s" % repr(reply
))
76 xml
= support
.read_bytes(cli_from_gui
, int(reply
.split(':', 1)[1], 16))
78 dom
= qdom
.parse(StringIO(xml
))
79 sels
= selections
.Selections(dom
)
81 if dom
.getAttribute('run-test'):
82 logging
.info("Testing program, as requested by GUI...")
83 if test_callback
is None:
84 output
= "Can't test: no test_callback was passed to get_selections_gui()\n"
86 output
= test_callback(sels
)
87 logging
.info("Sending results to GUI...")
88 output
= ('Length:%8x\n' % len(output
)) + output
89 logging
.debug("Sending: %s" % `output`
)
91 sent
= os
.write(cli_to_gui
, output
)
92 output
= output
[sent
:]
97 pid
, status
= os
.waitpid(child
, 0)
100 logging
.info("User cancelled the GUI; aborting")
101 return None # Aborted
103 raise Exception("Error from GUI: code = %d" % status
)
106 for fd
in [cli_to_gui
, cli_from_gui
, gui_to_cli
, gui_from_cli
]:
107 if fd
is not None: os
.close(fd
)