| Home | Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: utf-8 -*-
2 """
3
4 @author: Fabio Erculiani <lxnay@sabayonlinux.org>
5 @contact: lxnay@sabayonlinux.org
6 @copyright: Fabio Erculiani
7 @license: GPL-2
8
9 B{Entropy Package Manager Client Package Interface}.
10
11 """
12 from __future__ import with_statement
13 import os
14 import errno
15 import stat
16 import shutil
17 from entropy.const import etpConst, etpSys, etpCache, const_setup_perms, \
18 ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL, ETP_LOGLEVEL_VERBOSE
19 from entropy.exceptions import PermissionDenied, InvalidData, IncorrectParameter
20 from entropy.i18n import _
21 from entropy.output import TextInterface, brown, blue, bold, darkgreen, \
22 darkblue, red, purple, darkred, print_info, print_error, print_warning
23 from entropy.misc import TimeScheduled
24 from entropy.db import dbapi2, EntropyRepository
25 from entropy.client.interfaces.client import Client
26 from entropy.cache import EntropyCacher
27 import entropy.tools
28
30
32
33 if not isinstance(EquoInstance, Client):
34 mytxt = _("A valid Client instance or subclass is needed")
35 raise IncorrectParameter("IncorrectParameter: %s" % (mytxt,))
36 self.Entropy = EquoInstance
37
38 self.Cacher = EntropyCacher()
39 self.pkgmeta = {}
40 self.__prepared = False
41 self.matched_atom = ()
42 self.valid_actions = ("source", "fetch", "multi_fetch", "remove",
43 "remove_conflict", "install", "config"
44 )
45 self.action = None
46 self.fetch_abort_function = None
47 self.xterm_title = ''
48
50 self.pkgmeta.clear()
51
52 self.matched_atom = ()
53 self.valid_actions = ()
54 self.action = None
55 self.__prepared = False
56 self.fetch_abort_function = None
57
59 if self.__prepared:
60 mytxt = _("Already prepared")
61 raise PermissionDenied("PermissionDenied: %s" % (mytxt,))
62
64 if not self.__prepared:
65 mytxt = _("Not yet prepared")
66 raise PermissionDenied("PermissionDenied: %s" % (mytxt,))
67
69 if action not in self.valid_actions:
70 mytxt = _("Action must be in")
71 raise InvalidData("InvalidData: %s %s" % (mytxt,
72 self.valid_actions,)
73 )
74
75 - def match_checksum(self, repository = None, checksum = None,
76 download = None, signatures = None):
77
78 self.error_on_not_prepared()
79
80 if repository is None:
81 repository = self.pkgmeta['repository']
82 if checksum is None:
83 checksum = self.pkgmeta['checksum']
84 if download is None:
85 download = self.pkgmeta['download']
86 if signatures is None:
87 signatures = self.pkgmeta['signatures']
88
89 def do_signatures_validation(signatures):
90 # check signatures, if available
91 if isinstance(signatures, dict):
92 for hash_type in sorted(signatures):
93 hash_val = signatures[hash_type]
94 # XXX workaround bug on unreleased
95 # entropy versions
96 if hash_val in signatures:
97 continue
98 elif hash_val is None:
99 continue
100 elif not hasattr(entropy.tools, 'compare_%s' % (hash_type,)):
101 continue
102
103 self.Entropy.updateProgress(
104 "%s: %s" % (blue(_("Checking package hash")),
105 purple(hash_type.upper()),),
106 importance = 0,
107 type = "info",
108 header = red(" ## "),
109 back = True
110 )
111 cmp_func = getattr(entropy.tools,
112 'compare_%s' % (hash_type,))
113 mydownload = os.path.join(etpConst['entropyworkdir'],
114 download)
115 valid = cmp_func(mydownload, hash_val)
116 if not valid:
117 self.Entropy.updateProgress(
118 "%s: %s %s" % (
119 darkred(_("Package hash")),
120 purple(hash_type.upper()),
121 darkred(_("does not match the recorded one")),
122 ),
123 importance = 0,
124 type = "warning",
125 header = darkred(" ## ")
126 )
127 return 1
128 self.Entropy.updateProgress(
129 "%s %s" % (
130 purple(hash_type.upper()),
131 darkgreen(_("matches")),
132 ),
133 importance = 0,
134 type = "info",
135 header = " : "
136 )
137 return 0
138
139 dlcount = 0
140 match = False
141 while dlcount <= 5:
142
143 self.Entropy.updateProgress(
144 blue(_("Checking package checksum...")),
145 importance = 0,
146 type = "info",
147 header = red(" ## "),
148 back = True
149 )
150
151 dlcheck = self.Entropy.check_needed_package_download(download,
152 checksum = checksum)
153 if dlcheck == 0:
154 basef = os.path.basename(download)
155 self.Entropy.updateProgress(
156 "%s: %s" % (
157 blue(_("Package checksum matches")),
158 darkgreen(basef),
159 ),
160 importance = 0,
161 type = "info",
162 header = red(" ## ")
163 )
164
165 dlcheck = do_signatures_validation(signatures)
166 if dlcheck == 0:
167 self.pkgmeta['verified'] = True
168 match = True
169 break # file downloaded successfully
170
171 if dlcheck != 0:
172 dlcount += 1
173 mytxt = _("Checksum does not match. Download attempt #%s") % (
174 dlcount,
175 )
176 self.Entropy.updateProgress(
177 darkred(mytxt),
178 importance = 0,
179 type = "warning",
180 header = darkred(" ## ")
181 )
182 myrelative_uri = \
183 self.Entropy.get_branch_from_download_relative_uri(download)
184 fetch = self.Entropy.fetch_file_on_mirrors(
185 repository,
186 myrelative_uri,
187 download,
188 checksum,
189 fetch_abort_function = self.fetch_abort_function
190 )
191 if fetch != 0:
192 self.Entropy.updateProgress(
193 blue(_("Cannot properly fetch package! Quitting.")),
194 importance = 0,
195 type = "error",
196 header = darkred(" ## ")
197 )
198 return fetch
199
200 # package is fetched, let's loop one more time
201 # to make sure to run all the checksum checks
202 continue
203
204 if not match:
205 mytxt = _("Cannot fetch package or checksum does not match")
206 mytxt2 = _("Try to download latest repositories")
207 for txt in (mytxt, mytxt2,):
208 self.Entropy.updateProgress(
209 "%s." % (blue(txt),),
210 importance = 0,
211 type = "info",
212 header = red(" ## ")
213 )
214 return 1
215
216 return 0
217
219 rc = 0
220 for repository, branch, download, digest, signatures in \
221 self.pkgmeta['multi_checksum_list']:
222
223 rc = self.match_checksum(repository, digest, download, signatures)
224 if rc != 0:
225 break
226
227 return rc
228
230
231 if not self.pkgmeta['merge_from']:
232 self.Entropy.clientLog.log(
233 ETP_LOGPRI_INFO,
234 ETP_LOGLEVEL_NORMAL,
235 "Unpacking package: %s" % (self.pkgmeta['atom'],)
236 )
237 else:
238 self.Entropy.clientLog.log(
239 ETP_LOGPRI_INFO,
240 ETP_LOGLEVEL_NORMAL,
241 "Merging package: %s" % (self.pkgmeta['atom'],)
242 )
243
244 unpack_dir = self.pkgmeta['unpackdir']
245 unpack_dir_raw = self.pkgmeta['unpackdir'].encode('raw_unicode_escape')
246
247 if os.path.isdir(unpack_dir):
248 shutil.rmtree(unpack_dir_raw)
249 elif os.path.isfile(unpack_dir):
250 os.remove(unpack_dir_raw)
251 os.makedirs(self.pkgmeta['imagedir'])
252
253 if not os.path.isfile(self.pkgmeta['pkgpath']) and \
254 not self.pkgmeta['merge_from']:
255
256 if os.path.isdir(self.pkgmeta['pkgpath']):
257 shutil.rmtree(self.pkgmeta['pkgpath'])
258 if os.path.islink(self.pkgmeta['pkgpath']):
259 os.remove(self.pkgmeta['pkgpath'])
260 self.pkgmeta['verified'] = False
261 rc = self.fetch_step()
262 if rc != 0:
263 return rc
264
265 if not self.pkgmeta['merge_from']:
266
267 # extract entropy database from package file
268 # in order to avoid having to read content data
269 # from the repository database, which, in future
270 # is allowed to not provide such info.
271 pkg_dbdir = os.path.dirname(self.pkgmeta['pkgdbpath'])
272 if not os.path.isdir(pkg_dbdir):
273 os.makedirs(pkg_dbdir, 0755)
274
275 # extract edb
276 entropy.tools.extract_edb(self.pkgmeta['pkgpath'],
277 self.pkgmeta['pkgdbpath'])
278
279 unpack_tries = 3
280 while 1:
281 unpack_tries -= 1
282 try:
283 rc = entropy.tools.spawn_function(
284 entropy.tools.uncompress_tar_bz2,
285 self.pkgmeta['pkgpath'],
286 self.pkgmeta['imagedir'],
287 catchEmpty = True
288 )
289 except EOFError:
290 self.Entropy.clientLog.log(
291 ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL,
292 "EOFError on " + self.pkgmeta['pkgpath']
293 )
294 rc = 1
295 except:
296 # this will make devs to actually catch the
297 # right exception and prepare a fix
298 self.Entropy.clientLog.log(
299 ETP_LOGPRI_INFO,
300 ETP_LOGLEVEL_NORMAL,
301 "Raising Unicode/Pickling Error for " + \
302 self.pkgmeta['pkgpath']
303 )
304 rc = entropy.tools.uncompress_tar_bz2(
305 self.pkgmeta['pkgpath'],
306 self.pkgmeta['imagedir'],
307 catchEmpty = True
308 )
309 if rc == 0:
310 break
311
312 if unpack_tries <= 0:
313 return rc
314 # otherwise, try to download it again
315 self.pkgmeta['verified'] = False
316 f_rc = self.fetch_step()
317 if f_rc != 0:
318 return f_rc
319
320 else:
321
322 pid = os.fork()
323 if pid > 0:
324 os.waitpid(pid, 0)
325 else:
326 self.__fill_image_dir(self.pkgmeta['merge_from'],
327 self.pkgmeta['imagedir'])
328 os._exit(0)
329
330 # FIXME: add new entropy.spm plugin method
331
332 # unpack xpak ?
333 if os.path.isdir(self.pkgmeta['xpakpath']):
334 shutil.rmtree(self.pkgmeta['xpakpath'], True)
335
336 # create data dir where we'll unpack the xpak
337 xpak_dir = self.pkgmeta['xpakpath'] + os.path.sep + \
338 etpConst['entropyxpakdatarelativepath']
339
340 os.makedirs(xpak_dir, 0755)
341
342 xpak_path = self.pkgmeta['xpakpath'] + os.path.sep + \
343 etpConst['entropyxpakfilename']
344
345 if not self.pkgmeta['merge_from']:
346
347 if self.pkgmeta['smartpackage']:
348
349 # we need to get the .xpak from database
350 xdbconn = self.Entropy.open_repository(
351 self.pkgmeta['repository'])
352 xpakdata = xdbconn.retrieveXpakMetadata(
353 self.pkgmeta['idpackage'])
354 if xpakdata:
355 # save into a file
356 f = open(xpak_path, "wb")
357 f.write(xpakdata)
358 f.flush()
359 f.close()
360 self.pkgmeta['xpakstatus'] = entropy.tools.unpack_xpak(
361 xpak_path,
362 xpak_dir
363 )
364 else:
365 self.pkgmeta['xpakstatus'] = None
366 del xpakdata
367
368 else:
369 self.pkgmeta['xpakstatus'] = entropy.tools.extract_xpak(
370 self.pkgmeta['pkgpath'],
371 xpak_dir
372 )
373
374 else: # merge_from
375
376 tolink_dir = xpak_dir
377 if os.path.isdir(tolink_dir):
378 shutil.rmtree(tolink_dir, True)
379 # now link
380 os.symlink(self.pkgmeta['xpakdir'], tolink_dir)
381
382 # create fake portage ${D} linking it to imagedir
383 portage_cpv = self.pkgmeta['category'] + "/" + \
384 self.pkgmeta['name'] + "-" + self.pkgmeta['version']
385
386 portage_db_fakedir = os.path.join(
387 self.pkgmeta['unpackdir'],
388 "portage/" + portage_cpv
389 )
390
391 os.makedirs(portage_db_fakedir, 0755)
392 # now link it to self.pkgmeta['imagedir']
393 os.symlink(self.pkgmeta['imagedir'],
394 os.path.join(portage_db_fakedir, "image"))
395
396 return 0
397
399
400 try:
401 Spm = self.Entropy.Spm()
402 except Exception, err:
403 self.Entropy.clientLog.log(
404 ETP_LOGPRI_INFO,
405 ETP_LOGLEVEL_NORMAL,
406 "Source Package Manager not available: %s | %s" % (
407 type(Exception), err,
408 )
409 )
410 return 1
411
412 self.Entropy.updateProgress(
413 "SPM: %s" % (brown(_("configuration phase")),),
414 importance = 0,
415 header = red(" ## ")
416 )
417 return Spm.configure_installed_package(self.pkgmeta)
418
419
421
422 self.__clear_cache()
423
424 self.Entropy.clientLog.log(ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL,
425 "Removing package: %s" % (self.pkgmeta['removeatom'],))
426
427 mytxt = "%s: %s" % (
428 blue(_("Removing from Entropy")),
429 red(self.pkgmeta['removeatom']),
430 )
431 self.Entropy.updateProgress(
432 mytxt,
433 importance = 1,
434 type = "info",
435 header = red(" ## ")
436 )
437 automerge_metadata = \
438 self.Entropy.clientDbconn.retrieveAutomergefiles(
439 self.pkgmeta['removeidpackage'], get_dict = True
440 )
441 self.remove_installed_package(self.pkgmeta['removeidpackage'])
442
443 spm_rc = self.spm_remove_package()
444 if spm_rc != 0:
445 return spm_rc
446
447 self.remove_content_from_system(self.pkgmeta['removeidpackage'],
448 automerge_metadata)
449
450 return 0
451
453 """
454 Remove installed package from Entropy installed packages repository.
455
456 @param idpackage: Entropy Repository package identifier
457 @type idpackage: int
458 """
459 self.Entropy.clientDbconn.removePackage(idpackage, do_commit = False,
460 do_cleanup = False)
461
463 """
464 Remove installed package content (files/directories) from live system.
465
466 @param idpackage: Entropy Repository package identifier
467 @type idpackage: int
468 @keyword automerge_metadata: Entropy "automerge metadata"
469 @type automerge_metadata: dict
470 """
471 if automerge_metadata is None:
472 automerge_metadata = {}
473
474 sys_root = etpConst['systemroot']
475 # load CONFIG_PROTECT and CONFIG_PROTECT_MASK
476 sys_settings = self.Entropy.SystemSettings
477 protect = self.Entropy.get_installed_package_config_protect(idpackage)
478 mask = self.Entropy.get_installed_package_config_protect(idpackage,
479 mask = True)
480
481 sys_set_plg_id = \
482 etpConst['system_settings_plugins_ids']['client_plugin']
483 col_protect = sys_settings[sys_set_plg_id]['misc']['collisionprotect']
484
485 # remove files from system
486 directories = set()
487 directories_cache = set()
488 not_removed_due_to_collisions = set()
489 colliding_path_messages = set()
490
491 remove_content = sorted(self.pkgmeta['removecontent'], reverse = True)
492 for item in remove_content:
493
494 if not item:
495 continue # empty element??
496
497 sys_root_item = sys_root + item
498
499 # collision check
500 if col_protect > 0:
501
502 if self.Entropy.clientDbconn.isFileAvailable(item) \
503 and os.path.isfile(sys_root_item):
504
505 # in this way we filter out directories
506 colliding_path_messages.add(sys_root_item)
507 not_removed_due_to_collisions.add(item)
508 continue
509
510 protected = False
511 in_mask = False
512
513 if (not self.pkgmeta['removeconfig']) and \
514 (not self.pkgmeta['diffremoval']):
515
516 protected_item_test = sys_root_item
517 if isinstance(protected_item_test, unicode):
518 protected_item_test = protected_item_test.encode('utf-8')
519
520 in_mask, protected, x, do_continue = \
521 self._handle_config_protect(
522 protect, mask, None, protected_item_test,
523 do_allocation_check = False, do_quiet = True
524 )
525
526 if do_continue:
527 protected = True
528
529 # when files have not been modified by the user
530 # and they are inside a config protect directory
531 # we could even remove them directly
532 if in_mask:
533
534 oldprot_md5 = automerge_metadata.get(item)
535 if oldprot_md5 and os.path.exists(protected_item_test) and \
536 os.access(protected_item_test, os.R_OK):
537
538 in_system_md5 = entropy.tools.md5sum(
539 protected_item_test)
540
541 if oldprot_md5 == in_system_md5:
542 prot_msg = _("Removing config file, never modified")
543 mytxt = "%s: %s" % (
544 darkgreen(prot_msg),
545 blue(item),
546 )
547 self.Entropy.updateProgress(
548 mytxt,
549 importance = 1,
550 type = "info",
551 header = red(" ## ")
552 )
553 protected = False
554 do_continue = False
555
556 # Is file or directory a protected item?
557 if protected:
558 self.Entropy.clientLog.log(
559 ETP_LOGPRI_INFO,
560 ETP_LOGLEVEL_VERBOSE,
561 "[remove] Protecting config file: %s" % (sys_root_item,)
562 )
563 mytxt = "[%s] %s: %s" % (
564 red(_("remove")),
565 brown(_("Protecting config file")),
566 sys_root_item,
567 )
568 self.Entropy.updateProgress(
569 mytxt,
570 importance = 1,
571 type = "warning",
572 header = red(" ## ")
573 )
574 continue
575
576
577 try:
578 os.lstat(sys_root_item)
579
580 except OSError:
581 continue # skip file, does not exist
582
583 except UnicodeEncodeError:
584 msg = _("This package contains a badly encoded file !!!")
585 mytxt = brown(msg)
586 self.Entropy.updateProgress(
587 red("QA: ")+mytxt,
588 importance = 1,
589 type = "warning",
590 header = darkred(" ## ")
591 )
592 continue # file has a really bad encoding
593
594 if os.path.isdir(sys_root_item) and \
595 os.path.islink(sys_root_item):
596 # S_ISDIR returns False for directory symlinks,
597 # so using os.path.isdir valid directory symlink
598 if sys_root_item not in directories_cache:
599 directories.add((sys_root_item, "link"))
600 directories_cache.add(sys_root_item)
601 continue
602
603 if os.path.isdir(sys_root_item):
604 # plain directory
605 if sys_root_item not in directories_cache:
606 directories.add((sys_root_item, "dir"))
607 directories_cache.add(sys_root_item)
608 continue
609
610 # files, symlinks or not
611 # just a file or symlink or broken
612 # directory symlink (remove now)
613
614 try:
615 os.remove(sys_root_item)
616 except OSError, err:
617 self.Entropy.clientLog.log(
618 ETP_LOGPRI_INFO,
619 ETP_LOGLEVEL_NORMAL,
620 "[remove] Unable to remove %s, error: %s" % (
621 sys_root_item, err,)
622 )
623 continue
624
625 # add its parent directory
626 dirobj = os.path.dirname(sys_root_item)
627 if dirobj not in directories_cache:
628 if os.path.isdir(dirobj) and os.path.islink(dirobj):
629 directories.add((dirobj, "link"))
630 elif os.path.isdir(dirobj):
631 directories.add((dirobj, "dir"))
632
633 directories_cache.add(dirobj)
634
635
636 if colliding_path_messages:
637 self.Entropy.updateProgress(
638 "%s:" % (_("Collision found during removal of"),),
639 importance = 1,
640 type = "warning",
641 header = red(" ## ")
642 )
643
644 for path in sorted(colliding_path_messages):
645 self.Entropy.updateProgress(
646 purple(path),
647 importance = 0,
648 type = "warning",
649 header = red(" ## ")
650 )
651 self.Entropy.clientLog.log(ETP_LOGPRI_INFO, ETP_LOGLEVEL_NORMAL,
652 "Collision found during removal of %s - cannot overwrite" % (
653 path,)
654 )
655
656 # removing files not removed from removecontent.
657 # it happened that boot services not removed due to
658 # collisions got removed from their belonging runlevels
659 # by postremove step.
660 # since this is a set, it is a mapped type, so every
661 # other instance around will feature this update
662 self.pkgmeta['removecontent'] -= not_removed_due_to_collisions
663
664 # now handle directories
665 directories = sorted(directories, reverse = True)
666 while 1:
667 taint = False
668 for directory, dirtype in directories:
669 mydir = "%s%s" % (sys_root, directory,)
670 if dirtype == "link":
671 try:
672 mylist = os.listdir(mydir)
673 if not mylist:
674 try:
675 os.remove(mydir)
676 taint = True
677 except OSError:
678 pass
679 except OSError:
680 pass
681 elif dirtype == "dir":
682 try:
683 mylist = os.listdir(mydir)
684 if not mylist:
685 try:
686 os.rmdir(mydir)
687 taint = True
688 except OSError:
689 pass
690 except OSError:
691 pass
692
693 if not taint:
694 break
695
696 del directories_cache
697 del directories
698
700 # remove unpack dir
701 shutil.rmtree(unpack_dir, True)
702 try:
703 os.rmdir(unpack_dir)
704 except OSError:
705 pass
706 return 0
707
709 self.Entropy.clear_dump_cache(etpCache['advisories'])
710 self.Entropy.clear_dump_cache(etpCache['filter_satisfied_deps'])
711 self.Entropy.clear_dump_cache(etpCache['depends_tree'])
712 self.Entropy.clear_dump_cache(etpCache['check_package_update'])
713 self.Entropy.clear_dump_cache(etpCache['dep_tree'])
714 self.Entropy.clear_dump_cache(etpCache['dbMatch'] + \
715 etpConst['clientdbid']+"/")
716 self.Entropy.clear_dump_cache(etpCache['dbSearch'] + \
717 etpConst['clientdbid']+"/")
718
719 # clear caches, the bad way
720 self.Entropy.clear_dump_cache(etpCache['world_available'])
721 self.Entropy.clear_dump_cache(etpCache['world_update'])
722 self.Entropy.clear_dump_cache(etpCache['critical_update'])
723
725
726 # clear on-disk cache
727 self.__clear_cache()
728
729 self.Entropy.clientLog.log(
730 ETP_LOGPRI_INFO,
731 ETP_LOGLEVEL_NORMAL,
732 "Installing package: %s" % (self.pkgmeta['atom'],)
733 )
734
735 already_protected_config_files = {}
736 if self.pkgmeta['removeidpackage'] != -1:
737 already_protected_config_files = \
738 self.Entropy.clientDbconn.retrieveAutomergefiles(
739 self.pkgmeta['removeidpackage'], get_dict = True
740 )
741
742 # copy files over - install
743 # use fork? (in this case all the changed structures
744 # need to be pushed back)
745 rc = self.move_image_to_system(already_protected_config_files)
746 if rc != 0:
747 return rc
748
749 # inject into database
750 mytxt = "%s: %s" % (
751 blue(_("Updating database")),
752 red(self.pkgmeta['atom']),
753 )
754 self.Entropy.updateProgress(
755 mytxt,
756 importance = 1,
757 type = "info",
758 header = red(" ## ")
759 )
760 idpackage = self.add_installed_package()
761
762 # remove old files and spm stuff
763 if self.pkgmeta['removeidpackage'] != -1:
764
765 # doing a diff removal
766 self.Entropy.clientLog.log(
767 ETP_LOGPRI_INFO,
768 ETP_LOGLEVEL_NORMAL,
769 "Remove old package: %s" % (self.pkgmeta['removeatom'],)
770 )
771
772 self.Entropy.updateProgress(
773 blue(_("Cleaning previously installed information...")),
774 importance = 1,
775 type = "info",
776 header = red(" ## ")
777 )
778
779 spm_rc = self.spm_remove_package()
780 if spm_rc != 0:
781 return spm_rc
782
783 self.remove_content_from_system(self.pkgmeta['removeidpackage'],
784 automerge_metadata = already_protected_config_files)
785
786 return self.spm_install_package(idpackage)
787
789 """
790 Call Source Package Manager interface and tell it to register our
791 newly installed package.
792
793 @param idpackage: Entropy repository package identifier
794 @type idpackage: int
795 @return: execution status
796 @rtype: int
797 """
798 try:
799 Spm = self.Entropy.Spm()
800 except Exception, err:
801 self.Entropy.clientLog.log(
802 ETP_LOGPRI_INFO,
803 ETP_LOGLEVEL_NORMAL,
804 "Source Package Manager not available: %s | %s" % (
805 type(Exception), err,
806 )
807 )
808 return -1
809
810 self.Entropy.clientLog.log(
811 ETP_LOGPRI_INFO,
812 ETP_LOGLEVEL_NORMAL,
813 "Installing new SPM entry: %s" % (self.pkgmeta['atom'],)
814 )
815
816 spm_uid = Spm.add_installed_package(self.pkgmeta)
817 if spm_uid != -1:
818 self.Entropy.clientDbconn.insertSpmUid(idpackage, spm_uid)
819
820 return 0
821
823 """
824 Call Source Package Manager interface and tell it to remove our
825 just removed package.
826
827 @return: execution status
828 @rtype: int
829 """
830 try:
831 Spm = self.Entropy.Spm()
832 except Exception, err:
833 self.Entropy.clientLog.log(
834 ETP_LOGPRI_INFO,
835 ETP_LOGLEVEL_NORMAL,
836 "Source Package Manager not available: %s | %s" % (
837 type(Exception), err,
838 )
839 )
840 return -1
841
842 self.Entropy.clientLog.log(
843 ETP_LOGPRI_INFO,
844 ETP_LOGLEVEL_NORMAL,
845 "Removing from SPM: %s" % (self.pkgmeta['removeatom'],)
846 )
847
848 return Spm.remove_installed_package(self.pkgmeta)
849
850
852 """
853 For internal use only.
854 Copy package from repository to installed packages one.
855 """
856
857 # fetch info
858 smart_pkg = self.pkgmeta['smartpackage']
859 dbconn = self.Entropy.open_repository(self.pkgmeta['repository'])
860
861 if smart_pkg or self.pkgmeta['merge_from']:
862
863 data = dbconn.getPackageData(self.pkgmeta['idpackage'],
864 content_insert_formatted = True)
865
866 if self.pkgmeta['removeidpackage'] != -1:
867 self.pkgmeta['removecontent'].update(
868 self.Entropy.clientDbconn.contentDiff(
869 self.pkgmeta['removeidpackage'],
870 dbconn,
871 self.pkgmeta['idpackage']
872 )
873 )
874
875 else:
876
877 # normal repositories
878 data = dbconn.getPackageData(self.pkgmeta['idpackage'],
879 get_content = False)
880 pkg_dbconn = self.Entropy.open_generic_database(
881 self.pkgmeta['pkgdbpath'])
882 # it is safe to consider that package dbs coming from repos
883 # contain only one entry
884 pkg_idpackage = sorted(pkg_dbconn.listAllIdpackages())[0]
885 content = pkg_dbconn.retrieveContent(
886 pkg_idpackage, extended = True,
887 formatted = True, insert_formatted = True
888 )
889 real_idpk = self.pkgmeta['idpackage']
890 content = [(real_idpk, x, y,) for orig_idpk, x, y in content]
891 data['content'] = content
892
893 if self.pkgmeta['removeidpackage'] != -1:
894 self.pkgmeta['removecontent'].update(
895 self.Entropy.clientDbconn.contentDiff(
896 self.pkgmeta['removeidpackage'],
897 pkg_dbconn,
898 pkg_idpackage
899 )
900 )
901
902 pkg_dbconn.closeDB()
903
904 # this is needed to make postinstall trigger to work properly
905 trigger_content = set((x[1] for x in data['content']))
906 self.pkgmeta['triggers']['install']['content'] = trigger_content
907
908 # open client db
909 # always set data['injected'] to False
910 # installed packages database SHOULD never have more
911 # than one package for scope (key+slot)
912 data['injected'] = False
913 # spm counter will be set in self._install_package_into_spm_database()
914 data['counter'] = -1
915 # branch must be always set properly, it could happen it's not
916 # when installing packages through their .tbz2s
917 data['branch'] = self.Entropy.SystemSettings['repositories']['branch']
918 # there is no need to store needed paths into db
919 if data.get('needed_paths'):
920 del data['needed_paths']
921
922 idpackage, rev, x = self.Entropy.clientDbconn.handlePackage(
923 data, forcedRevision = data['revision'], formattedContent = True)
924
925 # update datecreation
926 ctime = entropy.tools.get_current_unix_time()
927 self.Entropy.clientDbconn.setCreationDate(idpackage, str(ctime))
928
929 # add idpk to the installedtable
930 self.Entropy.clientDbconn.dropInstalledPackageFromStore(idpackage)
931 self.Entropy.clientDbconn.storeInstalledPackage(idpackage,
932 self.pkgmeta['repository'], self.pkgmeta['install_source'])
933
934 automerge_data = self.pkgmeta.get('configprotect_data')
935 if automerge_data:
936 self.Entropy.clientDbconn.insertAutomergefiles(idpackage,
937 automerge_data)
938
939 # clear depends table, this will make clientdb dependstable to be
940 # regenerated during the next request (retrieveReverseDependencies)
941 self.Entropy.clientDbconn.taintReverseDependenciesMetadata()
942 return idpackage
943
945
946 dbconn = self.Entropy.open_repository(self.pkgmeta['repository'])
947 # this is triggered by merge_from pkgmeta metadata
948 # even if repositories are allowed to not have content
949 # metadata, in this particular case, it is mandatory
950 package_content = dbconn.retrieveContent(
951 self.pkgmeta['idpackage'], extended = True, formatted = True)
952 contents = sorted(package_content)
953
954 # collect files
955 for path in contents:
956 # convert back to filesystem str
957 encoded_path = path
958 path = os.path.join(mergeFrom, encoded_path[1:])
959 topath = os.path.join(image_dir, encoded_path[1:])
960 path = path.encode('raw_unicode_escape')
961 topath = topath.encode('raw_unicode_escape')
962
963 try:
964 exist = os.lstat(path)
965 except OSError:
966 continue # skip file
967 ftype = package_content[encoded_path]
968
969 if 'dir' == ftype and \
970 not stat.S_ISDIR(exist.st_mode) and \
971 os.path.isdir(path):
972 # workaround for directory symlink issues
973 path = os.path.realpath(path)
974
975 copystat = False
976 # if our directory is a symlink instead, then copy the symlink
977 if os.path.islink(path):
978 tolink = os.readlink(path)
979 if os.path.islink(topath):
980 os.remove(topath)
981 os.symlink(tolink, topath)
982 elif os.path.isdir(path):
983 if not os.path.isdir(topath):
984 os.makedirs(topath)
985 copystat = True
986 elif os.path.isfile(path):
987 if os.path.isfile(topath):
988 os.remove(topath) # should never happen
989 shutil.copy2(path, topath)
990 copystat = True
991
992 if copystat:
993 user = os.stat(path)[stat.ST_UID]
994 group = os.stat(path)[stat.ST_GID]
995 os.chown(topath, user, group)
996 shutil.copystat(path, topath)
997
998
1000
1001 # load CONFIG_PROTECT and its mask
1002 protect = self.Entropy.get_package_match_config_protect(
1003 self.matched_atom)
1004 mask = self.Entropy.get_package_match_config_protect(
1005 self.matched_atom, mask = True)
1006 sys_root = etpConst['systemroot']
1007 sys_set_plg_id = \
1008 etpConst['system_settings_plugins_ids']['client_plugin']
1009 misc_data = self.Entropy.SystemSettings[sys_set_plg_id]['misc']
1010 col_protect = misc_data['collisionprotect']
1011 items_installed = set()
1012
1013 # setup image_dir properly
1014 image_dir = self.pkgmeta['imagedir']
1015 encoded_image_dir = image_dir.encode('utf-8')
1016 movefile = entropy.tools.movefile
1017
1018 def workout_subdir(currentdir, subdir):
1019
1020 imagepath_dir = "%s/%s" % (currentdir, subdir,)
1021 rootdir = "%s%s" % (sys_root, imagepath_dir[len(image_dir):],)
1022
1023 # handle broken symlinks
1024 if os.path.islink(rootdir) and not os.path.exists(rootdir):
1025 # broken symlink
1026 os.remove(rootdir)
1027
1028 # if our directory is a file on the live system
1029 elif os.path.isfile(rootdir): # really weird...!
1030
1031 self.Entropy.clientLog.log(
1032 ETP_LOGPRI_INFO,
1033 ETP_LOGLEVEL_NORMAL,
1034 "WARNING!!! %s is a file when it should be " \
1035 "a directory !! Removing in 20 seconds..." % (rootdir,)
1036 )
1037 mytxt = darkred(_("%s is a file when should be a " \
1038 "directory !! Removing in 20 seconds...") % (rootdir,))
1039
1040 self.Entropy.updateProgress(
1041 red("QA: ")+mytxt,
1042 importance = 1,
1043 type = "warning",
1044 header = red(" !!! ")
1045 )
1046 entropy.tools.ebeep(20)
1047 os.remove(rootdir)
1048
1049 # if our directory is a symlink instead, then copy the symlink
1050 if os.path.islink(imagepath_dir):
1051
1052 # if our live system features a directory instead of
1053 # a symlink, we should consider removing the directory
1054 if not os.path.islink(rootdir) and os.path.isdir(rootdir):
1055 self.Entropy.clientLog.log(
1056 ETP_LOGPRI_INFO,
1057 ETP_LOGLEVEL_NORMAL,
1058 "WARNING!!! %s is a directory when it should be " \
1059 "a symlink !! Removing in 20 seconds..." % (
1060 rootdir,)
1061 )
1062 mytxt = "%s: %s" % (
1063 _("directory expected, symlink found"),
1064 rootdir,
1065 )
1066 mytxt2 = _("Removing in 20 seconds !!")
1067 for txt in (mytxt, mytxt2,):
1068 self.Entropy.updateProgress(
1069 darkred("QA: ") + darkred(txt),
1070 importance = 1,
1071 type = "warning",
1072 header = red(" !!! ")
1073 )
1074
1075 entropy.tools.ebeep(20)
1076 # fucking kill it in any case!
1077 # rootdir must die! die die die die!
1078 # /me brings chainsaw
1079 try:
1080 shutil.rmtree(rootdir, True)
1081 except (shutil.Error, OSError,), err:
1082 self.Entropy.clientLog.log(
1083 ETP_LOGPRI_INFO,
1084 ETP_LOGLEVEL_NORMAL,
1085 "WARNING!!! Failed to rm %s " \
1086 "directory ! [workout_subdir/1]: %s" % (
1087 rootdir, err,
1088 )
1089 )
1090
1091 tolink = os.readlink(imagepath_dir)
1092 live_tolink = None
1093 if os.path.islink(rootdir):
1094 live_tolink = os.readlink(rootdir)
1095
1096 if tolink != live_tolink:
1097 if os.path.lexists(rootdir):
1098 # at this point, it must be a file
1099 os.remove(rootdir)
1100 os.symlink(tolink, rootdir)
1101
1102 elif not os.path.isdir(rootdir) and not \
1103 os.access(rootdir, os.R_OK):
1104 # directory not found, we need to create it
1105
1106 try:
1107 # really force a simple mkdir first of all
1108 os.mkdir(rootdir)
1109 except OSError:
1110 os.makedirs(rootdir)
1111
1112
1113 if not os.path.islink(rootdir) and os.access(rootdir, os.W_OK):
1114
1115 # symlink doesn't need permissions, also
1116 # until os.walk ends they might be broken
1117 # XXX also, added os.access() check because
1118 # there might be directories/files unwritable
1119 # what to do otherwise?
1120 user = os.stat(imagepath_dir)[stat.ST_UID]
1121 group = os.stat(imagepath_dir)[stat.ST_GID]
1122 os.chown(rootdir, user, group)
1123 shutil.copystat(imagepath_dir, rootdir)
1124
1125 item_dir, item_base = os.path.split(rootdir)
1126 item_dir = os.path.realpath(item_dir)
1127 item_inst = os.path.join(item_dir, item_base)
1128 items_installed.add(item_inst)
1129
1130
1131 def workout_file(currentdir, item):
1132
1133 fromfile = "%s/%s" % (currentdir, item,)
1134 tofile = "%s%s" % (sys_root, fromfile[len(image_dir):],)
1135
1136 if col_protect > 1:
1137 todbfile = fromfile[len(image_dir):]
1138 myrc = self._handle_install_collision_protect(tofile,
1139 todbfile)
1140 if not myrc:
1141 return
1142
1143 prot_old_tofile = tofile[len(sys_root):]
1144 pre_tofile = tofile[:]
1145 in_mask, protected, tofile, do_return = \
1146 self._handle_config_protect(protect, mask, fromfile, tofile)
1147
1148 # collect new config automerge data
1149 if in_mask and os.path.exists(fromfile):
1150 try:
1151 prot_md5 = entropy.tools.md5sum(fromfile)
1152 self.pkgmeta['configprotect_data'].append(
1153 (prot_old_tofile, prot_md5,))
1154 except (IOError,), err:
1155 self.Entropy.clientLog.log(
1156 ETP_LOGPRI_INFO,
1157 ETP_LOGLEVEL_NORMAL,
1158 "WARNING!!! Failed to get md5 of %s " \
1159 "file ! [workout_file/1]: %s" % (
1160 fromfile, err,
1161 )
1162 )
1163
1164 # check if it's really necessary to protect file
1165 if protected:
1166
1167 # second task
1168 oldprot_md5 = already_protected_config_files.get(
1169 prot_old_tofile)
1170
1171 if oldprot_md5 and os.path.exists(pre_tofile) and \
1172 os.access(pre_tofile, os.R_OK):
1173
1174 try:
1175 in_system_md5 = entropy.tools.md5sum(pre_tofile)
1176 except (IOError,):
1177 # which is a clearly invalid value
1178 in_system_md5 = "0000"
1179
1180 if oldprot_md5 == in_system_md5:
1181 # we can merge it, files, even if
1182 # contains changes have not been modified
1183 # by the user
1184 msg = _("Automerging config file, never modified")
1185 mytxt = "%s: %s" % (
1186 darkgreen(msg),
1187 blue(pre_tofile),
1188 )
1189 self.Entropy.updateProgress(
1190 mytxt,
1191 importance = 1,
1192 type = "info",
1193 header = red(" ## ")
1194 )
1195 protected = False
1196 do_return = False
1197 tofile = pre_tofile
1198
1199 if do_return:
1200 return
1201
1202 if os.path.realpath(fromfile) == os.path.realpath(tofile) and \
1203 os.path.islink(tofile):
1204 # there is a serious issue here, better removing tofile,
1205 # happened to someone.
1206
1207 try:
1208 # try to cope...
1209 os.remove(tofile)
1210 except (OSError, IOError,), err:
1211 self.Entropy.clientLog.log(
1212 ETP_LOGPRI_INFO,
1213 ETP_LOGLEVEL_NORMAL,
1214 "WARNING!!! Failed to cope to oddity of %s " \
1215 "file ! [workout_file/2]: %s" % (
1216 tofile, err,
1217 )
1218 )
1219
1220 # if our file is a dir on the live system
1221 if os.path.isdir(tofile) and not os.path.islink(tofile):
1222
1223 # really weird...!
1224 self.Entropy.clientLog.log(
1225 ETP_LOGPRI_INFO,
1226 ETP_LOGLEVEL_NORMAL,
1227 "WARNING!!! %s is a directory when it should " \
1228 "be a file !! Removing in 20 seconds..." % (tofile,)
1229 )
1230
1231 mytxt = "%s: %s" % (
1232 _("file expected, directory found"),
1233 tofile,
1234 )
1235 mytxt2 = _("Removing in 20 seconds !!")
1236 for txt in (mytxt, mytxt2,):
1237 self.Entropy.updateProgress(
1238 darkred("QA: ") + darkred(txt),
1239 importance = 1,
1240 type = "warning",
1241 header = red(" !!! ")
1242 )
1243 entropy.tools.ebeep(20)
1244
1245 try:
1246 shutil.rmtree(tofile, True)
1247 except (shutil.Error, IOError,), err:
1248 self.Entropy.clientLog.log(
1249 ETP_LOGPRI_INFO,
1250 ETP_LOGLEVEL_NORMAL,
1251 "WARNING!!! Failed to cope to oddity of %s " \
1252 "file ! [workout_file/3]: %s" % (
1253 tofile, err,
1254 )
1255 )
1256
1257 # moving file using the raw format
1258 try:
1259 done = movefile(fromfile, tofile,
1260 src_basedir = encoded_image_dir)
1261 except (IOError,), err:
1262 # try to move forward, sometimes packages might be
1263 # fucked up and contain broken things
1264 if err.errno not in (errno.ENOENT, errno.EACCES,):
1265 raise
1266
1267 self.Entropy.clientLog.log(
1268 ETP_LOGPRI_INFO,
1269 ETP_LOGLEVEL_NORMAL,
1270 "WARNING!!! Error during file move" \
1271 " to system: %s => %s | IGNORED: %s" % (
1272 fromfile,
1273 tofile,
1274 err,
1275 )
1276 )
1277 done = True
1278
1279 if not done:
1280 self.Entropy.clientLog.log(
1281 ETP_LOGPRI_INFO,
1282 ETP_LOGLEVEL_NORMAL,
1283 "WARNING!!! Error during file move" \
1284 " to system: %s => %s" % (fromfile, tofile,)
1285 )
1286 mytxt = "%s: %s => %s, %s" % (
1287 _("File move error"),
1288 fromfile,
1289 tofile,
1290 _("please report"),
1291 )
1292 self.Entropy.updateProgress(
1293 red("QA: ")+darkred(mytxt),
1294 importance = 1,
1295 type = "warning",
1296 header = red(" !!! ")
1297 )
1298 return 4
1299
1300 item_dir = os.path.realpath(os.path.dirname(tofile))
1301 item_inst = os.path.join(item_dir, os.path.basename(tofile))
1302 items_installed.add(item_inst)
1303
1304 if protected:
1305 # add to disk cache
1306 self.Entropy.FileUpdates.add_to_cache(tofile, quiet = True)
1307
1308
1309 # merge data into system
1310 for currentdir, subdirs, files in os.walk(encoded_image_dir):
1311
1312 # create subdirs
1313 for subdir in subdirs:
1314 workout_subdir(currentdir, subdir)
1315
1316 for item in files:
1317 workout_file(currentdir, item)
1318
1319 # this is useful to avoid the removal of installed
1320 # files by __remove_package just because
1321 # there's a difference in the directory path, perhaps,
1322 # which is not handled correctly by
1323 # EntropyRepository.contentDiff for obvious reasons
1324 # (think about stuff in /usr/lib and /usr/lib64,
1325 # where the latter is just a symlink to the former)
1326 if self.pkgmeta.get('removecontent'):
1327 my_remove_content = set()
1328 for mypath in self.pkgmeta['removecontent']:
1329
1330 if not mypath:
1331 continue # empty?
1332
1333 item_dir = os.path.dirname("%s%s" % (sys_root, mypath,))
1334 item = os.path.join(os.path.realpath(item_dir),
1335 os.path.basename(mypath))
1336
1337 if item in items_installed:
1338 my_remove_content.add(item)
1339
1340 self.pkgmeta['removecontent'] -= my_remove_content
1341
1342 return 0
1343
1344 - def _handle_config_protect(self, protect, mask, fromfile, tofile,
1345 do_allocation_check = True, do_quiet = False):
1346 """
1347 Handle configuration file protection. This method contains the logic
1348 for determining if a file should be protected from overwrite.
1349 """
1350
1351 protected = False
1352 tofile_before_protect = tofile
1353 do_continue = False
1354 in_mask = False
1355 encoded_protect = [x.encode('raw_unicode_escape') for x in protect]
1356
1357 if tofile in encoded_protect:
1358 protected = True
1359 in_mask = True
1360
1361 elif os.path.dirname(tofile) in encoded_protect:
1362 protected = True
1363 in_mask = True
1364
1365 else:
1366 tofile_testdir = os.path.dirname(tofile)
1367 old_tofile_testdir = None
1368 while tofile_testdir != old_tofile_testdir:
1369 if tofile_testdir in encoded_protect:
1370 protected = True
1371 in_mask = True
1372 break
1373 old_tofile_testdir = tofile_testdir
1374 tofile_testdir = os.path.dirname(tofile_testdir)
1375
1376 if protected: # check if perhaps, file is masked, so unprotected
1377 newmask = [x.encode('raw_unicode_escape') for x in mask]
1378
1379 if tofile in newmask:
1380 protected = False
1381 in_mask = False
1382
1383 elif os.path.dirname(tofile) in newmask:
1384 protected = False
1385 in_mask = False
1386
1387 else:
1388 tofile_testdir = os.path.dirname(tofile)
1389 old_tofile_testdir = None
1390 while tofile_testdir != old_tofile_testdir:
1391 if tofile_testdir in newmask:
1392 protected = False
1393 in_mask = False
1394 break
1395 old_tofile_testdir = tofile_testdir
1396 tofile_testdir = os.path.dirname(tofile_testdir)
1397
1398 if not os.path.lexists(tofile):
1399 protected = False # file doesn't exist
1400
1401 # check if it's a text file
1402 if protected and os.access(tofile, os.F_OK | os.R_OK):
1403 protected = entropy.tools.istextfile(tofile)
1404 in_mask = protected
1405 else:
1406 protected = False # it's not a file
1407
1408 if not protected:
1409 return in_mask, protected, tofile, do_continue
1410
1411 ## ##
1412 # file is protected #
1413 ##__________________##
1414
1415 sys_set_plg_id = \
1416 etpConst['system_settings_plugins_ids']['client_plugin']
1417 client_settings = self.Entropy.SystemSettings[sys_set_plg_id]
1418 misc_settings = client_settings['misc']
1419
1420 # check if protection is disabled for this element
1421 if tofile in misc_settings['configprotectskip']:
1422 self.Entropy.clientLog.log(
1423 ETP_LOGPRI_INFO,
1424 ETP_LOGLEVEL_NORMAL,
1425 "Skipping config file installation/removal, " \
1426 "as stated in client.conf: %s" % (tofile,)
1427 )
1428 if not do_quiet:
1429 mytxt = "%s: %s" % (
1430 _("Skipping file installation/removal"),
1431 tofile,
1432 )
1433 self.Entropy.updateProgress(
1434 mytxt,
1435 importance = 1,
1436 type = "warning",
1437 header = darkred(" ## ")
1438 )
1439 do_continue = True
1440 return in_mask, protected, tofile, do_continue
1441
1442 ## ##
1443 # file is protected (2) #
1444 ##______________________##
1445
1446 prot_status = True
1447 if do_allocation_check:
1448 tofile, prot_status = entropy.tools.allocate_masked_file(
1449 tofile, fromfile)
1450
1451 if not prot_status:
1452 # a protected file with the same content
1453 # is already in place, so not going to protect
1454 # the same file twice
1455 protected = False
1456 return in_mask, protected, tofile, do_continue
1457
1458 ## ##
1459 # file is protected (3) #
1460 ##______________________##
1461
1462 oldtofile = tofile
1463 if oldtofile.find("._cfg") != -1:
1464 oldtofile = os.path.join(os.path.dirname(oldtofile),
1465 os.path.basename(oldtofile)[10:])
1466
1467 if not do_quiet:
1468 self.Entropy.clientLog.log(
1469 ETP_LOGPRI_INFO,
1470 ETP_LOGLEVEL_NORMAL,
1471 "Protecting config file: %s" % (oldtofile,)
1472 )
1473 mytxt = red("%s: %s") % (_("Protecting config file"), oldtofile,)
1474 self.Entropy.updateProgress(
1475 mytxt,
1476 importance = 1,
1477 type = "warning",
1478 header = darkred(" ## ")
1479 )
1480
1481 return in_mask, protected, tofile, do_continue
1482
1483
1485
1486 avail = self.Entropy.clientDbconn.isFileAvailable(todbfile,
1487 get_id = True)
1488
1489 if (self.pkgmeta['removeidpackage'] not in avail) and avail:
1490 mytxt = darkred(_("Collision found during install for"))
1491 mytxt += " %s - %s" % (
1492 blue(tofile),
1493 darkred(_("cannot overwrite")),
1494 )
1495 self.Entropy.updateProgress(
1496 red("QA: ")+mytxt,
1497 importance = 1,
1498 type = "warning",
1499 header = darkred(" ## ")
1500 )
1501 self.Entropy.clientLog.log(
1502 ETP_LOGPRI_INFO,
1503 ETP_LOGLEVEL_NORMAL,
1504 "WARNING!!! Collision found during install " \
1505 "for %s - cannot overwrite" % (tofile,)
1506 )
1507 return False
1508
1509 return True
1510
1512 self.error_on_not_prepared()
1513
1514 down_data = self.pkgmeta['download']
1515 down_keys = down_data.keys()
1516 d_cache = set()
1517 rc = 0
1518 key_cache = [os.path.basename(x) for x in down_keys]
1519
1520 for key in sorted(down_keys):
1521
1522 key_name = os.path.basename(key)
1523 if key_name in d_cache: continue
1524 # first fine wins
1525
1526 for url in down_data[key]:
1527
1528 file_name = os.path.basename(url)
1529 if self.pkgmeta.get('fetch_path'):
1530 dest_file = os.path.join(self.pkgmeta['fetch_path'],
1531 file_name)
1532 else:
1533 dest_file = os.path.join(self.pkgmeta['unpackdir'],
1534 file_name)
1535
1536 rc = self._fetch_source(url, dest_file)
1537 if rc == 0:
1538 d_cache.add(key_name)
1539 break
1540
1541 key_cache.remove(key_name)
1542 if rc != 0 and key_name not in key_cache:
1543 break
1544
1545 rc = 0
1546
1547 return rc
1548
1550 rc = 1
1551 try:
1552
1553 mytxt = "%s: %s" % (blue(_("Downloading")), brown(url),)
1554 # now fetch the new one
1555 self.Entropy.updateProgress(
1556 mytxt,
1557 importance = 1,
1558 type = "info",
1559 header = red(" ## ")
1560 )
1561
1562 rc, data_transfer, resumed = self.Entropy.fetch_file(
1563 url,
1564 None,
1565 None,
1566 False,
1567 fetch_file_abort_function = self.fetch_abort_function,
1568 filepath = dest_file
1569 )
1570 if rc == 0:
1571 mytxt = blue("%s: ") % (_("Successfully downloaded from"),)
1572 mytxt += red(entropy.tools.spliturl(url)[1])
1573 human_bytes = entropy.tools.bytes_into_human(data_transfer)
1574 mytxt += " %s %s/%s" % (_("at"), human_bytes, _("second"),)
1575 self.Entropy.updateProgress(
1576 mytxt,
1577 importance = 1,
1578 type = "info",
1579 header = red(" ## ")
1580 )
1581 self.Entropy.updateProgress(
1582 "%s: %s" % (blue(_("Local path")), brown(dest_file),),
1583 importance = 1,
1584 type = "info",
1585 header = red(" # ")
1586 )
1587 else:
1588 error_message = blue("%s: %s") % (
1589 _("Error downloading from"),
1590 red(entropy.tools.spliturl(url)[1]),
1591 )
1592 # something bad happened
1593 if rc == -1:
1594 error_message += " - %s." % (
1595 _("file not available on this mirror"),
1596 )
1597 elif rc == -3:
1598 error_message += " - not found."
1599 elif rc == -100:
1600 error_message += " - %s." % (_("discarded download"),)
1601 else:
1602 error_message += " - %s: %s" % (_("unknown reason"), rc,)
1603 self.Entropy.updateProgress(
1604 error_message,
1605 importance = 1,
1606 type = "warning",
1607 header = red(" ## ")
1608 )
1609
1610 except KeyboardInterrupt:
1611 pass
1612
1613 return rc
1614
1616 self.error_on_not_prepared()
1617
1618 mytxt = "%s: %s" % (blue(_("Downloading archive")),
1619 red(os.path.basename(self.pkgmeta['download'])),)
1620 self.Entropy.updateProgress(
1621 mytxt,
1622 importance = 1,
1623 type = "info",
1624 header = red(" ## ")
1625 )
1626
1627 rc = 0
1628 if not self.pkgmeta['verified']:
1629
1630 branch = self.Entropy.get_branch_from_download_relative_uri(
1631 self.pkgmeta['download'])
1632 rc = self.Entropy.fetch_file_on_mirrors(
1633 self.pkgmeta['repository'],
1634 branch,
1635 self.pkgmeta['download'],
1636 self.pkgmeta['checksum'],
1637 fetch_abort_function = self.fetch_abort_function
1638 )
1639
1640 if rc == 0:
1641 return 0
1642
1643 mytxt = "%s. %s: %s" % (
1644 red(_("Package cannot be fetched. Try to update repositories")),
1645 blue(_("Error")),
1646 rc,
1647 )
1648 self.Entropy.updateProgress(
1649 mytxt,
1650 importance = 1,
1651 type = "error",
1652 header = darkred(" ## ")
1653 )
1654
1655 return rc
1656
1658 self.error_on_not_prepared()
1659
1660 m_fetch_len = len(self.pkgmeta['multi_fetch_list'])
1661 mytxt = "%s: %s %s" % (
1662 blue(_("Downloading")),
1663 darkred(str(m_fetch_len)),
1664 _("archives"),
1665 )
1666
1667 self.Entropy.updateProgress(
1668 mytxt,
1669 importance = 1,
1670 type = "info",
1671 header = red(" ## ")
1672 )
1673 rc, err_list = self.Entropy.fetch_files_on_mirrors(
1674 self.pkgmeta['multi_fetch_list'],
1675 self.pkgmeta['checksum'],
1676 fetch_abort_function = self.fetch_abort_function
1677 )
1678
1679 if rc == 0:
1680 return 0
1681
1682 mytxt = _("Some packages cannot be fetched")
1683 mytxt2 = _("Try to update your repositories and retry")
1684 mytxt3 = "%s: %s" % (brown(_("Error")), bold(str(rc)),)
1685 for txt in (mytxt, mytxt2,):
1686 self.Entropy.updateProgress(
1687 "%s." % (darkred(txt),),
1688 importance = 0,
1689 type = "info",
1690 header = red(" ## ")
1691 )
1692 self.Entropy.updateProgress(
1693 mytxt3,
1694 importance = 0,
1695 type = "info",
1696 header = red(" ## ")
1697 )
1698
1699 for repo, branch, fname, cksum, signatures in err_list:
1700 self.Entropy.updateProgress(
1701 "[%s:%s|%s] %s" % (blue(repo), brown(branch),
1702 darkgreen(cksum), darkred(fname),),
1703 importance = 1,
1704 type = "error",
1705 header = darkred(" # ")
1706 )
1707
1708 return rc
1709
1711 self.Entropy.updateProgress(
1712 blue(_("Package cannot be downloaded, unknown error.")),
1713 importance = 1,
1714 type = "info",
1715 header = red(" ## ")
1716 )
1717 return 0
1718
1720 self.Entropy.updateProgress(
1721 blue(_("Installed package in queue vanished, skipping.")),
1722 importance = 1,
1723 type = "info",
1724 header = red(" ## ")
1725 )
1726 return 0
1727
1731
1735
1737 self.error_on_not_prepared()
1738
1739 if not self.pkgmeta['merge_from']:
1740 mytxt = "%s: %s" % (
1741 blue(_("Unpacking package")),
1742 red(os.path.basename(self.pkgmeta['download'])),
1743 )
1744 self.Entropy.updateProgress(
1745 mytxt,
1746 importance = 1,
1747 type = "info",
1748 header = red(" ## ")
1749 )
1750 else:
1751 mytxt = "%s: %s" % (
1752 blue(_("Merging package")),
1753 red(os.path.basename(self.pkgmeta['atom'])),
1754 )
1755 self.Entropy.updateProgress(
1756 mytxt,
1757 importance = 1,
1758 type = "info",
1759 header = red(" ## ")
1760 )
1761 rc = self.__unpack_package()
1762 if rc != 0:
1763 if rc == 512:
1764 errormsg = "%s. %s. %s: 512" % (
1765 red(_("You are running out of disk space")),
1766 red(_("I bet, you're probably Michele")),
1767 blue(_("Error")),
1768 )
1769 else:
1770 msg = _("An error occured while trying to unpack the package")
1771 errormsg = "%s. %s. %s: %s" % (
1772 red(msg),
1773 red(_("Check if your system is healthy")),
1774 blue(_("Error")),
1775 rc,
1776 )
1777 self.Entropy.updateProgress(
1778 errormsg,
1779 importance = 1,
1780 type = "error",
1781 header = red(" ## ")
1782 )
1783 return rc
1784
1786 self.error_on_not_prepared()
1787 mytxt = "%s: %s" % (
1788 blue(_("Installing package")),
1789 red(self.pkgmeta['atom']),
1790 )
1791 self.Entropy.updateProgress(
1792 mytxt,
1793 importance = 1,
1794 type = "info",
1795 header = red(" ## ")
1796 )
1797 if self.pkgmeta.get('description'):
1798 mytxt = "[%s]" % (purple(self.pkgmeta.get('description')),)
1799 self.Entropy.updateProgress(
1800 mytxt,
1801 importance = 1,
1802 type = "info",
1803 header = red(" ## ")
1804 )
1805
1806 rc = self.__install_package()
1807 if rc != 0:
1808 mytxt = "%s. %s. %s: %s" % (
1809 red(_("An error occured while trying to install the package")),
1810 red(_("Check if your system is healthy")),
1811 blue(_("Error")),
1812 rc,
1813 )
1814 self.Entropy.updateProgress(
1815 mytxt,
1816 importance = 1,
1817 type = "error",
1818 header = red(" ## ")
1819 )
1820 return rc
1821
1823 self.error_on_not_prepared()
1824 mytxt = "%s: %s" % (
1825 blue(_("Removing data")),
1826 red(self.pkgmeta['removeatom']),
1827 )
1828 self.Entropy.updateProgress(
1829 mytxt,
1830 importance = 1,
1831 type = "info",
1832 header = red(" ## ")
1833 )
1834
1835 rc = self.__remove_package()
1836 if rc != 0:
1837 mytxt = "%s. %s. %s: %s" % (
1838 red(_("An error occured while trying to remove the package")),
1839 red(_("Check if you have enough disk space on your hard disk")),
1840 blue(_("Error")),
1841 rc,
1842 )
1843 self.Entropy.updateProgress(
1844 mytxt,
1845 importance = 1,
1846 type = "error",
1847 header = red(" ## ")
1848 )
1849 return rc
1850
1852 self.error_on_not_prepared()
1853 mytxt = "%s: %s" % (
1854 blue(_("Cleaning")),
1855 red(self.pkgmeta['atom']),
1856 )
1857 self.Entropy.updateProgress(
1858 mytxt,
1859 importance = 1,
1860 type = "info",
1861 header = red(" ## ")
1862 )
1863 self._cleanup_package(self.pkgmeta['unpackdir'])
1864 # we don't care if cleanupPackage fails since it's not critical
1865 return 0
1866
1868 for msg in self.pkgmeta['messages']:
1869 self.Entropy.clientLog.write(">>> "+msg)
1870 return 0
1871
1873 self.error_on_not_prepared()
1874 pkgdata = self.pkgmeta['triggers'].get('install')
1875 if pkgdata:
1876 trigger = self.Entropy.Triggers('postinstall', pkgdata, self.action)
1877 do = trigger.prepare()
1878 if do:
1879 trigger.run()
1880 trigger.kill()
1881 del pkgdata
1882 return 0
1883
1885 self.error_on_not_prepared()
1886 pkgdata = self.pkgmeta['triggers'].get('install')
1887 if pkgdata:
1888
1889 trigger = self.Entropy.Triggers('preinstall', pkgdata, self.action)
1890 do = trigger.prepare()
1891 if self.pkgmeta.get("diffremoval") and do:
1892 # diffremoval is true only when the
1893 # removal is triggered by a package install
1894 remdata = self.pkgmeta['triggers'].get('remove')
1895 if remdata:
1896 r_trigger = self.Entropy.Triggers('preremove', remdata,
1897 self.action)
1898 r_trigger.prepare()
1899 r_trigger.triggers = [x for x in trigger.triggers if x \
1900 not in r_trigger.triggers]
1901 r_trigger.kill()
1902 del remdata
1903 if do:
1904 trigger.run()
1905 trigger.kill()
1906
1907 del pkgdata
1908 return 0
1909
1911 self.error_on_not_prepared()
1912 remdata = self.pkgmeta['triggers'].get('remove')
1913 if remdata:
1914 trigger = self.Entropy.Triggers('preremove', remdata, self.action)
1915 do = trigger.prepare()
1916 if do:
1917 trigger.run()
1918 trigger.kill()
1919 del remdata
1920 return 0
1921
1923 self.error_on_not_prepared()
1924 remdata = self.pkgmeta['triggers'].get('remove')
1925 if remdata:
1926
1927 trigger = self.Entropy.Triggers('postremove', remdata, self.action)
1928 do = trigger.prepare()
1929 if self.pkgmeta['diffremoval'] and \
1930 (self.pkgmeta.get("atom") is not None) and do:
1931 # diffremoval is true only when the remove
1932 # action is triggered by installPackages()
1933 pkgdata = self.pkgmeta['triggers'].get('install')
1934 if pkgdata:
1935 i_trigger = self.Entropy.Triggers('postinstall', pkgdata,
1936 self.action)
1937 i_trigger.prepare()
1938 i_trigger.triggers = [x for x in trigger.triggers if x \
1939 not in i_trigger.triggers]
1940 i_trigger.kill()
1941 del pkgdata
1942 if do:
1943 trigger.run()
1944 trigger.kill()
1945
1946 del remdata
1947 return 0
1948
1950 self.error_on_not_prepared()
1951
1952 for idpackage in self.pkgmeta['conflicts']:
1953 if not self.Entropy.clientDbconn.isIdpackageAvailable(idpackage):
1954 continue
1955
1956 pkg = self.Entropy.Package()
1957 pkg.prepare((idpackage,), "remove_conflict",
1958 self.pkgmeta['remove_metaopts'])
1959
1960 rc = pkg.run(xterm_header = self.xterm_title)
1961 pkg.kill()
1962 if rc != 0:
1963 return rc
1964
1965 return 0
1966
1968 self.error_on_not_prepared()
1969
1970 mytxt = "%s: %s" % (
1971 blue(_("Configuring package")),
1972 red(self.pkgmeta['atom']),
1973 )
1974 self.Entropy.updateProgress(
1975 mytxt,
1976 importance = 1,
1977 type = "info",
1978 header = red(" ## ")
1979 )
1980
1981 conf_rc = self.__configure_package()
1982 if conf_rc == 1:
1983 mytxt = _("An error occured while trying to configure the package")
1984 mytxt2 = "%s. %s: %s" % (
1985 red(_("Make sure that your system is healthy")),
1986 blue(_("Error")),
1987 conf_rc,
1988 )
1989 self.Entropy.updateProgress(
1990 darkred(mytxt),
1991 importance = 1,
1992 type = "error",
1993 header = red(" ## ")
1994 )
1995 self.Entropy.updateProgress(
1996 mytxt2,
1997 importance = 1,
1998 type = "error",
1999 header = red(" ## ")
2000 )
2001
2002 elif conf_rc == 2:
2003 mytxt = _("An error occured while trying to configure the package")
2004 mytxt2 = "%s. %s: %s" % (
2005 red(_("It seems that Source Package Manager entry is missing")),
2006 blue(_("Error")),
2007 conf_rc,
2008 )
2009 self.Entropy.updateProgress(
2010 darkred(mytxt),
2011 importance = 1,
2012 type = "error",
2013 header = red(" ## ")
2014 )
2015 self.Entropy.updateProgress(
2016 mytxt2,
2017 importance = 1,
2018 type = "error",
2019 header = red(" ## ")
2020 )
2021
2022 return conf_rc
2023
2025 if xterm_header is None:
2026 xterm_header = ""
2027
2028 if self.pkgmeta.has_key('remove_installed_vanished'):
2029 self.xterm_title += ' %s' % (_("Installed package vanished"),)
2030 self.Entropy.setTitle(self.xterm_title)
2031 rc = self.vanished_step()
2032 return rc
2033
2034 if self.pkgmeta.has_key('fetch_not_available'):
2035 self.xterm_title += ' %s' % (_("Fetch not available"),)
2036 self.Entropy.setTitle(self.xterm_title)
2037 rc = self.fetch_not_available_step()
2038 return rc
2039
2040 def do_fetch():
2041 self.xterm_title += ' %s: %s' % (
2042 _("Fetching"),
2043 os.path.basename(self.pkgmeta['download']),
2044 )
2045 self.Entropy.setTitle(self.xterm_title)
2046 return self.fetch_step()
2047
2048 def do_multi_fetch():
2049 self.xterm_title += ' %s: %s %s' % (_("Multi Fetching"),
2050 len(self.pkgmeta['multi_fetch_list']), _("packages"),)
2051 self.Entropy.setTitle(self.xterm_title)
2052 return self.multi_fetch_step()
2053
2054 def do_sources_fetch():
2055 self.xterm_title += ' %s: %s' % (
2056 _("Fetching sources"),
2057 os.path.basename(self.pkgmeta['atom']),)
2058 self.Entropy.setTitle(self.xterm_title)
2059 return self.sources_fetch_step()
2060
2061 def do_checksum():
2062 self.xterm_title += ' %s: %s' % (_("Verifying"),
2063 os.path.basename(self.pkgmeta['download']),)
2064 self.Entropy.setTitle(self.xterm_title)
2065 return self.checksum_step()
2066
2067 def do_multi_checksum():
2068 self.xterm_title += ' %s: %s %s' % (_("Multi Verification"),
2069 len(self.pkgmeta['multi_checksum_list']), _("packages"),)
2070 self.Entropy.setTitle(self.xterm_title)
2071 return self.multi_checksum_step()
2072
2073 def do_unpack():
2074 if not self.pkgmeta['merge_from']:
2075 mytxt = _("Unpacking")
2076 self.xterm_title += ' %s: %s' % (
2077 mytxt,
2078 os.path.basename(self.pkgmeta['download']),
2079 )
2080 else:
2081 mytxt = _("Merging")
2082 self.xterm_title += ' %s: %s' % (
2083 mytxt,
2084 os.path.basename(self.pkgmeta['atom']),
2085 )
2086 self.Entropy.setTitle(self.xterm_title)
2087 return self.unpack_step()
2088
2089 def do_remove_conflicts():
2090 return self.removeconflict_step()
2091
2092 def do_install():
2093 self.xterm_title += ' %s: %s' % (
2094 _("Installing"),
2095 self.pkgmeta['atom'],
2096 )
2097 self.Entropy.setTitle(self.xterm_title)
2098 return self.install_step()
2099
2100 def do_remove():
2101 self.xterm_title += ' %s: %s' % (
2102 _("Removing"),
2103 self.pkgmeta['removeatom'],
2104 )
2105 self.Entropy.setTitle(self.xterm_title)
2106 return self.remove_step()
2107
2108 def do_logmessages():
2109 return self.logmessages_step()
2110
2111 def do_cleanup():
2112 self.xterm_title += ' %s: %s' % (
2113 _("Cleaning"),
2114 self.pkgmeta['atom'],
2115 )
2116 self.Entropy.setTitle(self.xterm_title)
2117 return self.cleanup_step()
2118
2119 def do_postinstall():
2120 self.xterm_title += ' %s: %s' % (
2121 _("Postinstall"),
2122 self.pkgmeta['atom'],
2123 )
2124 self.Entropy.setTitle(self.xterm_title)
2125 return self.postinstall_step()
2126
2127 def do_preinstall():
2128 self.xterm_title += ' %s: %s' % (
2129 _("Preinstall"),
2130 self.pkgmeta['atom'],
2131 )
2132 self.Entropy.setTitle(self.xterm_title)
2133 return self.preinstall_step()
2134
2135 def do_preremove():
2136 self.xterm_title += ' %s: %s' % (
2137 _("Preremove"),
2138 self.pkgmeta['removeatom'],
2139 )
2140 self.Entropy.setTitle(self.xterm_title)
2141 return self.preremove_step()
2142
2143 def do_postremove():
2144 self.xterm_title += ' %s: %s' % (
2145 _("Postremove"),
2146 self.pkgmeta['removeatom'],
2147 )
2148 self.Entropy.setTitle(self.xterm_title)
2149 return self.postremove_step()
2150
2151 def do_config():
2152 self.xterm_title += ' %s: %s' % (
2153 _("Configuring"),
2154 self.pkgmeta['atom'],
2155 )
2156 self.Entropy.setTitle(self.xterm_title)
2157 return self.config_step()
2158
2159 steps_data = {
2160 "fetch": do_fetch,
2161 "multi_fetch": do_multi_fetch,
2162 "multi_checksum": do_multi_checksum,
2163 "sources_fetch": do_sources_fetch,
2164 "checksum": do_checksum,
2165 "unpack": do_unpack,
2166 "remove_conflicts": do_remove_conflicts,
2167 "install": do_install,
2168 "remove": do_remove,
2169 "logmessages": do_logmessages,
2170 "cleanup": do_cleanup,
2171 "postinstall": do_postinstall,
2172 "preinstall": do_preinstall,
2173 "postremove": do_postremove,
2174 "preremove": do_preremove,
2175 "config": do_config,
2176 }
2177
2178 rc = 0
2179 for step in self.pkgmeta['steps']:
2180 self.xterm_title = xterm_header
2181 rc = steps_data.get(step)()
2182 if rc != 0:
2183 break
2184 return rc
2185
2186
2188 self.error_on_not_prepared()
2189
2190 gave_up = self.Entropy.lock_check(self.Entropy.resources_check_lock)
2191 if gave_up:
2192 return 20
2193
2194 locked = self.Entropy.application_lock_check()
2195 if locked:
2196 return 21
2197
2198 # lock
2199 acquired = self.Entropy.resources_create_lock()
2200 if not acquired:
2201 self.Entropy.updateProgress(
2202 blue(_("Cannot acquire Entropy resources lock.")),
2203 importance = 2,
2204 type = "error",
2205 header = darkred(" ## ")
2206 )
2207 return 4 # app locked during lock acquire
2208 try:
2209 rc = self.run_stepper(xterm_header)
2210 finally:
2211 self.Entropy.resources_remove_lock()
2212
2213 # remove lock
2214 self.Entropy.resources_remove_lock()
2215
2216 if rc != 0:
2217 self.Entropy.updateProgress(
2218 blue(_("An error occured. Action aborted.")),
2219 importance = 2,
2220 type = "error",
2221 header = darkred(" ## ")
2222 )
2223 return rc
2224
2226 self.error_on_prepared()
2227
2228 self.check_action_validity(action)
2229
2230 self.action = action
2231 self.matched_atom = matched_atom
2232
2233 if metaopts is None:
2234 metaopts = {}
2235 self.metaopts = metaopts
2236
2237 # generate metadata dictionary
2238 self.generate_metadata()
2239
2241 self.error_on_prepared()
2242
2243 self.check_action_validity(self.action)
2244
2245 if self.action == "fetch":
2246 self.__generate_fetch_metadata()
2247 elif self.action == "multi_fetch":
2248 self.__generate_multi_fetch_metadata()
2249 elif self.action in ("remove", "remove_conflict"):
2250 self.__generate_remove_metadata()
2251 elif self.action == "install":
2252 self.__generate_install_metadata()
2253 elif self.action == "source":
2254 self.__generate_fetch_metadata(sources = True)
2255 elif self.action == "config":
2256 self.__generate_config_metadata()
2257
2258 self.__prepared = True
2259
2261
2262 self.pkgmeta.clear()
2263 idpackage = self.matched_atom[0]
2264
2265 if not self.Entropy.clientDbconn.isIdpackageAvailable(idpackage):
2266 self.pkgmeta['remove_installed_vanished'] = True
2267 return 0
2268
2269 self.pkgmeta['idpackage'] = idpackage
2270 self.pkgmeta['removeidpackage'] = idpackage
2271 self.pkgmeta['configprotect_data'] = []
2272 self.pkgmeta['triggers'] = {}
2273 self.pkgmeta['removeatom'] = \
2274 self.Entropy.clientDbconn.retrieveAtom(idpackage)
2275 self.pkgmeta['slot'] = \
2276 self.Entropy.clientDbconn.retrieveSlot(idpackage)
2277 self.pkgmeta['versiontag'] = \
2278 self.Entropy.clientDbconn.retrieveVersionTag(idpackage)
2279 self.pkgmeta['diffremoval'] = False
2280
2281 remove_config = False
2282 if self.metaopts.has_key('removeconfig'):
2283 remove_config = self.metaopts.get('removeconfig')
2284 self.pkgmeta['removeconfig'] = remove_config
2285
2286 self.pkgmeta['removecontent'] = \
2287 self.Entropy.clientDbconn.retrieveContent(idpackage)
2288 self.pkgmeta['triggers']['remove'] = \
2289 self.Entropy.clientDbconn.getTriggerInfo(idpackage)
2290 self.pkgmeta['triggers']['remove']['removecontent'] = \
2291 self.pkgmeta['removecontent']
2292 self.pkgmeta['triggers']['remove']['accept_license'] = \
2293 self.Entropy.clientDbconn.retrieveLicensedataKeys(idpackage)
2294
2295 self.pkgmeta['steps'] = [
2296 "preremove", "remove", "postremove"
2297 ]
2298
2299 return 0
2300
2302 self.pkgmeta.clear()
2303 idpackage = self.matched_atom[0]
2304
2305 self.pkgmeta['atom'] = \
2306 self.Entropy.clientDbconn.retrieveAtom(idpackage)
2307 key, slot = self.Entropy.clientDbconn.retrieveKeySlot(idpackage)
2308 self.pkgmeta['key'], self.pkgmeta['slot'] = key, slot
2309 self.pkgmeta['version'] = \
2310 self.Entropy.clientDbconn.retrieveVersion(idpackage)
2311 self.pkgmeta['accept_license'] = \
2312 self.Entropy.clientDbconn.retrieveLicensedataKeys(idpackage)
2313 self.pkgmeta['steps'] = []
2314 self.pkgmeta['steps'].append("config")
2315
2316 return 0
2317
2319 self.pkgmeta.clear()
2320
2321 idpackage, repository = self.matched_atom
2322 self.pkgmeta['idpackage'] = idpackage
2323 self.pkgmeta['repository'] = repository
2324
2325 # fetch abort function
2326 if self.metaopts.has_key('fetch_abort_function'):
2327 self.fetch_abort_function = \
2328 self.metaopts.pop('fetch_abort_function')
2329
2330 install_source = etpConst['install_sources']['unknown']
2331 meta_inst_source = self.metaopts.get('install_source', install_source)
2332 if meta_inst_source in etpConst['install_sources'].values():
2333 install_source = meta_inst_source
2334 self.pkgmeta['install_source'] = install_source
2335
2336 self.pkgmeta['configprotect_data'] = []
2337 dbconn = self.Entropy.open_repository(repository)
2338 self.pkgmeta['triggers'] = {}
2339 self.pkgmeta['atom'] = dbconn.retrieveAtom(idpackage)
2340 self.pkgmeta['slot'] = dbconn.retrieveSlot(idpackage)
2341
2342 ver, tag, rev = dbconn.getVersioningData(idpackage)
2343 self.pkgmeta['version'] = ver
2344 self.pkgmeta['versiontag'] = tag
2345 self.pkgmeta['revision'] = rev
2346
2347 self.pkgmeta['category'] = dbconn.retrieveCategory(idpackage)
2348 self.pkgmeta['download'] = dbconn.retrieveDownloadURL(idpackage)
2349 self.pkgmeta['name'] = dbconn.retrieveName(idpackage)
2350 self.pkgmeta['messages'] = dbconn.retrieveMessages(idpackage)
2351 self.pkgmeta['checksum'] = dbconn.retrieveDigest(idpackage)
2352 sha1, sha256, sha512 = dbconn.retrieveSignatures(idpackage)
2353 signatures = {
2354 'sha1': sha1,
2355 'sha256': sha256,
2356 'sha512': sha512,
2357 }
2358 self.pkgmeta['signatures'] = signatures
2359 self.pkgmeta['accept_license'] = \
2360 dbconn.retrieveLicensedataKeys(idpackage)
2361 self.pkgmeta['conflicts'] = \
2362 self.Entropy.get_match_conflicts(self.matched_atom)
2363
2364 description = dbconn.retrieveDescription(idpackage)
2365 if description:
2366 if len(description) > 74:
2367 description = description[:74].strip()
2368 description += "..."
2369 self.pkgmeta['description'] = description
2370
2371 # fill action queue
2372 self.pkgmeta['removeidpackage'] = -1
2373 removeConfig = False
2374 if self.metaopts.has_key('removeconfig'):
2375 removeConfig = self.metaopts.get('removeconfig')
2376
2377 self.pkgmeta['remove_metaopts'] = {
2378 'removeconfig': True,
2379 }
2380 if self.metaopts.has_key('remove_metaopts'):
2381 self.pkgmeta['remove_metaopts'] = \
2382 self.metaopts.get('remove_metaopts')
2383
2384 self.pkgmeta['merge_from'] = None
2385 mf = self.metaopts.get('merge_from')
2386 if mf != None:
2387 self.pkgmeta['merge_from'] = unicode(mf)
2388 self.pkgmeta['removeconfig'] = removeConfig
2389
2390 pkgkey = entropy.tools.dep_getkey(self.pkgmeta['atom'])
2391 inst_idpackage, inst_rc = self.Entropy.clientDbconn.atomMatch(pkgkey,
2392 matchSlot = self.pkgmeta['slot'])
2393
2394 # filled later...
2395 self.pkgmeta['removecontent'] = set()
2396 self.pkgmeta['removeidpackage'] = inst_idpackage
2397
2398 if self.pkgmeta['removeidpackage'] != -1:
2399 avail = self.Entropy.clientDbconn.isIdpackageAvailable(
2400 self.pkgmeta['removeidpackage'])
2401 if avail:
2402 inst_atom = self.Entropy.clientDbconn.retrieveAtom(
2403 self.pkgmeta['removeidpackage'])
2404 self.pkgmeta['removeatom'] = inst_atom
2405 else:
2406 self.pkgmeta['removeidpackage'] = -1
2407
2408 # smartpackage ?
2409 self.pkgmeta['smartpackage'] = False
2410 # set unpack dir and image dir
2411 if self.pkgmeta['repository'].endswith(etpConst['packagesext']):
2412
2413 # FIXME: add repository arch metadata to entropy.db
2414 # do arch check
2415 compiled_arch = dbconn.retrieveDownloadURL(idpackage)
2416 if compiled_arch.find("/"+etpSys['arch']+"/") == -1:
2417 self.pkgmeta.clear()
2418 self.__prepared = False
2419 return -1
2420
2421 repo_data = self.Entropy.SystemSettings['repositories']
2422 repo_meta = repo_data['available'][self.pkgmeta['repository']]
2423 self.pkgmeta['smartpackage'] = repo_meta['smartpackage']
2424 self.pkgmeta['pkgpath'] = repo_meta['pkgpath']
2425
2426 else:
2427 self.pkgmeta['pkgpath'] = etpConst['entropyworkdir'] + \
2428 os.path.sep + self.pkgmeta['download']
2429
2430 self.pkgmeta['unpackdir'] = etpConst['entropyunpackdir'] + \
2431 os.path.sep + self.pkgmeta['download']
2432
2433 self.pkgmeta['imagedir'] = etpConst['entropyunpackdir'] + \
2434 os.path.sep + self.pkgmeta['download'] + os.path.sep + \
2435 etpConst['entropyimagerelativepath']
2436
2437 self.pkgmeta['pkgdbpath'] = os.path.join(self.pkgmeta['unpackdir'],
2438 "edb/pkg.db")
2439
2440 # compare both versions and if they match, disable removeidpackage
2441 if self.pkgmeta['removeidpackage'] != -1:
2442
2443 # differential remove list
2444 self.pkgmeta['diffremoval'] = True
2445 self.pkgmeta['removeatom'] = \
2446 self.Entropy.clientDbconn.retrieveAtom(
2447 self.pkgmeta['removeidpackage'])
2448
2449 self.pkgmeta['triggers']['remove'] = \
2450 self.Entropy.clientDbconn.getTriggerInfo(
2451 self.pkgmeta['removeidpackage']
2452 )
2453 self.pkgmeta['triggers']['remove']['removecontent'] = \
2454 self.pkgmeta['removecontent'] # pass reference, not copy! nevva!
2455 self.pkgmeta['triggers']['remove']['accept_license'] = \
2456 self.Entropy.clientDbconn.retrieveLicensedataKeys(
2457 self.pkgmeta['removeidpackage'])
2458
2459 # set steps
2460 self.pkgmeta['steps'] = []
2461 if self.pkgmeta['conflicts']:
2462 self.pkgmeta['steps'].append("remove_conflicts")
2463 # install
2464 self.pkgmeta['steps'].append("unpack")
2465 # preinstall placed before preremove in order
2466 # to respect Spm order
2467 self.pkgmeta['steps'].append("preinstall")
2468 if (self.pkgmeta['removeidpackage'] != -1):
2469 self.pkgmeta['steps'].append("preremove")
2470 self.pkgmeta['steps'].append("install")
2471 if (self.pkgmeta['removeidpackage'] != -1):
2472 self.pkgmeta['steps'].append("postremove")
2473 self.pkgmeta['steps'].append("postinstall")
2474 self.pkgmeta['steps'].append("logmessages")
2475 self.pkgmeta['steps'].append("cleanup")
2476
2477 self.pkgmeta['triggers']['install'] = dbconn.getTriggerInfo(idpackage)
2478 self.pkgmeta['triggers']['install']['accept_license'] = \
2479 self.pkgmeta['accept_license']
2480 self.pkgmeta['triggers']['install']['unpackdir'] = \
2481 self.pkgmeta['unpackdir']
2482 self.pkgmeta['triggers']['install']['imagedir'] = \
2483 self.pkgmeta['imagedir']
2484
2485 # FIXME: move to entropy.spm
2486
2487 self.pkgmeta['xpakpath'] = etpConst['entropyunpackdir'] + \
2488 os.path.sep + self.pkgmeta['download'] + os.path.sep + \
2489 etpConst['entropyxpakrelativepath']
2490
2491 if not self.pkgmeta['merge_from']:
2492 self.pkgmeta['xpakstatus'] = None
2493 self.pkgmeta['xpakdir'] = self.pkgmeta['xpakpath'] + \
2494 os.path.sep + etpConst['entropyxpakdatarelativepath']
2495
2496 else:
2497 self.pkgmeta['xpakstatus'] = True
2498 portdbdir = 'var/db/pkg' # XXX hard coded ?
2499 portdbdir = os.path.join(self.pkgmeta['merge_from'], portdbdir)
2500 portdbdir = os.path.join(portdbdir, self.pkgmeta['category'])
2501 portdbdir = os.path.join(portdbdir, self.pkgmeta['name'] + "-" + \
2502 self.pkgmeta['version'])
2503
2504 self.pkgmeta['xpakdir'] = portdbdir
2505
2506 self.pkgmeta['triggers']['install']['xpakdir'] = \
2507 self.pkgmeta['xpakdir']
2508
2509
2510 return 0
2511
2513 self.pkgmeta.clear()
2514
2515 idpackage, repository = self.matched_atom
2516 dochecksum = True
2517
2518 # fetch abort function
2519 if self.metaopts.has_key('fetch_abort_function'):
2520 self.fetch_abort_function = \
2521 self.metaopts.pop('fetch_abort_function')
2522
2523 if self.metaopts.has_key('dochecksum'):
2524 dochecksum = self.metaopts.get('dochecksum')
2525
2526 # fetch_path is the path where data should be downloaded
2527 # at the moment is implemented only for sources = True
2528 if self.metaopts.has_key('fetch_path'):
2529 fetch_path = self.metaopts.get('fetch_path')
2530 if entropy.tools.is_valid_path(fetch_path):
2531 self.pkgmeta['fetch_path'] = fetch_path
2532
2533 self.pkgmeta['repository'] = repository
2534 self.pkgmeta['idpackage'] = idpackage
2535 dbconn = self.Entropy.open_repository(repository)
2536 self.pkgmeta['atom'] = dbconn.retrieveAtom(idpackage)
2537 if sources:
2538 self.pkgmeta['download'] = dbconn.retrieveSources(idpackage,
2539 extended = True)
2540 else:
2541 self.pkgmeta['checksum'] = dbconn.retrieveDigest(idpackage)
2542 sha1, sha256, sha512 = dbconn.retrieveSignatures(idpackage)
2543 signatures = {
2544 'sha1': sha1,
2545 'sha256': sha256,
2546 'sha512': sha512,
2547 }
2548 self.pkgmeta['signatures'] = signatures
2549 self.pkgmeta['download'] = dbconn.retrieveDownloadURL(idpackage)
2550
2551 if not self.pkgmeta['download']:
2552 self.pkgmeta['fetch_not_available'] = True
2553 return 0
2554
2555 self.pkgmeta['verified'] = False
2556 self.pkgmeta['steps'] = []
2557 if not repository.endswith(etpConst['packagesext']) and not sources:
2558 dl_check = self.Entropy.check_needed_package_download(
2559 self.pkgmeta['download'], None)
2560
2561 if dl_check < 0:
2562 self.pkgmeta['steps'].append("fetch")
2563 if dochecksum:
2564 self.pkgmeta['steps'].append("checksum")
2565
2566 elif sources:
2567 self.pkgmeta['steps'].append("sources_fetch")
2568
2569 if sources:
2570 # create sources destination directory
2571 unpack_dir = os.path.join(etpConst['entropyunpackdir'],
2572 "sources", self.pkgmeta['atom'])
2573 self.pkgmeta['unpackdir'] = unpack_dir
2574
2575 if not self.pkgmeta.get('fetch_path'):
2576 if os.path.lexists(unpack_dir):
2577 if os.path.isfile(unpack_dir):
2578 os.remove(unpack_dir)
2579 elif os.path.isdir(unpack_dir):
2580 shutil.rmtree(unpack_dir, True)
2581 if not os.path.lexists(unpack_dir):
2582 os.makedirs(unpack_dir, 0775)
2583 const_setup_perms(unpack_dir, etpConst['entropygid'])
2584 return 0
2585
2586 # downloading binary package
2587 # if file exists, first checksum then fetch
2588 down_path = os.path.join(etpConst['entropyworkdir'],
2589 self.pkgmeta['download'])
2590 if os.access(down_path, os.R_OK | os.F_OK):
2591 # check size first
2592 repo_size = dbconn.retrieveSize(idpackage)
2593 f = open(down_path, "r")
2594 f.seek(0, os.SEEK_END)
2595 disk_size = f.tell()
2596 f.close()
2597 if repo_size == disk_size:
2598 self.pkgmeta['steps'].reverse()
2599
2600 return 0
2601
2603 self.pkgmeta.clear()
2604
2605 if not isinstance(self.matched_atom, list):
2606 raise IncorrectParameter("IncorrectParameter: "
2607 "matched_atom must be a list of tuples, not %s" % (
2608 type(self.matched_atom,)
2609 )
2610 )
2611
2612 dochecksum = True
2613
2614 # meta options
2615 if self.metaopts.has_key('fetch_abort_function'):
2616 self.fetch_abort_function = \
2617 self.metaopts.pop('fetch_abort_function')
2618
2619 if self.metaopts.has_key('dochecksum'):
2620 dochecksum = self.metaopts.get('dochecksum')
2621 self.pkgmeta['checksum'] = dochecksum
2622
2623 matches = self.matched_atom
2624 self.pkgmeta['matches'] = matches
2625 self.pkgmeta['atoms'] = []
2626 self.pkgmeta['repository_atoms'] = {}
2627 temp_fetch_list = []
2628 temp_checksum_list = []
2629 temp_already_downloaded_count = 0
2630 etp_workdir = etpConst['entropyworkdir']
2631 for idpackage, repository in matches:
2632
2633 if repository.endswith(etpConst['packagesext']):
2634 continue
2635
2636 dbconn = self.Entropy.open_repository(repository)
2637 myatom = dbconn.retrieveAtom(idpackage)
2638
2639 # general purpose metadata
2640 self.pkgmeta['atoms'].append(myatom)
2641 if not self.pkgmeta['repository_atoms'].has_key(repository):
2642 self.pkgmeta['repository_atoms'][repository] = set()
2643 self.pkgmeta['repository_atoms'][repository].add(myatom)
2644
2645 download = dbconn.retrieveDownloadURL(idpackage)
2646 digest = dbconn.retrieveDigest(idpackage)
2647
2648 sha1, sha256, sha512 = dbconn.retrieveSignatures(idpackage)
2649 signatures = {
2650 'sha1': sha1,
2651 'sha256': sha256,
2652 'sha512': sha512,
2653 }
2654
2655 repo_size = dbconn.retrieveSize(idpackage)
2656 orig_branch = self.Entropy.get_branch_from_download_relative_uri(
2657 download)
2658 if self.Entropy.check_needed_package_download(download, None) < 0:
2659 obj = (repository, orig_branch, download, digest, signatures,)
2660 temp_fetch_list.append(obj)
2661 continue
2662
2663 elif dochecksum:
2664 obj = (repository, orig_branch, download, digest, signatures,)
2665 temp_checksum_list.append(obj)
2666
2667 down_path = os.path.join(etp_workdir, download)
2668 if os.path.isfile(down_path):
2669 with open(down_path, "r") as f:
2670 f.seek(0, os.SEEK_END)
2671 disk_size = f.tell()
2672 if repo_size == disk_size:
2673 temp_already_downloaded_count += 1
2674
2675 self.pkgmeta['steps'] = []
2676 self.pkgmeta['multi_fetch_list'] = temp_fetch_list
2677 self.pkgmeta['multi_checksum_list'] = temp_checksum_list
2678 if self.pkgmeta['multi_fetch_list']:
2679 self.pkgmeta['steps'].append("multi_fetch")
2680 if self.pkgmeta['multi_checksum_list']:
2681 self.pkgmeta['steps'].append("multi_checksum")
2682 if temp_already_downloaded_count == len(temp_checksum_list):
2683 self.pkgmeta['steps'].reverse()
2684
2685 return 0
2686
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Thu Sep 3 14:56:11 2009 | http://epydoc.sourceforge.net |