]> git.ipfire.org Git - pakfire.git/blame - pakfire/transaction.py
builder: Rename function cleanup -> destroy.
[pakfire.git] / pakfire / transaction.py
CommitLineData
47a4cb89
MT
1#!/usr/bin/python
2
3import logging
4
5import depsolve
1de8761d 6import packages
47a4cb89
MT
7import util
8
9from i18n import _
10
11class ActionError(Exception):
12 pass
13
14
15class Action(object):
16 def __init__(self, pakfire, pkg, deps=None):
17 self.pakfire = pakfire
18 self.pkg = pkg
19 self.deps = deps or []
20
21 def __cmp__(self, other):
22 # XXX ugly
23 return cmp(self.__repr__(), other.__repr__())
24
25 def __repr__(self):
26 return "<%s %s>" % (self.__class__.__name__, self.pkg.friendly_name)
27
28 def remove_dep(self, dep):
29 if not self.deps:
30 return
31
32 while dep in self.deps:
33 logging.debug("Removing dep %s from %s" % (dep, self))
34 self.deps.remove(dep)
35
36 def run(self):
37 raise NotImplementedError
38
39 @property
40 def local(self):
41 """
42 Reference to local repository (database).
43 """
44 return self.pakfire.repos.local
45
46
47class ActionExtract(Action):
48 def run(self):
49 logging.debug("Extracting package %s" % self.pkg.friendly_name)
50
51 # Create package in the database
66af936c 52 virtpkg = self.local.index.add_package(self.pkg)
47a4cb89
MT
53
54 # Grab an instance of the extractor and set it up
55 extractor = self.pkg.get_extractor(self.pakfire)
56
57 # Extract all files to instroot
66af936c 58 extractor.extractall(self.pakfire.path)
47a4cb89
MT
59
60 # Remove all temporary files
61 extractor.cleanup()
62
63
64class ActionScript(Action):
65 def run(self):
66 pass # XXX TBD
67
68
69class ActionScriptPreIn(ActionScript):
70 pass
71
72
73class ActionScriptPostIn(ActionScript):
74 pass
75
76
77class ActionScriptPreUn(ActionScript):
78 pass
79
80
81class ActionScriptPostUn(ActionScript):
82 pass
83
84
85class ActionInstall(Action):
86 pass
87
88
89class ActionRemove(Action):
90 pass
91
92
93class TransactionSet(object):
1de8761d
MT
94 def __init__(self):
95 self.installs = []
96 self.install_deps = []
47a4cb89 97
1de8761d
MT
98 self.updates = []
99 self.update_deps = []
47a4cb89 100
1de8761d
MT
101 self.removes = []
102 self.remove_deps = []
47a4cb89 103
20d2b270
MT
104 @property
105 def download_lists(self):
106 # All elements in these lists must be local.
107 return (self.installs, self.install_deps, self.updates, self.update_deps)
108
edd6a268
MT
109 @property
110 def downloads(self):
111 """
112 Return a list containing all packages that need to be downloaded.
113 """
20d2b270
MT
114 pkgs = []
115 for dl_list in self.download_lists:
116 pkgs += dl_list
117 pkgs.sort()
118
119 for pkg in pkgs:
edd6a268
MT
120 # Skip all packages that are already local.
121 if pkg.local:
122 continue
123
124 yield pkg
125
1de8761d
MT
126 def install(self, pkg, dep=False):
127 logging.info(" --> Marking package for install: %s" % pkg.friendly_name)
47a4cb89 128
1de8761d
MT
129 if dep:
130 self.install_deps.append(pkg)
131 else:
132 self.installs.append(pkg)
47a4cb89 133
1de8761d
MT
134 def remove(self, pkg, dep=False):
135 logging.info(" --> Marking package for remove: %s" % pkg.friendly_name)
136
137 if dep:
138 self.remove_deps.append(pkg)
139 else:
140 self.removes.append(pkg)
141
142 def update(self, pkg, dep=False):
143 logging.info(" --> Marking package for update: %s" % pkg.friendly_name)
144
145 if dep:
146 self.update_deps.append(pkg)
147 else:
148 self.updates.append(pkg)
149
150 def download(self):
4f91860e
MT
151 """
152 Convert all packages to BinaryPackage.
153 """
14ea3228
MT
154 pkgs = []
155 for pkg in self.downloads:
156 pkgs.append(pkg)
157
158 # If there are no packages to download skip the rest.
159 if not pkgs:
160 return
161
162 logging.info("Downloading packages:")
163 i = 0
164 for download in pkgs:
165 i += 1
166 pkg = download.download(text="(%2d/%02d): " % (i, len(pkgs)))
20d2b270
MT
167
168 for download_list in self.download_lists:
169 if download in download_list:
170 download_list.remove(download)
171 download_list.append(pkg)
172 break
1de8761d 173
14ea3228
MT
174 # Just an empty line to seperate the downloads from the extractions.
175 logging.info("")
176
1de8761d
MT
177
178class Transaction(object):
179 def __init__(self, pakfire, ds):
180 self.pakfire = pakfire
181 self.ds = ds
182
183 self._actions = []
47a4cb89
MT
184
185 def _install_pkg(self, pkg):
1de8761d
MT
186 assert isinstance(pkg, packages.BinaryPackage)
187
47a4cb89
MT
188 # XXX add dependencies for running the script here
189 action_prein = ActionScriptPreIn(self.pakfire, pkg)
190
191 action_extract = ActionExtract(self.pakfire, pkg, deps=[action_prein])
192
193 # XXX add dependencies for running the script here
194 action_postin = ActionScriptPostIn(self.pakfire, pkg, deps=[action_extract])
195
196 for action in (action_prein, action_extract, action_postin):
197 self.add_action(action)
198
47a4cb89 199 def _update_pkg(self, pkg):
1de8761d
MT
200 assert isinstance(pkg, packages.BinaryPackage)
201
47a4cb89
MT
202 action_extract = ActionExtract(self.pakfire, pkg)
203
204 self.add_action(action_extract)
47a4cb89
MT
205
206 def _remove_pkg(self, pkg):
207 # XXX TBD
1de8761d 208 pass
47a4cb89
MT
209
210 def populate(self):
47a4cb89
MT
211 # Determine which packages we have to add
212 # and which we have to remove.
213
1de8761d
MT
214 # Add all packages that need to be installed.
215 for pkg in self.ds.ts.installs + self.ds.ts.install_deps:
216 self._install_pkg(pkg)
47a4cb89 217
1de8761d
MT
218 # Add all packages that need to be updated.
219 for pkg in self.ds.ts.updates + self.ds.ts.update_deps:
220 self._update_pkg(pkg)
47a4cb89 221
1de8761d
MT
222 # Add all packages that need to be removed.
223 for pkg in self.ds.ts.removes + self.ds.ts.remove_deps:
224 self._remove_pkg(pkg)
47a4cb89
MT
225
226 def add_action(self, action):
227 logging.debug("New action added: %s" % action)
228
229 self._actions.append(action)
230
231 def remove_action(self, action):
232 logging.debug("Removing action: %s" % action)
233
234 self._actions.remove(action)
235 for _action in self.actions:
236 _action.remove_dep(action)
237
47a4cb89
MT
238 @property
239 def actions(self):
240 for action in self._actions:
241 yield action
242
243 @property
244 def packages(self):
245 for action in self._actions:
246 yield action.pkg
247
248 def run_action(self, action):
249 try:
250 action.run()
251 except ActionError, e:
252 logging.error("Action finished with an error: %s - %s" % (action, e))
253
254 def run(self):
1de8761d
MT
255 # Download all packages.
256 self.ds.ts.download()
257
258 # Create all the actions that need to be done.
259 self.populate()
260
47a4cb89
MT
261 while True:
262 if not [a for a in self.actions]:
263 break
264
265 for action in self.actions:
266 if action.deps:
267 #logging.debug("Skipping %s which cannot be run now." % action)
268 continue
269
270 self.run_action(action)
271 self.remove_action(action)
272