1 """
2 This class brings together a L{solve.Solver} to choose a set of implmentations, a
3 L{fetch.Fetcher} to download additional components, and the user's configuration
4 settings.
5 @since: 0.53
6 """
7
8
9
10
11 from zeroinstall import _, logger
12 import os
13
14 from zeroinstall.injector import arch
15 from zeroinstall.injector.model import network_offline
16 from zeroinstall.support import tasks
19 """Chooses a set of implementations based on a policy.
20 Typical use:
21 1. Create a Driver object, giving it the requirements about the program to be run.
22 2. Call L{solve_with_downloads}. If more information is needed, a L{fetch.Fetcher} will be used to download it.
23 3. When all downloads are complete, the L{solver} contains the chosen versions.
24 4. Use L{get_uncached_implementations} to find where to get these versions and download them
25 using L{download_uncached_implementations}.
26
27 @ivar target_arch: target architecture for binaries (deprecated)
28 @type target_arch: L{arch.Architecture}
29 @ivar solver: solver used to choose a set of implementations
30 @type solver: L{solve.Solver}
31 @ivar watchers: callbacks to invoke after solving
32 """
33 __slots__ = ['watchers', 'requirements', 'config', 'target_arch', 'solver']
34
35 - def __init__(self, config, requirements):
58
71
72 @tasks.async
74 """Run the solver, then download any feeds that are missing or
75 that need to be updated. Each time a new feed is imported into
76 the cache, the solver is run again, possibly adding new downloads.
77 @param force: whether to download even if we're already ready to run.
78 @type force: bool
79 @param update_local: fetch PackageKit feeds even if we're ready to run.
80 @type update_local: bool"""
81
82 downloads_finished = set()
83 downloads_in_progress = {}
84
85
86
87
88
89
90
91
92
93
94 try_quick_exit = not (force or update_local)
95
96 while True:
97 self.solver.solve_for(self.requirements)
98 for w in self.watchers: w()
99
100 if try_quick_exit and self.solver.ready:
101 break
102 try_quick_exit = False
103
104 if not self.solver.ready:
105 force = True
106
107 for f in self.solver.feeds_used:
108 if f in downloads_finished or f in downloads_in_progress:
109 continue
110 if os.path.isabs(f):
111 if force:
112 self.config.iface_cache.get_feed(f, force = True)
113 downloads_in_progress[f] = tasks.IdleBlocker('Refresh local feed')
114 continue
115 elif f.startswith('distribution:'):
116 if force or update_local:
117 downloads_in_progress[f] = self.config.fetcher.download_and_import_feed(f, self.config.iface_cache)
118 elif force and self.config.network_use != network_offline:
119 downloads_in_progress[f] = self.config.fetcher.download_and_import_feed(f, self.config.iface_cache)
120
121
122 force = True
123
124 if not downloads_in_progress:
125 if self.config.network_use == network_offline:
126 logger.info(_("Can't choose versions and in off-line mode, so aborting"))
127 break
128
129
130 blockers = downloads_in_progress.values()
131 yield blockers
132 tasks.check(blockers, self.config.handler.report_error)
133
134 for f in list(downloads_in_progress.keys()):
135 if f in downloads_in_progress and downloads_in_progress[f].happened:
136 del downloads_in_progress[f]
137 downloads_finished.add(f)
138
139
140
141 distro_feed_url = 'distribution:' + f
142 if distro_feed_url in downloads_finished:
143 downloads_finished.remove(distro_feed_url)
144 if distro_feed_url in downloads_in_progress:
145 del downloads_in_progress[distro_feed_url]
146
147 @tasks.async
149 """Run L{solve_with_downloads} and then get the selected implementations too.
150 @type refresh: bool
151 @type select_only: bool
152 @raise SafeException: if we couldn't select a set of implementations
153 @since: 0.40"""
154 refreshed = self.solve_with_downloads(refresh)
155 if refreshed:
156 yield refreshed
157 tasks.check(refreshed)
158
159 if not self.solver.ready:
160 raise self.solver.get_failure_reason()
161
162 if not select_only:
163 downloaded = self.download_uncached_implementations()
164 if downloaded:
165 yield downloaded
166 tasks.check(downloaded)
167
169 """Decide whether we need to download anything (but don't do it!)
170 @return: true if we MUST download something (feeds or implementations)
171 @rtype: bool"""
172 self.solver.solve_for(self.requirements)
173 for w in self.watchers: w()
174
175 if not self.solver.ready:
176 return True
177
178 if self.get_uncached_implementations():
179 return True
180
181 return False
182
190