def check_dnf_transaction(context, mode): check_context_table(context, ["Action", "Package"]) # check changes in DNF transaction table lines = context.cmd_stdout.splitlines() dnf_transaction = parse_transaction_table(lines) for action, nevras in context.table: if action in ["absent", "present", "unchanged", "changed"]: continue for nevra in nevras.split(", "): if action.startswith('group-') or action.startswith('module-'): title = action.split('-')[0].capitalize() group = nevra if group not in dnf_transaction[action]: candidates = ", ".join([str(i) for i in sorted(dnf_transaction[action])]) raise AssertionError("[dnf] %s %s not %s; Possible candidates: %s" % ( title, group, action, candidates)) else: rpm = RPM(nevra) if rpm not in dnf_transaction[action]: candidates = ", ".join([str(i) for i in sorted(dnf_transaction[action])]) raise AssertionError("[dnf] Package %s not %s; Possible candidates: %s" % ( rpm, action, candidates)) if mode == 'exact_match': context_table = parse_context_table(context) for action, rpms in dnf_transaction.items(): delta = rpms.difference(context_table[action]) if delta: raise AssertionError( "[dnf] Following packages weren't captured in the table for action '%s': %s" % ( action, ", ".join([str(rpm) for rpm in sorted(delta)])))
def check_rpmdb_transaction(context, mode): check_context_table(context, ["Action", "Package"]) if not "rpmdb_pre" in context.dnf: raise ValueError("RPMDB snapshot wasn't created before running this step.") context.dnf["rpmdb_post"] = get_rpmdb_rpms(context.dnf.installroot) checked_rpmdb = {} # check changes in RPMDB rpmdb_transaction = diff_rpm_lists(context.dnf["rpmdb_pre"], context.dnf["rpmdb_post"]) for action, nevras in context.table: if action in ["broken"]: continue for nevra in nevras.split(", "): checked_rpmdb.setdefault(action, set()).add(nevra) if action.startswith('group-'): continue if action.startswith('module-'): continue rpm = RPM(nevra) if action == "reinstall" and rpm not in rpmdb_transaction["reinstall"]: action = "unchanged" if (action == "remove" and rpm not in rpmdb_transaction["remove"] and rpm in rpmdb_transaction["obsoleted"]): action = "obsoleted" elif (action == "obsoleted" and rpm not in rpmdb_transaction["obsoleted"] and rpm in rpmdb_transaction["remove"]): action = "remove" if action == "absent": if rpm in rpmdb_transaction["present"]: raise AssertionError("[rpmdb] Package %s not '%s'" % (rpm, action)) continue if rpm not in rpmdb_transaction[action]: candidates = ", ".join([str(i) for i in sorted(rpmdb_transaction[action])]) raise AssertionError("[rpmdb] Package %s not '%s'; Possible candidates: %s" % ( rpm, action, candidates)) if mode == 'exact_match': context_table = parse_context_table(context) for action in ["install", "remove", "upgrade", "downgrade"]: delta = [] for nevra in context_table[action].copy(): if nevra in rpmdb_transaction[action]: rpmdb_transaction[action].remove(nevra) elif action == "remove": # and nevra in rpmdb_transaction["obsolete"]: rpmdb_transaction["obsoleted"].remove(nevra) else: delta.append(nevra) if delta: raise AssertionError( "[rpmdb] Following packages weren't captured in the table for action '%s': %s" % ( action, ", ".join([str(rpm) for rpm in sorted(delta)])))
def parse_microdnf_transaction_table(lines): """ Find and parse transaction table. Return {action: set([rpms])} """ trans_start_re = re.compile(r"Package +Repository +Size") transaction_start = None for i in range(0, len(lines) - 1): if trans_start_re.match(lines[i]): transaction_start = i + 1 break assert transaction_start is not None, "Transaction table start not found" lines = lines[transaction_start:] transaction_end = None for i in range(0, len(lines)): if lines[i].startswith("Transaction Summary:"): transaction_end = i assert transaction_end is not None, "Transaction table end not found" lines = lines[:transaction_end] label_re = re.compile(r"^([^ ].+):$") replacing_re = re.compile(r"^replacing +(?P<nevra>[^ ]*)$") action = None result = [] for line in lines: line = line.strip() label_match = label_re.match(line) if label_match: action = ACTIONS[label_match.group(1)] continue replacing_match = replacing_re.match(line) if replacing_match: real_action = "replaced" package = replacing_match.group("nevra") else: real_action = action package = line.split(" ")[0] # use RPM to parse and format the NEVRA to add epoch if missing result.append((real_action, str(RPM(package)))) return sorted(result)
def parse_context_table(context): result = {} for action in ACTIONS.values(): result[action] = [] result["obsoleted"] = [] for action, nevras in context.table: if action not in result: continue if action.startswith('group-') or action.startswith('module-'): for group in nevras.split(", "): result[action].append(group) else: for nevra in nevras.split(", "): rpm = RPM(nevra) result[action].append(rpm) return result