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