]> git.ipfire.org Git - people/stevee/pakfire.git/blame - pakfire/base.py
Merge branch 'master' of ssh://git.ipfire.org/pub/git/oddments/pakfire into sat
[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
715d7009
MT
29 def __init__(self, path="/", builder=False, configs=[],
30 enable_repos=None, disable_repos=None,
31 distro_config=None):
7c8f2953
MT
32 # Check if we are operating as the root user.
33 self.check_root_user()
34
3ad4bb5a
MT
35 config_type = None
36
7c8f2953
MT
37 # The path where we are operating in.
38 if builder:
3ad4bb5a 39 config_type = "builder"
7c8f2953
MT
40 self.builder = True
41 self.path = os.path.join(BUILD_ROOT, util.random_string())
42 else:
43 self.builder = False
715d7009 44 self.path = path
7c8f2953
MT
45
46 # XXX check if we are actually running on an ipfire system.
47
48 # Read configuration file(s)
3ad4bb5a 49 self.config = config.Config(type=config_type)
7c8f2953
MT
50 for filename in configs:
51 self.config.read(filename)
52
53 # Setup the logger
54 logger.setup_logging(self.config)
55 self.config.dump()
56
57 # Get more information about the distribution we are running
58 # or building
53bb7960 59 self.distro = distro.Distribution(self, distro_config)
c605d735 60 self.pool = satsolver.Pool(self.distro.arch)
ae20b05f
MT
61 self.repos = repository.Repositories(self,
62 enable_repos=enable_repos, disable_repos=disable_repos)
7c8f2953 63
c605d735
MT
64 # Create the solver of this pakfire instance.
65 # XXX maybe we can only create it when we need it?
66 #self.solver = satsolver.Solver(self, self.pool)
67
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 """
107 if not self.builder:
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
MT
123
124 def install(self, requires):
ae20b05f 125 # Create a new request.
84680c15 126 request = self.create_request()
18edfe75 127 for req in requires:
ae20b05f 128 request.install(req)
18edfe75 129
ae20b05f 130 # Do the solving.
84680c15
MT
131 solver = self.create_solver()
132 t = solver.solve(request)
18edfe75 133
ae20b05f 134 if not t:
18edfe75
MT
135 return
136
c0fd807c
MT
137 # Ask if the user acknowledges the transaction.
138 if not t.cli_yesno():
139 return
140
141 # Run the transaction.
ae20b05f 142 t.run()
18edfe75 143
e0b99370
MT
144 def localinstall(self, files):
145 repo_name = "localinstall"
146
147 # Create a new repository that holds all packages we passed on
148 # the commandline.
149 repo = self.solver.pool.create_repo(repo_name)
150
151 # Open all passed files and try to open them.
152 for file in files:
153 pkg = packages.open(self, None, file)
154
155 if not isinstance(pkg, packages.BinaryPackage):
156 logging.warning("Skipping package which is a wrong format: %s" % file)
157 continue
158
159 # Add the package information to the solver.
160 self.solver.add_package(pkg, repo_name)
161
162 # Break if no packages were added at all.
163 if not repo.size():
164 logging.critical("There are no packages to install.")
165 return
166
167 # Create a new request which contains all solvabled from the CLI and
168 # try to solve it.
169 request = self.solver.create_request()
170 for solvable in repo:
e0b99370
MT
171 request.install(solvable)
172
84680c15
MT
173 solver = self.create_solver()
174 t = solver.solve(request)
e0b99370
MT
175
176 # If solving was not possible, we exit here.
177 if not t:
178 return
179
c0fd807c 180 # Ask the user if this is okay.
3ad4bb5a
MT
181 #if not t.cli_yesno():
182 # return
c0fd807c
MT
183
184 # If okay, run the transcation.
e0b99370
MT
185 t.run()
186
18edfe75 187 def update(self, pkgs):
84680c15 188 request = self.create_request()
0c1a80b8
MT
189
190 repo_installed = self.solver.get_repo("installed")
191 assert repo_installed
192
193 for solvable in repo_installed:
194 request.update(solvable)
195
84680c15
MT
196 solver = self.create_solver()
197 t = solver.solve(request, update=True)
0c1a80b8
MT
198
199 if not t:
200 return
201
c0fd807c
MT
202 # Ask the user if the transaction is okay.
203 if not t.cli_yesno():
204 return
0c1a80b8 205
c0fd807c 206 # Run the transaction.
0c1a80b8 207 t.run()
18edfe75 208
a39fd08b
MT
209 def remove(self, pkgs):
210 # Create a new request.
84680c15 211 request = self.create_request()
a39fd08b
MT
212 for pkg in pkgs:
213 request.remove(pkg)
214
215 # Solve the request.
84680c15
MT
216 solver = self.create_solver()
217 t = solver.solve(request)
a39fd08b
MT
218
219 if not t:
220 return
221
c0fd807c
MT
222 # Ask the user if okay.
223 if not t.cli_yesno():
224 return
225
226 # Process the transaction.
a39fd08b
MT
227 t.run()
228
c1e7f927 229 def info(self, patterns):
18edfe75
MT
230 pkgs = []
231
1f27e8fe
MT
232 # For all patterns we run a single search which returns us a bunch
233 # of solvables which are transformed into Package objects.
18edfe75 234 for pattern in patterns:
1f27e8fe
MT
235 solvs = self.pool.search(pattern, satsolver.SEARCH_GLOB, "solvable:name")
236
237 for solv in solvs:
238 pkgs.append(packages.SolvPackage(self, solv))
18edfe75
MT
239
240 return packages.PackageListing(pkgs)
241
242 def search(self, pattern):
243 # Do the search.
f1ab3110 244 pkgs = []
884cd2fb 245 for solv in self.pool.search(pattern, satsolver.SEARCH_STRING|satsolver.SEARCH_FILES):
f1ab3110 246 pkgs.append(packages.SolvPackage(self, solv))
18edfe75
MT
247
248 # Return the output as a package listing.
249 return packages.PackageListing(pkgs)
250
251 def groupinstall(self, group):
252 pkgs = self.grouplist(group)
253
254 self.install(pkgs)
255
256 def grouplist(self, group):
fec9a917
MT
257 pkgs = []
258
259 for solv in self.pool.search(group, satsolver.SEARCH_SUBSTRING, "solvable:group"):
260 pkg = packages.SolvPackage(self, solv)
18edfe75 261
fec9a917
MT
262 if group in pkg.groups and not pkg.name in pkgs:
263 pkgs.append(pkg.name)
18edfe75 264
fec9a917 265 return sorted(pkgs)
18edfe75
MT
266
267 @staticmethod
dacaa18b 268 def build(pkg, resultdirs=None, shell=False, **kwargs):
18edfe75
MT
269 if not resultdirs:
270 resultdirs = []
271
272 b = builder.Builder(pkg, **kwargs)
273 p = b.pakfire
274
275 # Always include local repository.
276 resultdirs.append(p.repos.local_build.path)
277
278 try:
279 b.prepare()
280 b.extract()
281 b.build()
282 b.install_test()
283
284 # Copy-out all resultfiles
285 for resultdir in resultdirs:
286 if not resultdir:
287 continue
288
289 b.copy_result(resultdir)
290
291 except BuildError:
dacaa18b
MT
292 if shell:
293 b.shell()
294 else:
295 raise
18edfe75
MT
296
297 finally:
298 b.destroy()
299
300 @staticmethod
301 def shell(pkg, **kwargs):
302 b = builder.Builder(pkg, **kwargs)
303
304 try:
305 b.prepare()
306 b.extract()
307 b.shell()
308 finally:
309 b.destroy()
310
311 @staticmethod
50f96897
MT
312 def dist(pkgs, resultdirs=None, **pakfire_args):
313 # Create a builder with empty package.
314 b = builder.Builder(None, **pakfire_args)
18edfe75
MT
315 p = b.pakfire
316
317 if not resultdirs:
318 resultdirs = []
319
320 # Always include local repository
321 resultdirs.append(p.repos.local_build.path)
322
323 try:
324 b.prepare()
18edfe75 325
50f96897
MT
326 for pkg in pkgs:
327 b.pkg = pkg
18edfe75 328
50f96897 329 b.extract(build_deps=False)
18edfe75 330
50f96897
MT
331 # Run the actual dist.
332 b.dist()
333
334 # Copy-out all resultfiles
335 for resultdir in resultdirs:
336 if not resultdir:
337 continue
338
339 b.copy_result(resultdir)
340
341 # Cleanup the stuff that the package left.
342 b.cleanup()
18edfe75
MT
343 finally:
344 b.destroy()
345
346 def provides(self, patterns):
347 pkgs = []
348 for pattern in patterns:
c605d735 349 pkgs += self.repos.whatprovides(pattern)
18edfe75
MT
350
351 pkgs = packages.PackageListing(pkgs)
352 #pkgs.unique()
353
354 return pkgs
355
356 def requires(self, patterns):
357 pkgs = []
358 for pattern in patterns:
ae20b05f 359 pkgs += self.repos.get_by_requires(pattern)
18edfe75
MT
360
361 pkgs = packages.PackageListing(pkgs)
362 #pkgs.unique()
363
364 return pkgs
365
366 def repo_create(self, path, input_paths):
c605d735 367 repo = repository.RepositoryDir(
18edfe75
MT
368 self,
369 name="new",
370 description="New repository.",
371 path=path,
372 )
373
374 for input_path in input_paths:
c605d735 375 repo.collect_packages(input_path)
18edfe75
MT
376
377 repo.save()
378
379 def repo_list(self):
c605d735 380 return [r for r in self.repos]