def _grab_global_updates(self): from portage.update import grab_updates, parse_updates retupdates = {} errors = [] for repo_name in self._portdb.getRepositories(): repo = self._portdb.getRepositoryPath(repo_name) updpath = os.path.join(repo, "profiles", "updates") if not os.path.isdir(updpath): continue try: rawupdates = grab_updates(updpath) except portage.exception.DirectoryNotFound: rawupdates = [] upd_commands = [] for mykey, mystat, mycontent in rawupdates: commands, errors = parse_updates(mycontent) upd_commands.extend(commands) errors.extend(errors) retupdates[repo_name] = upd_commands if self._master_repo in retupdates: retupdates['DEFAULT'] = retupdates[self._master_repo] return retupdates, errors
def testParseUpdates(self): test_cases = (( """ slotmove invalid_atom 0 3 slotmove !=invalid/blocker-3* 0 3 slotmove =valid/atom-3* 0 3 invalid_extra_token slotmove =valid/atom-3* 0 3 slotmove =valid/atom-3* 0 3/3.1 slotmove =valid/atom-3* 0/0 3 move valid/atom1 valid/atom2 invalid_extra_token move valid/atom1 invalid_atom2 move invalid_atom1 valid/atom2 move !invalid/blocker1 valid/atom2 move valid/atom1 !invalid/blocker2 move =invalid/operator-1* valid/atom2 move valid/atom1 =invalid/operator-2* move valid/atom1 valid/atom2 """, [ ['slotmove', Atom('=valid/atom-3*'), '0', '3'], ['move', Atom('valid/atom1'), Atom('valid/atom2')], ], 12, ), ) for input_content, expected_output, expected_error_count in test_cases: output_data, errors = parse_updates(input_content) self.assertEqual(output_data, expected_output) self.assertEqual(len(errors), expected_error_count)
def testParseUpdates(self): test_cases = ( ( """ slotmove invalid_atom 0 3 slotmove !=invalid/blocker-3* 0 3 slotmove =valid/atom-3* 0 3 invalid_extra_token slotmove =valid/atom-3* 0 3 slotmove =valid/atom-3* 0 3/3.1 slotmove =valid/atom-3* 0/0 3 move valid/atom1 valid/atom2 invalid_extra_token move valid/atom1 invalid_atom2 move invalid_atom1 valid/atom2 move !invalid/blocker1 valid/atom2 move valid/atom1 !invalid/blocker2 move =invalid/operator-1* valid/atom2 move valid/atom1 =invalid/operator-2* move valid/atom1 valid/atom2 """, [ ['slotmove', Atom('=valid/atom-3*'), '0', '3'], ['move', Atom('valid/atom1'), Atom('valid/atom2')], ], 12, ), ) for input_content, expected_output, expected_error_count in test_cases: output_data, errors = parse_updates(input_content) self.assertEqual(output_data, expected_output) self.assertEqual(len(errors), expected_error_count)
def testParseUpdates(self): test_cases = ( ( """ slotmove invalid_atom 0 3 slotmove !=invalid/blocker-3* 0 3 slotmove =valid/atom-3* 0 3 invalid_extra_token slotmove =valid/atom-3* 0 3 move valid/atom1 valid/atom2 invalid_extra_token move valid/atom1 invalid_atom2 move invalid_atom1 valid/atom2 move !invalid/blocker1 valid/atom2 move valid/atom1 !invalid/blocker2 move =invalid/operator-1* valid/atom2 move valid/atom1 =invalid/operator-2* move valid/atom1 valid/atom2 """, [["slotmove", Atom("=valid/atom-3*"), "0", "3"], ["move", Atom("valid/atom1"), Atom("valid/atom2")]], 10, ), ) for input_content, expected_output, expected_error_count in test_cases: output_data, errors = parse_updates(input_content) self.assertEqual(output_data, expected_output) self.assertEqual(len(errors), expected_error_count)
def grab_global_updates(portdb): retupdates = {} for repo_name in portdb.getRepositories(): repo = portdb.getRepositoryPath(repo_name) updpath = os.path.join(repo, "profiles", "updates") if not os.path.isdir(updpath): continue try: rawupdates = grab_updates(updpath) except portage.exception.DirectoryNotFound: rawupdates = [] upd_commands = [] for mykey, mystat, mycontent in rawupdates: commands, errors = parse_updates(mycontent) upd_commands.extend(commands) retupdates[repo_name] = upd_commands master_repo = portdb.repositories.mainRepo() if master_repo is not None: master_repo = master_repo.name if master_repo in retupdates: retupdates['DEFAULT'] = retupdates[master_repo] return retupdates
def grab_global_updates(portdir): updpath = os.path.join(portdir, "profiles", "updates") try: rawupdates = grab_updates(updpath) except portage.exception.DirectoryNotFound: rawupdates = [] upd_commands = [] for mykey, mystat, mycontent in rawupdates: commands, errors = parse_updates(mycontent) upd_commands.extend(commands) return upd_commands
def grab_global_updates(portdir): from portage.update import grab_updates, parse_updates updpath = os.path.join(portdir, "profiles", "updates") try: rawupdates = grab_updates(updpath) except portage.exception.DirectoryNotFound: rawupdates = [] upd_commands = [] for mykey, mystat, mycontent in rawupdates: commands, errors = parse_updates(mycontent) upd_commands.extend(commands) return upd_commands
def _do_global_updates(trees, prev_mtimes, quiet=False, if_mtime_changed=True): root = trees._running_eroot mysettings = trees[root]["vartree"].settings portdb = trees[root]["porttree"].dbapi vardb = trees[root]["vartree"].dbapi bindb = trees[root]["bintree"].dbapi world_file = os.path.join(mysettings['EROOT'], WORLD_FILE) world_list = grabfile(world_file) world_modified = False world_warnings = set() updpath_map = {} # Maps repo_name to list of updates. If a given repo has no updates # directory, it will be omitted. If a repo has an updates directory # but none need to be applied (according to timestamp logic), the # value in the dict will be an empty list. repo_map = {} timestamps = {} retupd = False update_notice_printed = False for repo_name in portdb.getRepositories(): repo = portdb.getRepositoryPath(repo_name) updpath = os.path.join(repo, "profiles", "updates") if not os.path.isdir(updpath): continue if updpath in updpath_map: repo_map[repo_name] = updpath_map[updpath] continue try: if if_mtime_changed: update_data = grab_updates(updpath, prev_mtimes=prev_mtimes) else: update_data = grab_updates(updpath) except DirectoryNotFound: continue myupd = [] updpath_map[updpath] = myupd repo_map[repo_name] = myupd if len(update_data) > 0: for mykey, mystat, mycontent in update_data: if not update_notice_printed: update_notice_printed = True writemsg_stdout("\n") writemsg_stdout( colorize("GOOD", _("Performing Global Updates\n"))) writemsg_stdout( _("(Could take a couple of minutes if you have a lot of binary packages.)\n" )) if not quiet: writemsg_stdout(_(" %s='update pass' %s='binary update' " "%s='/var/db update' %s='/var/db move'\n" " %s='/var/db SLOT move' %s='binary move' " "%s='binary SLOT move'\n %s='update /etc/portage/package.*'\n") % \ (bold("."), bold("*"), bold("#"), bold("@"), bold("s"), bold("%"), bold("S"), bold("p"))) valid_updates, errors = parse_updates(mycontent) myupd.extend(valid_updates) if not quiet: writemsg_stdout(bold(mykey)) writemsg_stdout(len(valid_updates) * "." + "\n") if len(errors) == 0: # Update our internal mtime since we # processed all of our directives. timestamps[mykey] = mystat[stat.ST_MTIME] else: for msg in errors: writemsg("%s\n" % msg, noiselevel=-1) if myupd: retupd = True if retupd: if os.access(bindb.bintree.pkgdir, os.W_OK): # Call binarytree.populate(), since we want to make sure it's # only populated with local packages here (getbinpkgs=0). bindb.bintree.populate() else: bindb = None master_repo = portdb.repositories.mainRepo() if master_repo is not None: master_repo = master_repo.name if master_repo in repo_map: repo_map['DEFAULT'] = repo_map[master_repo] for repo_name, myupd in repo_map.items(): if repo_name == 'DEFAULT': continue if not myupd: continue def repo_match(repository): return repository == repo_name or \ (repo_name == master_repo and repository not in repo_map) def _world_repo_match(atoma, atomb): """ Check whether to perform a world change from atoma to atomb. If best vardb match for atoma comes from the same repository as the update file, allow that. Additionally, if portdb still can find a match for old atom name, warn about that. """ matches = vardb.match(atoma) if not matches: matches = vardb.match(atomb) if matches and \ repo_match(vardb.aux_get(best(matches), ['repository'])[0]): if portdb.match(atoma): world_warnings.add((atoma, atomb)) return True else: return False for update_cmd in myupd: for pos, atom in enumerate(world_list): new_atom = update_dbentry(update_cmd, atom) if atom != new_atom: if _world_repo_match(atom, new_atom): world_list[pos] = new_atom world_modified = True for update_cmd in myupd: if update_cmd[0] == "move": moves = vardb.move_ent(update_cmd, repo_match=repo_match) if moves: writemsg_stdout(moves * "@") if bindb: moves = bindb.move_ent(update_cmd, repo_match=repo_match) if moves: writemsg_stdout(moves * "%") elif update_cmd[0] == "slotmove": moves = vardb.move_slot_ent(update_cmd, repo_match=repo_match) if moves: writemsg_stdout(moves * "s") if bindb: moves = bindb.move_slot_ent(update_cmd, repo_match=repo_match) if moves: writemsg_stdout(moves * "S") if world_modified: world_list.sort() write_atomic(world_file, "".join("%s\n" % (x, ) for x in world_list)) if world_warnings: # XXX: print warning that we've updated world entries # and the old name still matches something (from an overlay)? pass if retupd: def _config_repo_match(repo_name, atoma, atomb): """ Check whether to perform a world change from atoma to atomb. If best vardb match for atoma comes from the same repository as the update file, allow that. Additionally, if portdb still can find a match for old atom name, warn about that. """ matches = vardb.match(atoma) if not matches: matches = vardb.match(atomb) if not matches: return False repository = vardb.aux_get(best(matches), ['repository'])[0] return repository == repo_name or \ (repo_name == master_repo and repository not in repo_map) update_config_files(root, shlex_split(mysettings.get("CONFIG_PROTECT", "")), shlex_split( mysettings.get("CONFIG_PROTECT_MASK", "")), repo_map, match_callback=_config_repo_match, case_insensitive="case-insensitive-fs" in mysettings.features) # The above global updates proceed quickly, so they # are considered a single mtimedb transaction. if timestamps: # We do not update the mtime in the mtimedb # until after _all_ of the above updates have # been processed because the mtimedb will # automatically commit when killed by ctrl C. for mykey, mtime in timestamps.items(): prev_mtimes[mykey] = mtime do_upgrade_packagesmessage = False # We gotta do the brute force updates for these now. if True: def onUpdate(_maxval, curval): if curval > 0: writemsg_stdout("#") if quiet: onUpdate = None vardb.update_ents(repo_map, onUpdate=onUpdate) if bindb: def onUpdate(_maxval, curval): if curval > 0: writemsg_stdout("*") if quiet: onUpdate = None bindb.update_ents(repo_map, onUpdate=onUpdate) else: do_upgrade_packagesmessage = 1 # Update progress above is indicated by characters written to stdout so # we print a couple new lines here to separate the progress output from # what follows. writemsg_stdout("\n\n") if do_upgrade_packagesmessage and bindb and \ bindb.cpv_all(): writemsg_stdout( _(" ** Skipping packages. Run 'fixpackages' or set it in FEATURES to fix the tbz2's in the packages directory.\n" )) writemsg_stdout(bold(_("Note: This can take a very long time."))) writemsg_stdout("\n") return retupd
def _do_global_updates(trees, prev_mtimes, quiet=False, if_mtime_changed=True): root = trees._running_eroot mysettings = trees[root]["vartree"].settings portdb = trees[root]["porttree"].dbapi vardb = trees[root]["vartree"].dbapi bindb = trees[root]["bintree"].dbapi world_file = os.path.join(mysettings['EROOT'], WORLD_FILE) world_list = grabfile(world_file) world_modified = False world_warnings = set() updpath_map = {} # Maps repo_name to list of updates. If a given repo has no updates # directory, it will be omitted. If a repo has an updates directory # but none need to be applied (according to timestamp logic), the # value in the dict will be an empty list. repo_map = {} timestamps = {} retupd = False update_notice_printed = False for repo_name in portdb.getRepositories(): repo = portdb.getRepositoryPath(repo_name) updpath = os.path.join(repo, "profiles", "updates") if not os.path.isdir(updpath): continue if updpath in updpath_map: repo_map[repo_name] = updpath_map[updpath] continue try: if if_mtime_changed: update_data = grab_updates(updpath, prev_mtimes=prev_mtimes) else: update_data = grab_updates(updpath) except DirectoryNotFound: continue myupd = [] updpath_map[updpath] = myupd repo_map[repo_name] = myupd if len(update_data) > 0: for mykey, mystat, mycontent in update_data: if not update_notice_printed: update_notice_printed = True writemsg_stdout("\n") if quiet: writemsg_stdout(colorize("GOOD", _("Performing Global Updates\n"))) writemsg_stdout(_("(Could take a couple of minutes if you have a lot of binary packages.)\n")) else: writemsg_stdout(colorize("GOOD", _("Performing Global Updates:\n"))) writemsg_stdout(_("(Could take a couple of minutes if you have a lot of binary packages.)\n")) writemsg_stdout(_(" %s='update pass' %s='binary update' " "%s='/var/db update' %s='/var/db move'\n" " %s='/var/db SLOT move' %s='binary move' " "%s='binary SLOT move'\n %s='update /etc/portage/package.*'\n") % \ (bold("."), bold("*"), bold("#"), bold("@"), bold("s"), bold("%"), bold("S"), bold("p"))) valid_updates, errors = parse_updates(mycontent) myupd.extend(valid_updates) if not quiet: writemsg_stdout(bold(mykey)) writemsg_stdout(len(valid_updates) * "." + "\n") if len(errors) == 0: # Update our internal mtime since we # processed all of our directives. timestamps[mykey] = mystat[stat.ST_MTIME] else: for msg in errors: writemsg("%s\n" % msg, noiselevel=-1) if myupd: retupd = True if retupd: if os.access(bindb.bintree.pkgdir, os.W_OK): # Call binarytree.populate(), since we want to make sure it's # only populated with local packages here (getbinpkgs=0). bindb.bintree.populate() else: bindb = None master_repo = portdb.getRepositoryName(portdb.porttree_root) if master_repo in repo_map: repo_map['DEFAULT'] = repo_map[master_repo] for repo_name, myupd in repo_map.items(): if repo_name == 'DEFAULT': continue if not myupd: continue def repo_match(repository): return repository == repo_name or \ (repo_name == master_repo and repository not in repo_map) def _world_repo_match(atoma, atomb): """ Check whether to perform a world change from atoma to atomb. If best vardb match for atoma comes from the same repository as the update file, allow that. Additionally, if portdb still can find a match for old atom name, warn about that. """ matches = vardb.match(atoma) if not matches: matches = vardb.match(atomb) if matches and \ repo_match(vardb.aux_get(best(matches), ['repository'])[0]): if portdb.match(atoma): world_warnings.add((atoma, atomb)) return True else: return False for update_cmd in myupd: for pos, atom in enumerate(world_list): new_atom = update_dbentry(update_cmd, atom) if atom != new_atom: if _world_repo_match(atom, new_atom): world_list[pos] = new_atom world_modified = True for update_cmd in myupd: if update_cmd[0] == "move": moves = vardb.move_ent(update_cmd, repo_match=repo_match) if moves: writemsg_stdout(moves * "@") if bindb: moves = bindb.move_ent(update_cmd, repo_match=repo_match) if moves: writemsg_stdout(moves * "%") elif update_cmd[0] == "slotmove": moves = vardb.move_slot_ent(update_cmd, repo_match=repo_match) if moves: writemsg_stdout(moves * "s") if bindb: moves = bindb.move_slot_ent(update_cmd, repo_match=repo_match) if moves: writemsg_stdout(moves * "S") if world_modified: world_list.sort() write_atomic(world_file, "".join("%s\n" % (x,) for x in world_list)) if world_warnings: # XXX: print warning that we've updated world entries # and the old name still matches something (from an overlay)? pass if retupd: def _config_repo_match(repo_name, atoma, atomb): """ Check whether to perform a world change from atoma to atomb. If best vardb match for atoma comes from the same repository as the update file, allow that. Additionally, if portdb still can find a match for old atom name, warn about that. """ matches = vardb.match(atoma) if not matches: matches = vardb.match(atomb) if not matches: return False repository = vardb.aux_get(best(matches), ['repository'])[0] return repository == repo_name or \ (repo_name == master_repo and repository not in repo_map) update_config_files(root, shlex_split(mysettings.get("CONFIG_PROTECT", "")), shlex_split(mysettings.get("CONFIG_PROTECT_MASK", "")), repo_map, match_callback=_config_repo_match) # The above global updates proceed quickly, so they # are considered a single mtimedb transaction. if timestamps: # We do not update the mtime in the mtimedb # until after _all_ of the above updates have # been processed because the mtimedb will # automatically commit when killed by ctrl C. for mykey, mtime in timestamps.items(): prev_mtimes[mykey] = mtime do_upgrade_packagesmessage = False # We gotta do the brute force updates for these now. if True: def onUpdate(maxval, curval): if curval > 0: writemsg_stdout("#") if quiet: onUpdate = None vardb.update_ents(repo_map, onUpdate=onUpdate) if bindb: def onUpdate(maxval, curval): if curval > 0: writemsg_stdout("*") if quiet: onUpdate = None bindb.update_ents(repo_map, onUpdate=onUpdate) else: do_upgrade_packagesmessage = 1 # Update progress above is indicated by characters written to stdout so # we print a couple new lines here to separate the progress output from # what follows. writemsg_stdout("\n\n") if do_upgrade_packagesmessage and bindb and \ bindb.cpv_all(): writemsg_stdout(_(" ** Skipping packages. Run 'fixpackages' or set it in FEATURES to fix the tbz2's in the packages directory.\n")) writemsg_stdout(bold(_("Note: This can take a very long time."))) writemsg_stdout("\n") return retupd
def _global_updates(trees, prev_mtimes): """ Perform new global updates if they exist in $PORTDIR/profiles/updates/. This simply returns if ROOT != "/" (when len(trees) != 1). If ROOT != "/" then the user should instead use emaint --fix movebin and/or moveinst. @param trees: A dictionary containing portage trees. @type trees: dict @param prev_mtimes: A dictionary containing mtimes of files located in $PORTDIR/profiles/updates/. @type prev_mtimes: dict @rtype: None or List @return: None if no were no updates, otherwise a list of update commands that have been performed. """ # only do this if we're root and not running repoman/ebuild digest if secpass < 2 or \ "SANDBOX_ACTIVE" in os.environ or \ len(trees) != 1: return 0 root = "/" mysettings = trees["/"]["vartree"].settings updpath = os.path.join(mysettings["PORTDIR"], "profiles", "updates") try: if mysettings["PORTAGE_CALLER"] == "fixpackages": update_data = grab_updates(updpath) else: update_data = grab_updates(updpath, prev_mtimes) except DirectoryNotFound: writemsg(_("--- 'profiles/updates' is empty or " "not available. Empty portage tree?\n"), noiselevel=1) return 0 myupd = None if len(update_data) > 0: do_upgrade_packagesmessage = 0 myupd = [] timestamps = {} for mykey, mystat, mycontent in update_data: writemsg_stdout("\n\n") writemsg_stdout(colorize("GOOD", _("Performing Global Updates: "))+bold(mykey)+"\n") writemsg_stdout(_("(Could take a couple of minutes if you have a lot of binary packages.)\n")) writemsg_stdout(_(" %s='update pass' %s='binary update' " "%s='/var/db update' %s='/var/db move'\n" " %s='/var/db SLOT move' %s='binary move' " "%s='binary SLOT move'\n %s='update /etc/portage/package.*'\n") % \ (bold("."), bold("*"), bold("#"), bold("@"), bold("s"), bold("%"), bold("S"), bold("p"))) valid_updates, errors = parse_updates(mycontent) myupd.extend(valid_updates) writemsg_stdout(len(valid_updates) * "." + "\n") if len(errors) == 0: # Update our internal mtime since we # processed all of our directives. timestamps[mykey] = mystat[stat.ST_MTIME] else: for msg in errors: writemsg("%s\n" % msg, noiselevel=-1) world_file = os.path.join(root, WORLD_FILE) world_list = grabfile(world_file) world_modified = False for update_cmd in myupd: for pos, atom in enumerate(world_list): new_atom = update_dbentry(update_cmd, atom) if atom != new_atom: world_list[pos] = new_atom world_modified = True if world_modified: world_list.sort() write_atomic(world_file, "".join("%s\n" % (x,) for x in world_list)) update_config_files("/", mysettings.get("CONFIG_PROTECT","").split(), mysettings.get("CONFIG_PROTECT_MASK","").split(), myupd) vardb = trees["/"]["vartree"].dbapi bindb = trees["/"]["bintree"].dbapi if not os.access(bindb.bintree.pkgdir, os.W_OK): bindb = None else: # Call binarytree.populate(), since we want to make sure it's # only populated with local packages here (getbinpkgs=0). bindb.bintree.populate() for update_cmd in myupd: if update_cmd[0] == "move": moves = vardb.move_ent(update_cmd) if moves: writemsg_stdout(moves * "@") if bindb: moves = bindb.move_ent(update_cmd) if moves: writemsg_stdout(moves * "%") elif update_cmd[0] == "slotmove": moves = vardb.move_slot_ent(update_cmd) if moves: writemsg_stdout(moves * "s") if bindb: moves = bindb.move_slot_ent(update_cmd) if moves: writemsg_stdout(moves * "S") # The above global updates proceed quickly, so they # are considered a single mtimedb transaction. if len(timestamps) > 0: # We do not update the mtime in the mtimedb # until after _all_ of the above updates have # been processed because the mtimedb will # automatically commit when killed by ctrl C. for mykey, mtime in timestamps.items(): prev_mtimes[mykey] = mtime # We gotta do the brute force updates for these now. if mysettings["PORTAGE_CALLER"] == "fixpackages" or \ "fixpackages" in mysettings.features: def onUpdate(maxval, curval): if curval > 0: writemsg_stdout("#") vardb.update_ents(myupd, onUpdate=onUpdate) if bindb: def onUpdate(maxval, curval): if curval > 0: writemsg_stdout("*") bindb.update_ents(myupd, onUpdate=onUpdate) else: do_upgrade_packagesmessage = 1 # Update progress above is indicated by characters written to stdout so # we print a couple new lines here to separate the progress output from # what follows. print() print() if do_upgrade_packagesmessage and bindb and \ bindb.cpv_all(): writemsg_stdout(_(" ** Skipping packages. Run 'fixpackages' or set it in FEATURES to fix the tbz2's in the packages directory.\n")) writemsg_stdout(bold(_("Note: This can take a very long time."))) writemsg_stdout("\n") if myupd: return myupd