1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
from __future__ import print_function
import argparse
import fnmatch
import os.path
import sys
import ssg.yaml
from tests.common import stability
def describe_change(difference, name):
msg = ""
msg += stability.describe_changeset(
"Following selections were added to the {name} profile:\n".format(name=name),
difference.added,
)
msg += stability.describe_changeset(
"Following selections were removed from the {name} profile:\n".format(name=name),
difference.removed,
)
return msg.rstrip()
def compare_sets(reference, sample):
reference = set(reference)
sample = set(sample)
result = stability.Difference()
result.added = list(sample.difference(reference))
result.removed = list(reference.difference(sample))
return result
def get_references_filenames(ref_root):
found = []
for root, dirs, files in os.walk(ref_root):
for basename in files:
if fnmatch.fnmatch(basename, "*.profile"):
filename = os.path.join(root, basename)
found.append(filename)
return found
def corresponding_product_built(build_dir, reference_fname):
ref_path_components = reference_fname.split(os.path.sep)
product_id = ref_path_components[-2]
return os.path.isdir(os.path.join(build_dir, product_id))
def get_matching_compiled_profile_filename(build_dir, reference_fname):
ref_path_components = reference_fname.split(os.path.sep)
product_id = ref_path_components[-2]
profile_fname = ref_path_components[-1]
matching_filename = os.path.join(build_dir, product_id, "profiles", profile_fname)
if os.path.isfile(matching_filename):
return matching_filename
def get_selections_key_from_yaml(yaml_fname):
return ssg.yaml.open_raw(yaml_fname)["selections"]
def get_profile_name_from_reference_filename(fname):
path_components = fname.split(os.path.sep)
product_id = path_components[-2]
profile_id = os.path.splitext(path_components[-1])[0]
name = "{product_id}'s {profile_id}".format(
product_id=product_id, profile_id=profile_id)
return name
def get_reference_vs_built_difference(reference_fname, built_fname):
ref_selections = get_selections_key_from_yaml(reference_fname)
built_selections = get_selections_key_from_yaml(built_fname)
difference = compare_sets(ref_selections, built_selections)
return difference
def inform_and_append_fix_based_on_reference_compiled_profile(ref, build_root, fix_commands):
if not corresponding_product_built(build_root, ref):
return
compiled_profile = get_matching_compiled_profile_filename(build_root, ref)
if not compiled_profile:
msg = ("Unexpectedly unable to find compiled profile corresponding"
"to the test file {ref}, although the corresponding product has been built. "
"This indicates that a profile we have tests for is missing."
.format(ref=ref))
raise RuntimeError(msg)
difference = get_reference_vs_built_difference(ref, compiled_profile)
if not difference.empty:
comprehensive_profile_name = get_profile_name_from_reference_filename(ref)
stability.report_comparison(comprehensive_profile_name, difference, describe_change)
fix_commands.append(
"cp '{compiled}' '{reference}'"
.format(compiled=compiled_profile, reference=ref)
)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("build_root")
parser.add_argument("test_data_root")
args = parser.parse_args()
reference_files = get_references_filenames(args.test_data_root)
if not reference_files:
raise RuntimeError("Unable to find any reference profiles in {test_root}"
.format(test_root=args.test_data_root))
fix_commands = []
for ref in reference_files:
inform_and_append_fix_based_on_reference_compiled_profile(
ref, args.build_root, fix_commands)
if fix_commands:
msg = (
"If changes to mentioned profiles are intentional, "
"copy those compiled files, so they become the new reference:\n{fixes}\n"
"Please remember that if you change a profile that is extended by other profiles, "
"changes propagate to derived profiles. "
"If those changes are unwanted, you have to supress them "
"using explicit selections or !unselections in derived profiles."
.format(fixes="\n".join(fix_commands)))
print(msg, file=sys.stderr)
sys.exit(bool(fix_commands))
if __name__ == "__main__":
main()
|