]> git.ipfire.org Git - people/ms/pakfire.git/blob - pakfire/base.py
Add "clean all" command to pakfire and pakfire-builder.
[people/ms/pakfire.git] / pakfire / base.py
1 #!/usr/bin/python
2
3 import logging
4 import os
5 import random
6 import string
7
8 import builder
9 import config
10 import distro
11 import logger
12 import repository
13 import packages
14 import satsolver
15 import util
16
17 from constants import *
18 from i18n import _
19
20 class Pakfire(object):
21 RELATIONS = (
22 (">=", satsolver.REL_GE,),
23 ("<=", satsolver.REL_LE,),
24 ("=" , satsolver.REL_EQ,),
25 ("<" , satsolver.REL_LT,),
26 (">" , satsolver.REL_GT,),
27 )
28
29 def __init__(self, mode, path="/", configs=[],
30 enable_repos=None, disable_repos=None,
31 distro_config=None):
32
33 # Set the mode.
34 assert mode in ("normal", "builder", "repo", "server", "master")
35 self.mode = mode
36
37 # Check if we are operating as the root user.
38 self.check_root_user()
39
40 # The path where we are operating in.
41 self.path = path
42
43 # Configure the instance of Pakfire we just started.
44 if mode == "builder":
45 self.path = os.path.join(BUILD_ROOT, util.random_string())
46
47 elif mode == "normal":
48 # check if we are actually running on an ipfire system.
49 self.check_is_ipfire()
50
51 # Read configuration file(s)
52 self.config = config.Config(type=mode)
53 for filename in configs:
54 self.config.read(filename)
55
56 # Setup the logger
57 logger.setup_logging(self.config)
58 self.config.dump()
59
60 # Get more information about the distribution we are running
61 # or building
62 self.distro = distro.Distribution(self, distro_config)
63 self.pool = satsolver.Pool(self.distro.arch)
64 self.repos = repository.Repositories(self,
65 enable_repos=enable_repos, disable_repos=disable_repos)
66
67 def create_solver(self):
68 return satsolver.Solver(self, self.pool)
69
70 def create_request(self):
71 return satsolver.Request(self.pool)
72
73 def create_relation(self, s):
74 assert s
75
76 if s.startswith("/"):
77 return satsolver.Relation(self.pool, s)
78
79 for pattern, type in self.RELATIONS:
80 if not pattern in s:
81 continue
82
83 name, version = s.split(pattern, 1)
84
85 return satsolver.Relation(self.pool, name, version, type)
86
87 return satsolver.Relation(self.pool, s)
88
89 def destroy(self):
90 if not self.path == "/":
91 util.rm(self.path)
92
93 @property
94 def supported_arches(self):
95 return self.config.supported_arches
96
97 def check_root_user(self):
98 if not os.getuid() == 0 or not os.getgid() == 0:
99 raise Exception, "You must run pakfire as the root user."
100
101 def check_build_mode(self):
102 """
103 Check if we are running in build mode.
104 Otherwise, raise an exception.
105 """
106 if not self.mode == "builder":
107 raise BuildError, "Cannot build when not in build mode."
108
109 def check_host_arch(self, arch):
110 """
111 Check if we can build for arch.
112 """
113 # If no arch was given on the command line we build for our
114 # own arch which should always work.
115 if not arch:
116 return True
117
118 if not self.config.host_supports_arch(arch):
119 raise BuildError, "Cannot build for the target architecture: %s" % arch
120
121 raise BuildError, arch
122
123 def check_is_ipfire(self):
124 ret = os.path.exists("/etc/ipfire-release")
125
126 if not ret:
127 raise NotAnIPFireSystemError, "You can run pakfire only on an IPFire system"
128
129 @property
130 def builder(self):
131 # XXX just backwards compatibility
132 return self.mode == "builder"
133
134 def install(self, requires):
135 # Create a new request.
136 request = self.create_request()
137 for req in requires:
138 request.install(req)
139
140 # Do the solving.
141 solver = self.create_solver()
142 t = solver.solve(request)
143
144 if not t:
145 return
146
147 # Ask if the user acknowledges the transaction.
148 if not t.cli_yesno():
149 return
150
151 # Run the transaction.
152 t.run()
153
154 def localinstall(self, files):
155 repo_name = "localinstall"
156
157 # Create a new repository that holds all packages we passed on
158 # the commandline.
159 repo = self.solver.pool.create_repo(repo_name)
160
161 # Open all passed files and try to open them.
162 for file in files:
163 pkg = packages.open(self, None, file)
164
165 if not isinstance(pkg, packages.BinaryPackage):
166 logging.warning("Skipping package which is a wrong format: %s" % file)
167 continue
168
169 # Add the package information to the solver.
170 self.solver.add_package(pkg, repo_name)
171
172 # Break if no packages were added at all.
173 if not repo.size():
174 logging.critical("There are no packages to install.")
175 return
176
177 # Create a new request which contains all solvabled from the CLI and
178 # try to solve it.
179 request = self.solver.create_request()
180 for solvable in repo:
181 request.install(solvable)
182
183 solver = self.create_solver()
184 t = solver.solve(request)
185
186 # If solving was not possible, we exit here.
187 if not t:
188 return
189
190 # Ask the user if this is okay.
191 #if not t.cli_yesno():
192 # return
193
194 # If okay, run the transcation.
195 t.run()
196
197 def update(self, pkgs):
198 request = self.create_request()
199
200 # If there are given any packets on the command line, we will
201 # only update them. Otherwise, we update the whole system.
202 if pkgs:
203 update = False
204 for pkg in pkgs:
205 request.update(pkg)
206 else:
207 update = True
208
209 solver = self.create_solver()
210 t = solver.solve(request, update=update)
211
212 if not t:
213 return
214
215 # Ask the user if the transaction is okay.
216 if not t.cli_yesno():
217 return
218
219 # Run the transaction.
220 t.run()
221
222 def remove(self, pkgs):
223 # Create a new request.
224 request = self.create_request()
225 for pkg in pkgs:
226 request.remove(pkg)
227
228 # Solve the request.
229 solver = self.create_solver()
230 t = solver.solve(request, uninstall=True)
231
232 if not t:
233 return
234
235 # Ask the user if okay.
236 if not t.cli_yesno():
237 return
238
239 # Process the transaction.
240 t.run()
241
242 def info(self, patterns):
243 pkgs = []
244
245 # For all patterns we run a single search which returns us a bunch
246 # of solvables which are transformed into Package objects.
247 for pattern in patterns:
248 solvs = self.pool.search(pattern, satsolver.SEARCH_GLOB, "solvable:name")
249
250 for solv in solvs:
251 pkgs.append(packages.SolvPackage(self, solv))
252
253 return packages.PackageListing(pkgs)
254
255 def search(self, pattern):
256 # Do the search.
257 pkgs = []
258 for solv in self.pool.search(pattern, satsolver.SEARCH_STRING|satsolver.SEARCH_FILES):
259 pkgs.append(packages.SolvPackage(self, solv))
260
261 # Return the output as a package listing.
262 return packages.PackageListing(pkgs)
263
264 def groupinstall(self, group):
265 pkgs = self.grouplist(group)
266
267 self.install(pkgs)
268
269 def grouplist(self, group):
270 pkgs = []
271
272 for solv in self.pool.search(group, satsolver.SEARCH_SUBSTRING, "solvable:group"):
273 pkg = packages.SolvPackage(self, solv)
274
275 if group in pkg.groups and not pkg.name in pkgs:
276 pkgs.append(pkg.name)
277
278 return sorted(pkgs)
279
280 @staticmethod
281 def build(pkg, resultdirs=None, shell=False, **kwargs):
282 if not resultdirs:
283 resultdirs = []
284
285 b = builder.Builder(pkg, **kwargs)
286 p = b.pakfire
287
288 # Always include local repository.
289 resultdirs.append(p.repos.local_build.path)
290
291 try:
292 b.prepare()
293 b.extract()
294 b.build()
295 b.install_test()
296
297 # Copy-out all resultfiles
298 for resultdir in resultdirs:
299 if not resultdir:
300 continue
301
302 b.copy_result(resultdir)
303
304 except BuildError:
305 if shell:
306 b.shell()
307 else:
308 raise
309
310 finally:
311 b.destroy()
312
313 @staticmethod
314 def shell(pkg, **kwargs):
315 b = builder.Builder(pkg, **kwargs)
316
317 try:
318 b.prepare()
319 b.extract()
320 b.shell()
321 finally:
322 b.destroy()
323
324 @staticmethod
325 def dist(pkgs, resultdirs=None, **pakfire_args):
326 # Create a builder with empty package.
327 b = builder.Builder(None, **pakfire_args)
328 p = b.pakfire
329
330 if not resultdirs:
331 resultdirs = []
332
333 # Always include local repository
334 resultdirs.append(p.repos.local_build.path)
335
336 try:
337 b.prepare()
338
339 for pkg in pkgs:
340 b.pkg = pkg
341
342 b.extract(build_deps=False)
343
344 # Run the actual dist.
345 b.dist()
346
347 # Copy-out all resultfiles
348 for resultdir in resultdirs:
349 if not resultdir:
350 continue
351
352 b.copy_result(resultdir)
353
354 # Cleanup the stuff that the package left.
355 b.cleanup()
356 finally:
357 b.destroy()
358
359 def provides(self, patterns):
360 pkgs = []
361 for pattern in patterns:
362 pkgs += self.repos.whatprovides(pattern)
363
364 pkgs = packages.PackageListing(pkgs)
365 #pkgs.unique()
366
367 return pkgs
368
369 def requires(self, patterns):
370 pkgs = []
371 for pattern in patterns:
372 pkgs += self.repos.get_by_requires(pattern)
373
374 pkgs = packages.PackageListing(pkgs)
375 #pkgs.unique()
376
377 return pkgs
378
379 def repo_create(self, path, input_paths):
380 repo = repository.RepositoryDir(
381 self,
382 name="new",
383 description="New repository.",
384 path=path,
385 )
386
387 for input_path in input_paths:
388 repo.collect_packages(input_path)
389
390 repo.save()
391
392 def repo_list(self):
393 return [r for r in self.repos]
394
395 def clean_all(self):
396 logging.debug("Cleaning up everything...")
397
398 # Clean up repository caches.
399 self.repos.clean()