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