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