]>
git.ipfire.org Git - pakfire.git/blob - python/pakfire/base.py
2 ###############################################################################
4 # Pakfire - The IPFire package management system #
5 # Copyright (C) 2011 Pakfire development team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
37 from constants
import *
40 class Pakfire(object):
42 (">=", satsolver
.REL_GE
,),
43 ("<=", satsolver
.REL_LE
,),
44 ("=" , satsolver
.REL_EQ
,),
45 ("<" , satsolver
.REL_LT
,),
46 (">" , satsolver
.REL_GT
,),
49 def __init__(self
, mode
=None, path
="/", configs
=[],
50 enable_repos
=None, disable_repos
=None,
51 distro_config
=None, **kwargs
):
54 assert mode
in ("normal", "builder", "server",)
57 # Check if we are operating as the root user.
58 self
.check_root_user()
60 # The path where we are operating in.
63 # Configure the instance of Pakfire we just started.
65 self
.path
= os
.path
.join(BUILD_ROOT
, util
.random_string())
67 elif mode
== "normal":
68 # check if we are actually running on an ipfire system.
70 self
.check_is_ipfire()
72 # Read configuration file(s)
73 self
.config
= config
.Config(type=mode
)
74 for filename
in configs
:
75 self
.config
.read(filename
)
76 # Assume, that all other keyword arguments are configuration
78 self
.config
.update(kwargs
)
81 logger
.setup_logging(self
.config
)
84 # Get more information about the distribution we are running
86 self
.distro
= distro
.Distribution(self
, distro_config
)
87 self
.pool
= satsolver
.Pool(self
.distro
.arch
)
88 self
.repos
= repository
.Repositories(self
,
89 enable_repos
=enable_repos
, disable_repos
=disable_repos
)
93 logger
.setup_logging()
95 def create_solver(self
):
96 return satsolver
.Solver(self
, self
.pool
)
98 def create_request(self
, builder
=False):
99 request
= satsolver
.Request(self
.pool
)
101 # Add multiinstall information.
102 for solv
in PAKFIRE_MULTIINSTALL
:
103 request
.noobsoletes(solv
)
107 def create_relation(self
, s
):
110 if isinstance(s
, filelist
._File
):
111 return satsolver
.Relation(self
.pool
, s
.name
)
113 elif s
.startswith("/"):
114 return satsolver
.Relation(self
.pool
, s
)
116 for pattern
, type in self
.RELATIONS
:
120 name
, version
= s
.split(pattern
, 1)
122 return satsolver
.Relation(self
.pool
, name
, version
, type)
124 return satsolver
.Relation(self
.pool
, s
)
127 if not self
.path
== "/":
134 # Get distribution information.
135 env
.update(self
.distro
.environ
)
140 def supported_arches(self
):
141 return self
.config
.supported_arches
146 A shortcut that indicates if the system is running in offline mode.
148 return self
.config
.get("offline", False)
150 def check_root_user(self
):
151 if not os
.getuid() == 0 or not os
.getgid() == 0:
152 raise Exception, "You must run pakfire as the root user."
154 def check_build_mode(self
):
156 Check if we are running in build mode.
157 Otherwise, raise an exception.
159 if not self
.mode
== "builder":
160 raise BuildError
, "Cannot build when not in build mode."
162 def check_host_arch(self
, arch
):
164 Check if we can build for arch.
166 # If no arch was given on the command line we build for our
167 # own arch which should always work.
171 if not self
.config
.host_supports_arch(arch
):
172 raise BuildError
, "Cannot build for the target architecture: %s" % arch
174 raise BuildError
, arch
176 def check_is_ipfire(self
):
177 return # XXX disabled for now
179 ret
= os
.path
.exists("/etc/ipfire-release")
182 raise NotAnIPFireSystemError
, "You can run pakfire only on an IPFire system"
186 # XXX just backwards compatibility
187 return self
.mode
== "builder"
189 def resolvdep(self
, requires
):
190 # Create a new request.
191 request
= self
.create_request()
193 req
= self
.create_relation(req
)
197 solver
= self
.create_solver()
198 t
= solver
.solve(request
)
203 logging
.info(_("Nothing to do"))
205 def install(self
, requires
, interactive
=True, logger
=None, **kwargs
):
207 logger
= logging
.getLogger()
209 # Create a new request.
210 request
= self
.create_request()
214 if req
.startswith("@"):
215 reqs
= self
.grouplist(req
[1:])
220 if not isinstance(req
, packages
.BinaryPackage
):
221 req
= self
.create_relation(req
)
226 solver
= self
.create_solver()
227 t
= solver
.solve(request
, **kwargs
)
231 raise DependencyError
233 logging
.info(_("Nothing to do"))
237 # Ask if the user acknowledges the transaction.
238 if not t
.cli_yesno():
242 t
.dump(logger
=logger
)
244 # Run the transaction.
247 def localinstall(self
, files
, yes
=None, allow_uninstall
=False):
248 repo_name
= repo_desc
= "localinstall"
250 # Create a new repository that holds all packages we passed on
252 repo
= repository
.RepositoryDir(self
, repo_name
, repo_desc
,
253 os
.path
.join(LOCAL_TMP_PATH
, "repo_%s" % util
.random_string()))
255 # Register the repository.
256 self
.repos
.add_repo(repo
)
259 # Add all packages to the repository index.
261 repo
.collect_packages(file)
263 # Break if no packages were added at all.
265 logging
.critical(_("There are no packages to install."))
268 # Create a new request that installs all solvables from the
270 request
= self
.create_request()
271 for solv
in [p
.solvable
for p
in repo
]:
272 request
.install(solv
)
274 solver
= self
.create_solver()
275 t
= solver
.solve(request
, uninstall
=allow_uninstall
)
277 # If solving was not possible, we exit here.
279 logging
.info(_("Nothing to do"))
283 # Ask the user if this is okay.
284 if not t
.cli_yesno():
291 # If okay, run the transcation.
295 # Remove the temporary copy of the repository we have created earlier.
297 self
.repos
.rem_repo(repo
)
299 def update(self
, pkgs
, check
=False):
301 check indicates, if the method should return after calculation
304 request
= self
.create_request()
306 # If there are given any packets on the command line, we will
307 # only update them. Otherwise, we update the whole system.
311 pkg
= self
.create_relation(pkg
)
316 solver
= self
.create_solver()
317 t
= solver
.solve(request
, update
=update
)
320 logging
.info(_("Nothing to do"))
322 # If we are running in check mode, we return a non-zero value to
323 # indicate, that there are no updates.
329 # Just exit here, because we won't do the transaction in this mode.
334 # Ask the user if the transaction is okay.
335 if not t
.cli_yesno():
338 # Run the transaction.
341 def remove(self
, pkgs
):
342 # Create a new request.
343 request
= self
.create_request()
345 pkg
= self
.create_relation(pkg
)
349 solver
= self
.create_solver()
350 t
= solver
.solve(request
, uninstall
=True)
353 logging
.info(_("Nothing to do"))
356 # Ask the user if okay.
357 if not t
.cli_yesno():
360 # Process the transaction.
363 def info(self
, patterns
):
366 # For all patterns we run a single search which returns us a bunch
367 # of solvables which are transformed into Package objects.
368 for pattern
in patterns
:
369 if os
.path
.exists(pattern
) and not os
.path
.isdir(pattern
):
370 pkg
= packages
.open(self
, self
.repos
.dummy
, pattern
)
375 solvs
= self
.pool
.search(pattern
, satsolver
.SEARCH_GLOB
, "solvable:name")
378 pkg
= packages
.SolvPackage(self
, solv
)
386 def search(self
, pattern
):
389 for solv
in self
.pool
.search(pattern
, satsolver
.SEARCH_STRING|satsolver
.SEARCH_FILES
):
390 pkg
= packages
.SolvPackage(self
, solv
)
392 # Check, if a package with the name is already in the resultset
393 # and always replace older ones by more recent ones.
394 if pkgs
.has_key(pkg
.name
):
395 if pkgs
[pkg
.name
] < pkg
:
400 # Return a list of the packages, alphabetically sorted.
401 return sorted(pkgs
.values())
403 def groupinstall(self
, group
, **kwargs
):
404 self
.install("@%s" % group
, **kwargs
)
406 def grouplist(self
, group
):
409 for solv
in self
.pool
.search(group
, satsolver
.SEARCH_SUBSTRING
, "solvable:group"):
410 pkg
= packages
.SolvPackage(self
, solv
)
412 if group
in pkg
.groups
and not pkg
.name
in pkgs
:
413 pkgs
.append(pkg
.name
)
418 def build(pkg
, resultdirs
=None, shell
=False, install_test
=True, **kwargs
):
422 b
= builder
.BuildEnviron(pkg
, **kwargs
)
425 # Always include local repository.
426 resultdirs
.append(p
.repos
.local_build
.path
)
429 # Start to prepare the build environment by mounting
430 # the filesystems and extracting files.
434 b
.build(install_test
=install_test
)
436 # Copy-out all resultfiles
437 for resultdir
in resultdirs
:
441 b
.copy_result(resultdir
)
452 def _build(self
, pkg
, resultdir
, nodeps
=False, **kwargs
):
453 b
= builder
.Builder(self
, pkg
, resultdir
, **kwargs
)
458 raise BuildError
, _("Build command has failed.")
460 # If the build was successful, cleanup all temporary files.
464 def shell(pkg
, **kwargs
):
465 b
= builder
.BuildEnviron(pkg
, **kwargs
)
473 def dist(self
, pkgs
, resultdirs
=None):
477 pkg
= packages
.Makefile(self
, pkg
)
481 def provides(self
, patterns
):
483 for pattern
in patterns
:
484 for pkg
in self
.repos
.whatprovides(pattern
):
492 def repo_create(self
, path
, input_paths
, type="binary"):
493 assert type in ("binary", "source",)
495 repo
= repository
.RepositoryDir(
498 description
="New repository.",
503 for input_path
in input_paths
:
504 repo
.collect_packages(input_path
)
511 return [r
for r
in self
.repos
]
514 logging
.debug("Cleaning up everything...")
516 # Clean up repository caches.
519 def check(self
, downgrade
=True, uninstall
=True):
521 Try to fix any errors in the system.
523 # Detect any errors in the dependency tree.
524 # For that we create an empty request and solver and try to solve
526 request
= self
.create_request()
527 solver
= self
.create_solver()
529 # XXX the solver does crash if we call it with fix_system=1,
530 # allow_downgrade=1 and uninstall=1. Need to fix this.
531 allow_downgrade
= False
534 t
= solver
.solve(request
, fix_system
=True, allow_downgrade
=downgrade
,
538 logging
.info(_("Everything is fine."))
541 # Ask the user if okay.
542 if not t
.cli_yesno():
545 # Process the transaction.