2 Convenience routines for performing common operations.
6 # Copyright (C) 2009, Thomas Leonard
7 # See the README file for details, or visit http://0install.net.
9 import os
, sys
, logging
10 from zeroinstall
import support
11 from zeroinstall
import _
12 from zeroinstall
.support
import tasks
14 def get_selections_gui(iface_uri
, gui_args
, test_callback
= None):
15 """Run the GUI to choose and download a set of implementations.
16 The user may ask the GUI to submit a bug report about the program. In that case,
17 the GUI may ask us to test it. test_callback is called in that case with the implementations
18 to be tested; the callback will typically call L{zeroinstall.injector.run.test_selections} and return the result of that.
19 @param iface_uri: the required program, or None to show just the preferences dialog
21 @param gui_args: any additional arguments for the GUI itself
23 @param test_callback: function to use to try running the program
24 @type test_callback: L{zeroinstall.injector.selections.Selections} -> str
25 @return: the selected implementations
26 @rtype: L{zeroinstall.injector.selections.Selections}
29 from zeroinstall
.injector
import selections
, qdom
30 from StringIO
import StringIO
32 from os
.path
import join
, dirname
33 gui_exe
= join(dirname(__file__
), '0launch-gui', '0launch-gui')
36 cli
, gui
= socket
.socketpair()
41 # We are the child (GUI)
45 # We used to use pipes to support Python2.3...
46 os
.dup2(gui
.fileno(), 1)
47 os
.dup2(gui
.fileno(), 0)
48 if iface_uri
is not None:
49 gui_args
= gui_args
+ ['--', iface_uri
]
50 os
.execvp(gui_exe
, [gui_exe
] + gui_args
)
53 traceback
.print_exc(file = sys
.stderr
)
57 # We are the parent (CLI)
62 logging
.info("Waiting for selections from GUI...")
64 reply
= support
.read_bytes(cli
.fileno(), len('Length:') + 9, null_ok
= True)
66 if not reply
.startswith('Length:'):
67 raise Exception("Expected Length:, but got %s" % repr(reply
))
68 xml
= support
.read_bytes(cli
.fileno(), int(reply
.split(':', 1)[1], 16))
70 dom
= qdom
.parse(StringIO(xml
))
71 sels
= selections
.Selections(dom
)
73 if dom
.getAttribute('run-test'):
74 logging
.info("Testing program, as requested by GUI...")
75 if test_callback
is None:
76 output
= "Can't test: no test_callback was passed to get_selections_gui()\n"
78 output
= test_callback(sels
)
79 logging
.info("Sending results to GUI...")
80 output
= ('Length:%8x\n' % len(output
)) + output
81 logging
.debug("Sending: %s", repr(output
))
83 sent
= cli
.send(output
)
84 output
= output
[sent
:]
89 pid
, status
= os
.waitpid(child
, 0)
92 logging
.info("User cancelled the GUI; aborting")
95 raise Exception("Error from GUI: code = %d" % status
)
98 for sock
in [cli
, gui
]:
99 if sock
is not None: sock
.close()
103 def ensure_cached(uri
, command
= 'run'):
104 """Ensure that an implementation of uri is cached.
105 If not, it downloads one. It uses the GUI if a display is
106 available, or the console otherwise.
107 @param uri: the required interface
109 @return: the selected implementations, or None if the user cancelled
110 @rtype: L{zeroinstall.injector.selections.Selections}
112 from zeroinstall
.injector
import policy
, selections
113 from zeroinstall
.injector
.config
import load_config
115 config
= load_config()
116 p
= policy
.Policy(uri
, command
= command
, config
= config
)
117 p
.freshness
= 0 # Don't check for updates
119 if p
.need_download() or not p
.ready
:
120 if os
.environ
.get('DISPLAY', None):
121 return get_selections_gui(uri
, ['--command', command
])
123 done
= p
.solve_and_download_impls()
124 tasks
.wait_for_blocker(done
)
126 return selections
.Selections(p
)