]> git.ipfire.org Git - people/ms/pakfire.git/blame - src/pakfire/base.py
libpakfire: Export repositories to Python
[people/ms/pakfire.git] / src / pakfire / base.py
CommitLineData
964aa579 1#!/usr/bin/python3
b792d887
MT
2###############################################################################
3# #
4# Pakfire - The IPFire package management system #
5# Copyright (C) 2011 Pakfire development team #
6# #
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. #
11# #
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. #
16# #
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/>. #
19# #
20###############################################################################
47a4cb89 21
bfa112c3 22import logging
7c8f2953
MT
23import os
24import random
25import string
26
2b5ba3b7 27from . import _pakfire
964aa579 28from . import distro
bfa112c3 29from . import logger
964aa579 30from . import packages
964aa579 31from . import util
7c8f2953 32
36374696 33from .config import Config
14dcd4ba
MT
34from .system import system
35
964aa579
MT
36from .constants import *
37from .i18n import _
7c8f2953 38
6e46b18e 39class Pakfire(_pakfire.Pakfire):
cb16be57 40 __version__ = PAKFIRE_VERSION
73776c23 41
69e754ab 42 def __init__(self, path=None, config=None, arch=None, distro=None, offline=False):
72caad76 43 _pakfire.Pakfire.__init__(self, path, arch, offline=offline)
14dcd4ba 44
bfa112c3
MT
45 # Initialise logging system
46 self.log = self._setup_logger()
47
9e5e1f15
MT
48 # Default to system distribution
49 self.distro = distro or system.distro
50
a9d2c50d 51 # Load configuration
36374696 52 self.config = config or Config("general.conf")
7c8f2953 53
bfa112c3
MT
54 def _setup_logger(self):
55 log = logging.getLogger("pakfire")
56 log.propagate = 0
57
58 # Always process all messages (include debug)
59 log.setLevel(logging.DEBUG)
60
61 # Pass everything down to libpakfire
62 handler = logger.PakfireLogHandler(self)
63 log.addHandler(handler)
64
65 return log
66
a9d2c50d 67 def __enter__(self):
36b328f2 68 """
a9d2c50d
MT
69 Called to initialize this Pakfire instance when
70 the context is entered.
36b328f2 71 """
a9d2c50d
MT
72 # Dump the configuration when we enter the context
73 self.config.dump()
36b328f2 74
1b61ba46 75 # Refresh repositories
3265ba73 76 self.refresh_repositories()
36b328f2 77
9ecdbcd1 78 return PakfireContext(self)
36b328f2 79
a9d2c50d 80 def __exit__(self, type, value, traceback):
1b61ba46 81 pass
36b328f2 82
3265ba73
MT
83 def refresh_repositories(self, force=False):
84 for repo in self.repos:
cd2f27a0 85 repo.refresh(force=force)
3265ba73 86
0c547b16 87 def clean(self):
cb6d631c
MT
88 # Clean up repository caches
89 for repo in self.repos:
90 repo.clean()
c49a002d 91
c49a002d 92
9ecdbcd1
MT
93class PakfireContext(object):
94 """
95 This context has functions that require
96 pakfire to be initialized.
97
98 That means that repository data has to be downloaded
99 and imported to be searchable, etc.
100 """
101 def __init__(self, pakfire):
102 self.pakfire = pakfire
103
0812ebe2
MT
104 @property
105 def repos(self):
106 """
107 Shortcut to access any configured
108 repositories for this Pakfire instance
109 """
110 return self.pakfire.repos
111
f466d0db 112 def check(self, **kwargs):
0dc4873e
MT
113 """
114 Try to fix any errors in the system.
115 """
116 # Detect any errors in the dependency tree.
117 # For that we create an empty request and solver and try to solve
118 # something.
19f3d106 119 request = _pakfire.Request(self.pakfire)
0dc4873e
MT
120 request.verify()
121
f466d0db 122 return request.solve(**kwargs)
0dc4873e 123
312fd26f 124 def info(self, args):
9ecdbcd1
MT
125 pkgs = []
126
312fd26f
MT
127 with _pakfire.Repo(self.pakfire, "tmp", clean=True) as r:
128 for arg in args:
129 if os.path.exists(arg) and not os.path.isdir(arg):
130 archive = _pakfire.Archive(self.pakfire, arg)
131
132 # Add the archive to the repository
133 pkg = r.add_archive(archive)
9ecdbcd1
MT
134 pkgs.append(pkg)
135
312fd26f
MT
136 else:
137 pkgs += self.pakfire.whatprovides(arg, name_only=True)
9ecdbcd1
MT
138
139 return sorted(pkgs)
140
1edcccc0
MT
141 def provides(self, patterns):
142 pkgs = []
143
144 for pattern in patterns:
78d8c9ec 145 for pkg in self.pakfire.whatprovides(pattern):
1edcccc0
MT
146 if pkg in pkgs:
147 continue
148
149 pkgs.append(pkg)
150
151 return sorted(pkgs)
152
d063a356 153 def search(self, pattern):
44b27b6f 154 return self.pakfire.search(pattern)
d063a356 155
e7da5970
MT
156 def extract(self, filenames, target=None):
157 if target and target == "/":
158 raise ValueError("Cannot extract to: %s" % target)
159
160 archives = []
161
162 # Open all archives
163 for filename in filenames:
164 a = _pakfire.Archive(self.pakfire, filename)
165 archives.append(a)
166
167 # Nothing to do when no archives where opened
168 if not archives:
169 return
170
171 # Extract them all
172 for archive in archives:
173 archive.extract(target)
174
154f8448
MT
175 # Transactions
176
b546c786 177 def install(self, requires, **kwargs):
19f3d106 178 request = _pakfire.Request(self.pakfire)
154f8448 179
b546c786 180 # XXX handle files and URLs
154f8448
MT
181
182 for req in requires:
8ad0a954
MT
183 # Handle groups
184 # TODO should move into libpakfire
185 if req.startswith("@"):
186 sel = _pakfire.Selector(self.pakfire)
187 sel.set(_pakfire.PAKFIRE_PKG_GROUP, _pakfire.PAKFIRE_EQ, req[1:])
188 request.install(sel)
189 continue
190
191 # Handle everything else
44b27b6f 192 relation = _pakfire.Relation(self.pakfire, req)
b546c786 193 request.install(relation)
154f8448 194
b546c786 195 return request.solve(**kwargs)
154f8448 196
532260e0
MT
197 def reinstall(self, pkgs, strict=False, logger=None):
198 """
b546c786 199 Reinstall one or more packages
532260e0 200 """
b546c786 201 raise NotImplementedError
532260e0 202
2f1289eb 203 def erase(self, pkgs, **kwargs):
19f3d106 204 request = _pakfire.Request(self.pakfire)
2f1289eb
MT
205
206 for pkg in pkgs:
44b27b6f 207 relation = _pakfire.Relation(self.pakfire, pkg)
2f1289eb
MT
208 request.erase(relation)
209
210 return request.solve(**kwargs)
211
47857184 212 def update(self, reqs=None, excludes=None, **kwargs):
19f3d106 213 request = _pakfire.Request(self.pakfire)
a0b428f8 214
47857184
MT
215 # Add all packages that should be updated to the request
216 for req in reqs or []:
44b27b6f 217 relation = _pakfire.Relation(self.pakfire, req)
47857184 218 request.upgrade(relation)
a0b428f8 219
47857184
MT
220 # Otherwise we will try to upgrade everything
221 else:
222 request.upgrade_all()
a0b428f8 223
47857184 224 # Exclude packages that should not be updated
a0b428f8 225 for exclude in excludes or []:
44b27b6f 226 relation = _pakfire.Relation(self.pakfire, exclude)
47857184 227 request.lock(relation)
a0b428f8 228
47857184 229 return request.solve(**kwargs)
a0b428f8 230
93f41006
MT
231 def downgrade(self, pkgs, logger=None, **kwargs):
232 assert pkgs
233
234 if logger is None:
235 logger = logging.getLogger("pakfire")
236
237 # Create a new request.
44b27b6f 238 request = self.pakfire.create_request()
93f41006
MT
239
240 # Fill request.
241 for pattern in pkgs:
242 best = None
243 for pkg in self.pakfire.repos.whatprovides(pattern):
244 # Only consider installed packages.
245 if not pkg.is_installed():
246 continue
247
248 if best and pkg > best:
249 best = pkg
250 elif best is None:
251 best = pkg
252
253 if best is None:
254 logger.warning(_("\"%s\" package does not seem to be installed.") % pattern)
255 else:
44b27b6f 256 rel = self.pakfire.create_relation("%s < %s" % (best.name, best.friendly_version))
93f41006
MT
257 request.install(rel)
258
259 # Solve the request.
44b27b6f 260 solver = self.pakfire.solve(request, allow_downgrade=True, **kwargs)
93f41006
MT
261 assert solver.status is True
262
263 # Create the transaction.
264 t = transaction.Transaction.from_solver(self.pakfire, solver)
265 t.dump(logger=logger)
266
267 if not t:
268 logger.info(_("Nothing to do"))
269 return
270
271 if not t.cli_yesno():
272 return
273
274 t.run()
275
9ecdbcd1 276
1f6c466e 277class PakfireKey(Pakfire):
f530fe71 278 pass