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