1#!/usr/bin/env python3 2 3#Signed-off-by: Anne Mulhern <mulhern@yoctoproject.org> 4 5import argparse, os, shutil, sys, tempfile, traceback 6from os import path 7 8 9 10def get_config(lines): 11 """ 12 From a sequence of lines retrieve the question file name, question identifier 13 pairs. 14 """ 15 for l in lines: 16 if not l.startswith("#"): 17 try: 18 (coord, value) = l.split("=") 19 try: 20 (fname, ident) = coord.split(".") 21 yield fname, ident 22 except ValueError as e: 23 raise ValueError("Badly formatted coordinates %s in line %s." % (coord, l.strip())) 24 except ValueError as e: 25 raise ValueError("Skipping badly formatted line %s, %s" % (l.strip(), e)) 26 27 28 29def check_contains(line, name): 30 """ 31 Check if the value field for REQUIRE_DISTRO contains the given name. 32 @param name line The REQUIRE_DISTRO line 33 @param name name The name to look for in the value field of the line. 34 """ 35 try: 36 (label, distros) = line.split(":") 37 return name in distros.split() 38 except ValueError as e: 39 raise ValueError("Error splitting REQUIRE_DISTRO line: %s" % e) 40 41 42 43def add_requires(the_ident, distro, lines): 44 45 """ 46 Yield a sequence of lines the same as lines except that where 47 the_ident matches a question identifier change the REQUIRE_DISTRO so that 48 it includes the specified distro. 49 50 @param name the_ident The question identifier to be matched. 51 @param name distro The distribution to added to the questions REQUIRE_DISTRO 52 field. 53 @param lines The sequence to be processed. 54 """ 55 for l in lines: 56 yield l 57 if l.startswith("LABEL:"): 58 try: 59 (label, ident) = l.split(":") 60 if ident.strip() == the_ident: 61 break 62 except ValueError as e: 63 raise ValueError("Unexpected line %s in questions file." % l.strip()) 64 for l in lines: 65 if l.startswith("REQUIRE_DISTRO"): 66 if not check_contains(l, distro): 67 yield l.rstrip() + " " + distro + "\n" 68 else: 69 yield l 70 break; 71 else: 72 yield l 73 for l in lines: 74 yield l 75 76 77 78def xform_file(qfile, distro, qlabel): 79 """ 80 Transform a Questions file. 81 @param name qfile The designated questions file. 82 @param name distro The distribution to add to the required distributions. 83 @param name qlabel The question label for which the distro is to be added. 84 """ 85 questions_in = open(qfile) 86 questions_out = tempfile.NamedTemporaryFile(mode="w+", delete=False) 87 for l in add_requires(qlabel, distro, questions_in): 88 questions_out.write(l) 89 questions_out.close() 90 questions_in.close() 91 shutil.copystat(qfile, questions_out.name) 92 os.remove(qfile) 93 shutil.move(questions_out.name, qfile) 94 95 96 97def handle_args(parser): 98 parser.add_argument('config_file', 99 help = "Configuration file path.") 100 parser.add_argument('questions_dir', 101 help = "Directory containing Questions files.") 102 parser.add_argument('--distro', '-d', 103 help = "The distribution, the default is Yocto.", 104 default = "Yocto") 105 parser.add_argument('--debug', '-b', 106 help = "Print debug information.", 107 action = 'store_true') 108 return parser.parse_args() 109 110 111 112def check_args(args): 113 args.config_file = os.path.abspath(args.config_file) 114 args.questions_dir = os.path.abspath(args.questions_dir) 115 116 if not os.path.isdir(args.questions_dir): 117 raise ValueError("Specified Questions directory %s does not exist or is not a directory." % args.questions_dir) 118 119 if not os.path.isfile(args.config_file): 120 raise ValueError("Specified configuration file %s not found." % args.config_file) 121 122 123 124def main(): 125 opts = handle_args(argparse.ArgumentParser(description="A simple script that sets required questions based on the question/answer pairs in a configuration file.")) 126 127 try: 128 check_args(opts) 129 except ValueError as e: 130 if opts.debug: 131 traceback.print_exc() 132 else: 133 sys.exit("Fatal error:\n%s" % e) 134 135 136 try: 137 config_in = open(opts.config_file) 138 for qfile, qlabel in get_config(config_in): 139 questions_file = os.path.join(opts.questions_dir, qfile + ".txt") 140 xform_file(questions_file, opts.distro, qlabel) 141 config_in.close() 142 143 except IOError as e: 144 if opts.debug: 145 traceback.print_exc() 146 else: 147 sys.exit("Fatal error reading or writing file:\n%s" % e) 148 except ValueError as e: 149 if opts.debug: 150 traceback.print_exc() 151 else: 152 sys.exit("Fatal error:\n%s" % e) 153 154 155 156if __name__ == "__main__": 157 main() 158