]> git.ipfire.org Git - pakfire.git/blame - pakfire/packages/base.py
Add support for prerequires.
[pakfire.git] / pakfire / packages / base.py
CommitLineData
47a4cb89
MT
1#!/usr/bin/python
2
c605d735 3import datetime
47a4cb89 4import logging
d4c94aa5 5import xml.sax.saxutils
47a4cb89 6
47a4cb89
MT
7import util
8
9from pakfire.i18n import _
10
11class Package(object):
a2d1644c 12 def __init__(self, pakfire, repo=None):
3723913b
MT
13 self.pakfire = pakfire
14 self._repo = repo
47a4cb89 15
911e0d8c
MT
16 # Pointer to a package that is updated by this one.
17 self.old_package = None
18
47a4cb89 19 def __repr__(self):
3723913b 20 return "<%s %s>" % (self.__class__.__name__, self.friendly_name)
47a4cb89
MT
21
22 def __cmp__(self, other):
23 # if packages differ names return in alphabetical order
24 if not self.name == other.name:
25 return cmp(self.name, other.name)
26
268dd720 27 ret = util.version_compare(self.version_tuple, other.version_tuple)
47a4cb89 28
b566f7e3
MT
29 # XXX this is to move packages that have been built a while ago and
30 # do not have all the meta information that they won't be evaluated
31 # as the best match.
32 if not ret:
33 if "X"*3 in (self.build_id, other.build_id):
34 if self.build_id == "X"*3 and not other.build_id == "X"*3:
35 ret = -1
36
37 elif not self.build_id == "X"*3 and other.build_id == "X"*3:
38 ret = 1
39 # XXX hack end
40
ddd6b1de 41 # Compare the build times if we have a rebuilt package.
a2d1644c 42 if not ret and self.build_time and other.build_time:
ddd6b1de
MT
43 ret = cmp(self.build_time, other.build_time)
44
47a4cb89
MT
45 #if ret == 0:
46 # logging.debug("%s is equal to %s" % (self, other))
47 #elif ret < 0:
48 # logging.debug("%s is more recent than %s" % (other, self))
49 #elif ret > 0:
50 # logging.debug("%s is more recent than %s" % (self, other))
51
4ad46eec
MT
52 # If no rank could be created, sort by repository priority
53 if not ret:
54 ret = cmp(self.repo, other.repo)
55
47a4cb89
MT
56 return ret
57
a7277777
MT
58 def __hash__(self):
59 hashstr = ["%s" % s for s in (self.name, self.epoch, self.version,
60 self.release, self.arch,)]
61
62 return hash("-".join(hashstr))
63
9afa5620 64 def dump(self, short=False, long=False):
47a4cb89
MT
65 if short:
66 return "%s.%s : %s" % (self.name, self.arch, self.summary)
67
68 items = [
69 (_("Name"), self.name),
70 (_("Arch"), self.arch),
71 (_("Version"), self.version),
72 (_("Release"), self.release),
73 (_("Size"), util.format_size(self.size)),
a7cf3466 74 (_("Repo"), self.repo.name),
47a4cb89 75 (_("Summary"), self.summary),
8537c16d 76 (_("Groups"), " ".join(self.groups)),
a7cf3466 77 (_("URL"), self.url),
47a4cb89
MT
78 (_("License"), self.license),
79 ]
80
81 caption = _("Description")
82 for line in util.text_wrap(self.description):
83 items.append((caption, line))
84 caption = ""
85
9afa5620 86 if long:
1317485d 87 items.append((_("UUID"), self.uuid))
9afa5620
MT
88 items.append((_("Build ID"), self.build_id))
89 items.append((_("Build date"), self.build_date))
90 items.append((_("Build host"), self.build_host))
91
f81022c1
MT
92 caption = _("Provides")
93 for prov in sorted(self.provides):
94 items.append((caption, prov))
95 caption = ""
96
97 caption = _("Requires")
98 for req in sorted(self.requires):
99 items.append((caption, req))
100 caption = ""
101
47a4cb89
MT
102 format = "%%-%ds : %%s" % (max([len(k) for k, v in items]))
103
104 s = []
105 for caption, value in items:
106 s.append(format % (caption, value))
107
108 s.append("") # New line at the end
109
52d73aa8
MT
110 # XXX why do we need to decode this?
111 return "\n".join([str.decode("utf-8") for str in s])
47a4cb89 112
47a4cb89
MT
113 @property
114 def info(self):
115 info = {
116 "name" : self.name,
117 "version" : self.version,
118 "release" : self.release,
119 "epoch" : self.epoch,
120 "arch" : self.arch,
8537c16d 121 "groups" : self.groups,
47a4cb89
MT
122 "summary" : self.summary,
123 "description" : self.description,
124 "maintainer" : self.maintainer,
125 "url" : self.url,
126 "license" : self.license,
d4c94aa5
MT
127 "hash1" : self.hash1,
128 "vendor" : self.vendor,
129 "build_host" : self.build_host,
130 "build_time" : self.build_time,
131 "size" : self.size,
132 "inst_size" : self.inst_size,
47a4cb89
MT
133 }
134
135 return info
136
d4c94aa5
MT
137 @property
138 def hash1(self):
139 return "0"*40
140
47a4cb89
MT
141 @property
142 def size(self):
143 """
144 Return the size of the package file.
47a4cb89 145
9e8b1d7a
MT
146 This should be overloaded by another class and returns 0 for
147 virtual packages.
47a4cb89 148 """
9e8b1d7a 149 return 0
47a4cb89 150
d4c94aa5
MT
151 @property
152 def inst_size(self):
153 # XXX to be done
154 return 0
155
edd6a268
MT
156 @property
157 def local(self):
158 """
159 Indicates whether a package is located "local" means on disk
160 and has not be downloaded.
161 """
162 return False
163
47a4cb89
MT
164 ### META INFORMATION ###
165
166 @property
167 def metadata(self):
9e8b1d7a 168 raise NotImplementedError
47a4cb89
MT
169
170 @property
171 def friendly_name(self):
26fdc6dc 172 return "%s-%s.%s" % (self.name, self.friendly_version, self.arch)
47a4cb89
MT
173
174 @property
175 def friendly_version(self):
176 s = "%s-%s" % (self.version, self.release)
177
178 if self.epoch:
179 s = "%d:%s" % (self.epoch, s)
180
181 return s
182
183 @property
184 def repo(self):
a2d1644c
MT
185 if self._repo:
186 return self._repo
187
188 # By default, every package is connected to a dummy repository
189 return self.pakfire.repos.dummy
47a4cb89
MT
190
191 @property
192 def name(self):
193 return self.metadata.get("PKG_NAME")
194
195 @property
196 def version(self):
197 return self.metadata.get("PKG_VER")
198
199 @property
200 def release(self):
201 ret = None
202
203 for i in ("PKG_RELEASE", "PKG_REL"):
204 ret = self.metadata.get(i, None)
205 if ret:
206 break
207
208 return ret
209
210 @property
211 def epoch(self):
212 epoch = self.metadata.get("PKG_EPOCH", 0)
213
214 return int(epoch)
215
268dd720
MT
216 @property
217 def version_tuple(self):
218 """
219 Returns a tuple like (epoch, version, release) that can
220 be used to compare versions of packages.
221 """
222 return (self.epoch, self.version, self.release)
223
47a4cb89
MT
224 @property
225 def arch(self):
226 raise NotImplementedError
227
8537c16d
MT
228 @property
229 def base(self):
230 """
231 Say if a package belongs to the basic set
232 that is installed by default.
233 """
234 return "Base" in self.groups
235
236 @property
237 def critical(self):
238 """
239 Return if a package is marked "critial".
240 """
241 return "Critical" in self.groups
242
03f33deb
MT
243 @property
244 def type(self):
245 return self.metadata.get("TYPE", "unknown")
246
47a4cb89
MT
247 @property
248 def maintainer(self):
249 return self.metadata.get("PKG_MAINTAINER")
250
251 @property
252 def license(self):
253 return self.metadata.get("PKG_LICENSE")
254
255 @property
256 def summary(self):
257 return self.metadata.get("PKG_SUMMARY")
258
259 @property
260 def description(self):
261 return self.metadata.get("PKG_DESCRIPTION")
262
263 @property
8537c16d
MT
264 def groups(self):
265 return self.metadata.get("PKG_GROUPS", "").split()
47a4cb89
MT
266
267 @property
268 def url(self):
269 return self.metadata.get("PKG_URL")
270
9c75e8ed
MT
271 @property
272 def triggers(self):
273 triggers = self.metadata.get("PKG_TRIGGERS", "")
274
275 return triggers.split()
276
47a4cb89
MT
277 @property
278 def signature(self):
9e8b1d7a 279 raise NotImplementedError
47a4cb89
MT
280
281 @property
282 def build_date(self):
c605d735
MT
283 """
284 Automatically convert the UNIX timestamp from self.build_time to
285 a humanly readable format.
286 """
287 return "%s UTC" % datetime.datetime.utcfromtimestamp(self.build_time)
47a4cb89
MT
288
289 @property
290 def build_host(self):
c605d735 291 return self.metadata.get("BUILD_HOST")
47a4cb89
MT
292
293 @property
294 def build_id(self):
295 return self.metadata.get("BUILD_ID")
296
ddd6b1de
MT
297 @property
298 def build_time(self):
299 build_time = self.metadata.get("BUILD_TIME", 0)
300
301 return int(build_time)
302
1317485d
MT
303 @property
304 def uuid(self):
305 return self.metadata.get("PKG_UUID", None)
306
677ff42a
MT
307 @property
308 def supported_arches(self):
309 return self.metadata.get("PKG_SUPPORTED_ARCHES", "all")
310
ae20b05f
MT
311 @property
312 def vendor(self):
313 return self.metadata.get("PKG_VENDOR", "")
314
d4c94aa5 315 @property
71d3b468
MT
316 def prerequires(self):
317 requires = self.metadata.get("PKG_PREREQUIRES", "")
318
319 return requires.split()
d4c94aa5 320
743eaa12 321 @property
4496b160
MT
322 def requires(self):
323 ret = ""
324
325 # The default attributes, that are process for the requires.
326 attrs = ("PKG_REQUIRES", "PKG_DEPS")
327
328 # Source packages do depend on their build dependencies.
329 if self.arch == "src":
330 attrs = ("PKG_BUILD_DEPS",)
331
332 for i in attrs:
333 ret = self.metadata.get(i, ret)
334 if ret:
335 break
336
71d3b468 337 return ret.split()
4496b160 338
da77e6fa 339 @property
ae20b05f 340 def provides(self):
71d3b468 341 return self.metadata.get("PKG_PROVIDES", "").split()
da77e6fa 342
d4c94aa5
MT
343 @property
344 def conflicts(self):
71d3b468 345 return self.metadata.get("PKG_CONFLICTS", "").split()
d4c94aa5 346
ae20b05f
MT
347 @property
348 def obsoletes(self):
71d3b468 349 return self.metadata.get("PKG_OBSOLETES", "").split()
47a4cb89 350
ae20b05f 351 def extract(self, path, prefix=None):
d4c94aa5 352 raise NotImplementedError, "%s" % repr(self)