]> git.ipfire.org Git - people/stevee/pakfire.git/blame - pakfire/base.py
Merge branch 'master' of git://git.ipfire.org/oddments/pakfire
[people/stevee/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
MT
155 def localinstall(self, files):
156 repo_name = "localinstall"
157
158 # Create a new repository that holds all packages we passed on
159 # the commandline.
160 repo = self.solver.pool.create_repo(repo_name)
161
162 # Open all passed files and try to open them.
163 for file in files:
164 pkg = packages.open(self, None, file)
165
166 if not isinstance(pkg, packages.BinaryPackage):
167 logging.warning("Skipping package which is a wrong format: %s" % file)
168 continue
169
170 # Add the package information to the solver.
171 self.solver.add_package(pkg, repo_name)
172
173 # Break if no packages were added at all.
174 if not repo.size():
175 logging.critical("There are no packages to install.")
176 return
177
178 # Create a new request which contains all solvabled from the CLI and
179 # try to solve it.
180 request = self.solver.create_request()
181 for solvable in repo:
e0b99370
MT
182 request.install(solvable)
183
84680c15
MT
184 solver = self.create_solver()
185 t = solver.solve(request)
e0b99370
MT
186
187 # If solving was not possible, we exit here.
188 if not t:
189 return
190
c0fd807c 191 # Ask the user if this is okay.
3ad4bb5a
MT
192 #if not t.cli_yesno():
193 # return
c0fd807c
MT
194
195 # If okay, run the transcation.
e0b99370
MT
196 t.run()
197
18edfe75 198 def update(self, pkgs):
84680c15 199 request = self.create_request()
0c1a80b8 200
6c395339
MT
201 # If there are given any packets on the command line, we will
202 # only update them. Otherwise, we update the whole system.
203 if pkgs:
204 update = False
205 for pkg in pkgs:
206 request.update(pkg)
207 else:
208 update = True
0c1a80b8 209
84680c15 210 solver = self.create_solver()
6c395339 211 t = solver.solve(request, update=update)
0c1a80b8
MT
212
213 if not t:
214 return
215
c0fd807c
MT
216 # Ask the user if the transaction is okay.
217 if not t.cli_yesno():
218 return
0c1a80b8 219
c0fd807c 220 # Run the transaction.
0c1a80b8 221 t.run()
18edfe75 222
a39fd08b
MT
223 def remove(self, pkgs):
224 # Create a new request.
84680c15 225 request = self.create_request()
a39fd08b
MT
226 for pkg in pkgs:
227 request.remove(pkg)
228
229 # Solve the request.
84680c15 230 solver = self.create_solver()
6eb8f338 231 t = solver.solve(request, uninstall=True)
a39fd08b
MT
232
233 if not t:
234 return
235
c0fd807c
MT
236 # Ask the user if okay.
237 if not t.cli_yesno():
238 return
239
240 # Process the transaction.
a39fd08b
MT
241 t.run()
242
c1e7f927 243 def info(self, patterns):
18edfe75
MT
244 pkgs = []
245
1f27e8fe
MT
246 # For all patterns we run a single search which returns us a bunch
247 # of solvables which are transformed into Package objects.
18edfe75 248 for pattern in patterns:
1f27e8fe
MT
249 solvs = self.pool.search(pattern, satsolver.SEARCH_GLOB, "solvable:name")
250
251 for solv in solvs:
252 pkgs.append(packages.SolvPackage(self, solv))
18edfe75
MT
253
254 return packages.PackageListing(pkgs)
255
256 def search(self, pattern):
257 # Do the search.
f1ab3110 258 pkgs = []
884cd2fb 259 for solv in self.pool.search(pattern, satsolver.SEARCH_STRING|satsolver.SEARCH_FILES):
f1ab3110 260 pkgs.append(packages.SolvPackage(self, solv))
18edfe75
MT
261
262 # Return the output as a package listing.
263 return packages.PackageListing(pkgs)
264
265 def groupinstall(self, group):
266 pkgs = self.grouplist(group)
267
268 self.install(pkgs)
269
270 def grouplist(self, group):
fec9a917
MT
271 pkgs = []
272
273 for solv in self.pool.search(group, satsolver.SEARCH_SUBSTRING, "solvable:group"):
274 pkg = packages.SolvPackage(self, solv)
18edfe75 275
fec9a917
MT
276 if group in pkg.groups and not pkg.name in pkgs:
277 pkgs.append(pkg.name)
18edfe75 278
fec9a917 279 return sorted(pkgs)
18edfe75
MT
280
281 @staticmethod
dacaa18b 282 def build(pkg, resultdirs=None, shell=False, **kwargs):
18edfe75
MT
283 if not resultdirs:
284 resultdirs = []
285
286 b = builder.Builder(pkg, **kwargs)
287 p = b.pakfire
288
289 # Always include local repository.
290 resultdirs.append(p.repos.local_build.path)
291
292 try:
293 b.prepare()
294 b.extract()
295 b.build()
296 b.install_test()
297
298 # Copy-out all resultfiles
299 for resultdir in resultdirs:
300 if not resultdir:
301 continue
302
303 b.copy_result(resultdir)
304
305 except BuildError:
dacaa18b
MT
306 if shell:
307 b.shell()
308 else:
309 raise
18edfe75
MT
310
311 finally:
312 b.destroy()
313
314 @staticmethod
315 def shell(pkg, **kwargs):
316 b = builder.Builder(pkg, **kwargs)
317
318 try:
319 b.prepare()
320 b.extract()
321 b.shell()
322 finally:
323 b.destroy()
324
325 @staticmethod
50f96897
MT
326 def dist(pkgs, resultdirs=None, **pakfire_args):
327 # Create a builder with empty package.
328 b = builder.Builder(None, **pakfire_args)
18edfe75
MT
329 p = b.pakfire
330
331 if not resultdirs:
332 resultdirs = []
333
334 # Always include local repository
335 resultdirs.append(p.repos.local_build.path)
336
337 try:
338 b.prepare()
18edfe75 339
50f96897
MT
340 for pkg in pkgs:
341 b.pkg = pkg
18edfe75 342
50f96897 343 b.extract(build_deps=False)
18edfe75 344
50f96897
MT
345 # Run the actual dist.
346 b.dist()
347
348 # Copy-out all resultfiles
349 for resultdir in resultdirs:
350 if not resultdir:
351 continue
352
353 b.copy_result(resultdir)
354
355 # Cleanup the stuff that the package left.
356 b.cleanup()
18edfe75
MT
357 finally:
358 b.destroy()
359
360 def provides(self, patterns):
361 pkgs = []
362 for pattern in patterns:
c605d735 363 pkgs += self.repos.whatprovides(pattern)
18edfe75
MT
364
365 pkgs = packages.PackageListing(pkgs)
366 #pkgs.unique()
367
368 return pkgs
369
370 def requires(self, patterns):
371 pkgs = []
372 for pattern in patterns:
ae20b05f 373 pkgs += self.repos.get_by_requires(pattern)
18edfe75
MT
374
375 pkgs = packages.PackageListing(pkgs)
376 #pkgs.unique()
377
378 return pkgs
379
380 def repo_create(self, path, input_paths):
c605d735 381 repo = repository.RepositoryDir(
18edfe75
MT
382 self,
383 name="new",
384 description="New repository.",
385 path=path,
386 )
387
388 for input_path in input_paths:
c605d735 389 repo.collect_packages(input_path)
18edfe75
MT
390
391 repo.save()
392
393 def repo_list(self):
c605d735 394 return [r for r in self.repos]
31267a64
MT
395
396 def clean_all(self):
397 logging.debug("Cleaning up everything...")
398
399 # Clean up repository caches.
400 self.repos.clean()