diff options
| author | Tudor Florea <tudor.florea@enea.com> | 2015-10-09 22:59:03 +0200 |
|---|---|---|
| committer | Tudor Florea <tudor.florea@enea.com> | 2015-10-09 22:59:03 +0200 |
| commit | 972dcfcdbfe75dcfeb777150c136576cf1a71e99 (patch) | |
| tree | 97a61cd7e293d7ae9d56ef7ed0f81253365bb026 /scripts/lib | |
| download | poky-972dcfcdbfe75dcfeb777150c136576cf1a71e99.tar.gz | |
initial commit for Enea Linux 5.0 arm
Signed-off-by: Tudor Florea <tudor.florea@enea.com>
Diffstat (limited to 'scripts/lib')
213 files changed, 17582 insertions, 0 deletions
diff --git a/scripts/lib/bsp/__init__.py b/scripts/lib/bsp/__init__.py new file mode 100644 index 0000000000..8bbb6e1530 --- /dev/null +++ b/scripts/lib/bsp/__init__.py | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | # | ||
| 2 | # Yocto BSP tools library | ||
| 3 | # | ||
| 4 | # Copyright (c) 2012, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # AUTHORS | ||
| 21 | # Tom Zanussi <tom.zanussi (at] intel.com> | ||
| 22 | # | ||
diff --git a/scripts/lib/bsp/engine.py b/scripts/lib/bsp/engine.py new file mode 100644 index 0000000000..7d6be239da --- /dev/null +++ b/scripts/lib/bsp/engine.py | |||
| @@ -0,0 +1,1947 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2012, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This module implements the templating engine used by 'yocto-bsp' to | ||
| 22 | # create BSPs. The BSP templates are simply the set of files expected | ||
| 23 | # to appear in a generated BSP, marked up with a small set of tags | ||
| 24 | # used to customize the output. The engine parses through the | ||
| 25 | # templates and generates a Python program containing all the logic | ||
| 26 | # and input elements needed to display and retrieve BSP-specific | ||
| 27 | # information from the user. The resulting program uses those results | ||
| 28 | # to generate the final BSP files. | ||
| 29 | # | ||
| 30 | # AUTHORS | ||
| 31 | # Tom Zanussi <tom.zanussi (at] intel.com> | ||
| 32 | # | ||
| 33 | |||
| 34 | import os | ||
| 35 | import sys | ||
| 36 | from abc import ABCMeta, abstractmethod | ||
| 37 | from tags import * | ||
| 38 | import shlex | ||
| 39 | import json | ||
| 40 | import subprocess | ||
| 41 | import shutil | ||
| 42 | |||
| 43 | class Line(): | ||
| 44 | """ | ||
| 45 | Generic (abstract) container representing a line that will appear | ||
| 46 | in the BSP-generating program. | ||
| 47 | """ | ||
| 48 | __metaclass__ = ABCMeta | ||
| 49 | |||
| 50 | def __init__(self, line): | ||
| 51 | self.line = line | ||
| 52 | self.generated_line = "" | ||
| 53 | self.prio = sys.maxint | ||
| 54 | self.discard = False | ||
| 55 | |||
| 56 | @abstractmethod | ||
| 57 | def gen(self, context = None): | ||
| 58 | """ | ||
| 59 | Generate the final executable line that will appear in the | ||
| 60 | BSP-generation program. | ||
| 61 | """ | ||
| 62 | pass | ||
| 63 | |||
| 64 | def escape(self, line): | ||
| 65 | """ | ||
| 66 | Escape single and double quotes and backslashes until I find | ||
| 67 | something better (re.escape() escapes way too much). | ||
| 68 | """ | ||
| 69 | return line.replace("\\", "\\\\").replace("\"", "\\\"").replace("'", "\\'") | ||
| 70 | |||
| 71 | def parse_error(self, msg, lineno, line): | ||
| 72 | raise SyntaxError("%s: %s" % (msg, line)) | ||
| 73 | |||
| 74 | |||
| 75 | class NormalLine(Line): | ||
| 76 | """ | ||
| 77 | Container for normal (non-tag) lines. | ||
| 78 | """ | ||
| 79 | def __init__(self, line): | ||
| 80 | Line.__init__(self, line) | ||
| 81 | self.is_filename = False | ||
| 82 | self.is_dirname = False | ||
| 83 | self.out_filebase = None | ||
| 84 | |||
| 85 | def gen(self, context = None): | ||
| 86 | if self.is_filename: | ||
| 87 | line = "current_file = \"" + os.path.join(self.out_filebase, self.escape(self.line)) + "\"; of = open(current_file, \"w\")" | ||
| 88 | elif self.is_dirname: | ||
| 89 | dirname = os.path.join(self.out_filebase, self.escape(self.line)) | ||
| 90 | line = "if not os.path.exists(\"" + dirname + "\"): os.mkdir(\"" + dirname + "\")" | ||
| 91 | else: | ||
| 92 | line = "of.write(\"" + self.escape(self.line) + "\\n\")" | ||
| 93 | return line | ||
| 94 | |||
| 95 | |||
| 96 | class CodeLine(Line): | ||
| 97 | """ | ||
| 98 | Container for Python code tag lines. | ||
| 99 | """ | ||
| 100 | def __init__(self, line): | ||
| 101 | Line.__init__(self, line) | ||
| 102 | |||
| 103 | def gen(self, context = None): | ||
| 104 | return self.line | ||
| 105 | |||
| 106 | |||
| 107 | class Assignment: | ||
| 108 | """ | ||
| 109 | Representation of everything we know about {{=name }} tags. | ||
| 110 | Instances of these are used by Assignment lines. | ||
| 111 | """ | ||
| 112 | def __init__(self, start, end, name): | ||
| 113 | self.start = start | ||
| 114 | self.end = end | ||
| 115 | self.name = name | ||
| 116 | |||
| 117 | |||
| 118 | class AssignmentLine(NormalLine): | ||
| 119 | """ | ||
| 120 | Container for normal lines containing assignment tags. Assignment | ||
| 121 | tags must be in ascending order of 'start' value. | ||
| 122 | """ | ||
| 123 | def __init__(self, line): | ||
| 124 | NormalLine.__init__(self, line) | ||
| 125 | self.assignments = [] | ||
| 126 | |||
| 127 | def add_assignment(self, start, end, name): | ||
| 128 | self.assignments.append(Assignment(start, end, name)) | ||
| 129 | |||
| 130 | def gen(self, context = None): | ||
| 131 | line = self.escape(self.line) | ||
| 132 | |||
| 133 | for assignment in self.assignments: | ||
| 134 | replacement = "\" + " + assignment.name + " + \"" | ||
| 135 | idx = line.find(ASSIGN_TAG) | ||
| 136 | line = line[:idx] + replacement + line[idx + assignment.end - assignment.start:] | ||
| 137 | if self.is_filename: | ||
| 138 | return "current_file = \"" + os.path.join(self.out_filebase, line) + "\"; of = open(current_file, \"w\")" | ||
| 139 | elif self.is_dirname: | ||
| 140 | dirname = os.path.join(self.out_filebase, line) | ||
| 141 | return "if not os.path.exists(\"" + dirname + "\"): os.mkdir(\"" + dirname + "\")" | ||
| 142 | else: | ||
| 143 | return "of.write(\"" + line + "\\n\")" | ||
| 144 | |||
| 145 | |||
| 146 | class InputLine(Line): | ||
| 147 | """ | ||
| 148 | Base class for Input lines. | ||
| 149 | """ | ||
| 150 | def __init__(self, props, tag, lineno): | ||
| 151 | Line.__init__(self, tag) | ||
| 152 | self.props = props | ||
| 153 | self.lineno = lineno | ||
| 154 | |||
| 155 | try: | ||
| 156 | self.prio = int(props["prio"]) | ||
| 157 | except KeyError: | ||
| 158 | self.prio = sys.maxint | ||
| 159 | |||
| 160 | def gen(self, context = None): | ||
| 161 | try: | ||
| 162 | depends_on = self.props["depends-on"] | ||
| 163 | try: | ||
| 164 | depends_on_val = self.props["depends-on-val"] | ||
| 165 | except KeyError: | ||
| 166 | self.parse_error("No 'depends-on-val' for 'depends-on' property", | ||
| 167 | self.lineno, self.line) | ||
| 168 | except KeyError: | ||
| 169 | pass | ||
| 170 | |||
| 171 | |||
| 172 | class EditBoxInputLine(InputLine): | ||
| 173 | """ | ||
| 174 | Base class for 'editbox' Input lines. | ||
| 175 | |||
| 176 | props: | ||
| 177 | name: example - "Load address" | ||
| 178 | msg: example - "Please enter the load address" | ||
| 179 | result: | ||
| 180 | Sets the value of the variable specified by 'name' to | ||
| 181 | whatever the user typed. | ||
| 182 | """ | ||
| 183 | def __init__(self, props, tag, lineno): | ||
| 184 | InputLine.__init__(self, props, tag, lineno) | ||
| 185 | |||
| 186 | def gen(self, context = None): | ||
| 187 | InputLine.gen(self, context) | ||
| 188 | name = self.props["name"] | ||
| 189 | if not name: | ||
| 190 | self.parse_error("No input 'name' property found", | ||
| 191 | self.lineno, self.line) | ||
| 192 | msg = self.props["msg"] | ||
| 193 | if not msg: | ||
| 194 | self.parse_error("No input 'msg' property found", | ||
| 195 | self.lineno, self.line) | ||
| 196 | |||
| 197 | try: | ||
| 198 | default_choice = self.props["default"] | ||
| 199 | except KeyError: | ||
| 200 | default_choice = "" | ||
| 201 | |||
| 202 | msg += " [default: " + default_choice + "]" | ||
| 203 | |||
| 204 | line = name + " = default(raw_input(\"" + msg + " \"), " + name + ")" | ||
| 205 | |||
| 206 | return line | ||
| 207 | |||
| 208 | |||
| 209 | class GitRepoEditBoxInputLine(EditBoxInputLine): | ||
| 210 | """ | ||
| 211 | Base class for 'editbox' Input lines for user input of remote git | ||
| 212 | repos. This class verifies the existence and connectivity of the | ||
| 213 | specified git repo. | ||
| 214 | |||
| 215 | props: | ||
| 216 | name: example - "Load address" | ||
| 217 | msg: example - "Please enter the load address" | ||
| 218 | result: | ||
| 219 | Sets the value of the variable specified by 'name' to | ||
| 220 | whatever the user typed. | ||
| 221 | """ | ||
| 222 | def __init__(self, props, tag, lineno): | ||
| 223 | EditBoxInputLine.__init__(self, props, tag, lineno) | ||
| 224 | |||
| 225 | def gen(self, context = None): | ||
| 226 | EditBoxInputLine.gen(self, context) | ||
| 227 | name = self.props["name"] | ||
| 228 | if not name: | ||
| 229 | self.parse_error("No input 'name' property found", | ||
| 230 | self.lineno, self.line) | ||
| 231 | msg = self.props["msg"] | ||
| 232 | if not msg: | ||
| 233 | self.parse_error("No input 'msg' property found", | ||
| 234 | self.lineno, self.line) | ||
| 235 | |||
| 236 | try: | ||
| 237 | default_choice = self.props["default"] | ||
| 238 | except KeyError: | ||
| 239 | default_choice = "" | ||
| 240 | |||
| 241 | msg += " [default: " + default_choice + "]" | ||
| 242 | |||
| 243 | line = name + " = get_verified_git_repo(\"" + msg + "\"," + name + ")" | ||
| 244 | |||
| 245 | return line | ||
| 246 | |||
| 247 | |||
| 248 | class FileEditBoxInputLine(EditBoxInputLine): | ||
| 249 | """ | ||
| 250 | Base class for 'editbox' Input lines for user input of existing | ||
| 251 | files. This class verifies the existence of the specified file. | ||
| 252 | |||
| 253 | props: | ||
| 254 | name: example - "Load address" | ||
| 255 | msg: example - "Please enter the load address" | ||
| 256 | result: | ||
| 257 | Sets the value of the variable specified by 'name' to | ||
| 258 | whatever the user typed. | ||
| 259 | """ | ||
| 260 | def __init__(self, props, tag, lineno): | ||
| 261 | EditBoxInputLine.__init__(self, props, tag, lineno) | ||
| 262 | |||
| 263 | def gen(self, context = None): | ||
| 264 | EditBoxInputLine.gen(self, context) | ||
| 265 | name = self.props["name"] | ||
| 266 | if not name: | ||
| 267 | self.parse_error("No input 'name' property found", | ||
| 268 | self.lineno, self.line) | ||
| 269 | msg = self.props["msg"] | ||
| 270 | if not msg: | ||
| 271 | self.parse_error("No input 'msg' property found", | ||
| 272 | self.lineno, self.line) | ||
| 273 | |||
| 274 | try: | ||
| 275 | default_choice = self.props["default"] | ||
| 276 | except KeyError: | ||
| 277 | default_choice = "" | ||
| 278 | |||
| 279 | msg += " [default: " + default_choice + "]" | ||
| 280 | |||
| 281 | line = name + " = get_verified_file(\"" + msg + "\"," + name + ", True)" | ||
| 282 | |||
| 283 | return line | ||
| 284 | |||
| 285 | |||
| 286 | class BooleanInputLine(InputLine): | ||
| 287 | """ | ||
| 288 | Base class for boolean Input lines. | ||
| 289 | props: | ||
| 290 | name: example - "keyboard" | ||
| 291 | msg: example - "Got keyboard?" | ||
| 292 | result: | ||
| 293 | Sets the value of the variable specified by 'name' to "yes" or "no" | ||
| 294 | example - keyboard = "yes" | ||
| 295 | """ | ||
| 296 | def __init__(self, props, tag, lineno): | ||
| 297 | InputLine.__init__(self, props, tag, lineno) | ||
| 298 | |||
| 299 | def gen(self, context = None): | ||
| 300 | InputLine.gen(self, context) | ||
| 301 | name = self.props["name"] | ||
| 302 | if not name: | ||
| 303 | self.parse_error("No input 'name' property found", | ||
| 304 | self.lineno, self.line) | ||
| 305 | msg = self.props["msg"] | ||
| 306 | if not msg: | ||
| 307 | self.parse_error("No input 'msg' property found", | ||
| 308 | self.lineno, self.line) | ||
| 309 | |||
| 310 | try: | ||
| 311 | default_choice = self.props["default"] | ||
| 312 | except KeyError: | ||
| 313 | default_choice = "" | ||
| 314 | |||
| 315 | msg += " [default: " + default_choice + "]" | ||
| 316 | |||
| 317 | line = name + " = boolean(raw_input(\"" + msg + " \"), " + name + ")" | ||
| 318 | |||
| 319 | return line | ||
| 320 | |||
| 321 | |||
| 322 | class ListInputLine(InputLine): | ||
| 323 | """ | ||
| 324 | Base class for List-based Input lines. e.g. Choicelist, Checklist. | ||
| 325 | """ | ||
| 326 | __metaclass__ = ABCMeta | ||
| 327 | |||
| 328 | def __init__(self, props, tag, lineno): | ||
| 329 | InputLine.__init__(self, props, tag, lineno) | ||
| 330 | self.choices = [] | ||
| 331 | |||
| 332 | def gen_choicepair_list(self): | ||
| 333 | """Generate a list of 2-item val:desc lists from self.choices.""" | ||
| 334 | if not self.choices: | ||
| 335 | return None | ||
| 336 | |||
| 337 | choicepair_list = list() | ||
| 338 | |||
| 339 | for choice in self.choices: | ||
| 340 | choicepair = [] | ||
| 341 | choicepair.append(choice.val) | ||
| 342 | choicepair.append(choice.desc) | ||
| 343 | choicepair_list.append(choicepair) | ||
| 344 | |||
| 345 | return choicepair_list | ||
| 346 | |||
| 347 | def gen_degenerate_choicepair_list(self, choices): | ||
| 348 | """Generate a list of 2-item val:desc with val=desc from passed-in choices.""" | ||
| 349 | choicepair_list = list() | ||
| 350 | |||
| 351 | for choice in choices: | ||
| 352 | choicepair = [] | ||
| 353 | choicepair.append(choice) | ||
| 354 | choicepair.append(choice) | ||
| 355 | choicepair_list.append(choicepair) | ||
| 356 | |||
| 357 | return choicepair_list | ||
| 358 | |||
| 359 | def exec_listgen_fn(self, context = None): | ||
| 360 | """ | ||
| 361 | Execute the list-generating function contained as a string in | ||
| 362 | the "gen" property. | ||
| 363 | """ | ||
| 364 | retval = None | ||
| 365 | try: | ||
| 366 | fname = self.props["gen"] | ||
| 367 | modsplit = fname.split('.') | ||
| 368 | mod_fn = modsplit.pop() | ||
| 369 | mod = '.'.join(modsplit) | ||
| 370 | |||
| 371 | __import__(mod) | ||
| 372 | # python 2.7 has a better way to do this using importlib.import_module | ||
| 373 | m = sys.modules[mod] | ||
| 374 | |||
| 375 | fn = getattr(m, mod_fn) | ||
| 376 | if not fn: | ||
| 377 | self.parse_error("couldn't load function specified for 'gen' property ", | ||
| 378 | self.lineno, self.line) | ||
| 379 | retval = fn(context) | ||
| 380 | if not retval: | ||
| 381 | self.parse_error("function specified for 'gen' property returned nothing ", | ||
| 382 | self.lineno, self.line) | ||
| 383 | except KeyError: | ||
| 384 | pass | ||
| 385 | |||
| 386 | return retval | ||
| 387 | |||
| 388 | def gen_choices_str(self, choicepairs): | ||
| 389 | """ | ||
| 390 | Generate a numbered list of choices from a list of choicepairs | ||
| 391 | for display to the user. | ||
| 392 | """ | ||
| 393 | choices_str = "" | ||
| 394 | |||
| 395 | for i, choicepair in enumerate(choicepairs): | ||
| 396 | choices_str += "\t" + str(i + 1) + ") " + choicepair[1] + "\n" | ||
| 397 | |||
| 398 | return choices_str | ||
| 399 | |||
| 400 | def gen_choices_val_str(self, choicepairs): | ||
| 401 | """ | ||
| 402 | Generate an array of choice values corresponding to the | ||
| 403 | numbered list generated by gen_choices_str(). | ||
| 404 | """ | ||
| 405 | choices_val_list = "[" | ||
| 406 | |||
| 407 | for i, choicepair in enumerate(choicepairs): | ||
| 408 | choices_val_list += "\"" + choicepair[0] + "\"," | ||
| 409 | choices_val_list += "]" | ||
| 410 | |||
| 411 | return choices_val_list | ||
| 412 | |||
| 413 | def gen_choices_val_list(self, choicepairs): | ||
| 414 | """ | ||
| 415 | Generate an array of choice values corresponding to the | ||
| 416 | numbered list generated by gen_choices_str(). | ||
| 417 | """ | ||
| 418 | choices_val_list = [] | ||
| 419 | |||
| 420 | for i, choicepair in enumerate(choicepairs): | ||
| 421 | choices_val_list.append(choicepair[0]) | ||
| 422 | |||
| 423 | return choices_val_list | ||
| 424 | |||
| 425 | def gen_choices_list(self, context = None, checklist = False): | ||
| 426 | """ | ||
| 427 | Generate an array of choice values corresponding to the | ||
| 428 | numbered list generated by gen_choices_str(). | ||
| 429 | """ | ||
| 430 | choices = self.exec_listgen_fn(context) | ||
| 431 | if choices: | ||
| 432 | if len(choices) == 0: | ||
| 433 | self.parse_error("No entries available for input list", | ||
| 434 | self.lineno, self.line) | ||
| 435 | choicepairs = self.gen_degenerate_choicepair_list(choices) | ||
| 436 | else: | ||
| 437 | if len(self.choices) == 0: | ||
| 438 | self.parse_error("No entries available for input list", | ||
| 439 | self.lineno, self.line) | ||
| 440 | choicepairs = self.gen_choicepair_list() | ||
| 441 | |||
| 442 | return choicepairs | ||
| 443 | |||
| 444 | def gen_choices(self, context = None, checklist = False): | ||
| 445 | """ | ||
| 446 | Generate an array of choice values corresponding to the | ||
| 447 | numbered list generated by gen_choices_str(), display it to | ||
| 448 | the user, and process the result. | ||
| 449 | """ | ||
| 450 | msg = self.props["msg"] | ||
| 451 | if not msg: | ||
| 452 | self.parse_error("No input 'msg' property found", | ||
| 453 | self.lineno, self.line) | ||
| 454 | |||
| 455 | try: | ||
| 456 | default_choice = self.props["default"] | ||
| 457 | except KeyError: | ||
| 458 | default_choice = "" | ||
| 459 | |||
| 460 | msg += " [default: " + default_choice + "]" | ||
| 461 | |||
| 462 | choicepairs = self.gen_choices_list(context, checklist) | ||
| 463 | |||
| 464 | choices_str = self.gen_choices_str(choicepairs) | ||
| 465 | choices_val_list = self.gen_choices_val_list(choicepairs) | ||
| 466 | if checklist: | ||
| 467 | choiceval = default(find_choicevals(raw_input(msg + "\n" + choices_str), choices_val_list), default_choice) | ||
| 468 | else: | ||
| 469 | choiceval = default(find_choiceval(raw_input(msg + "\n" + choices_str), choices_val_list), default_choice) | ||
| 470 | |||
| 471 | return choiceval | ||
| 472 | |||
| 473 | |||
| 474 | def find_choiceval(choice_str, choice_list): | ||
| 475 | """ | ||
| 476 | Take number as string and return val string from choice_list, | ||
| 477 | empty string if oob. choice_list is a simple python list. | ||
| 478 | """ | ||
| 479 | choice_val = "" | ||
| 480 | |||
| 481 | try: | ||
| 482 | choice_idx = int(choice_str) | ||
| 483 | if choice_idx <= len(choice_list): | ||
| 484 | choice_idx -= 1 | ||
| 485 | choice_val = choice_list[choice_idx] | ||
| 486 | except ValueError: | ||
| 487 | pass | ||
| 488 | |||
| 489 | return choice_val | ||
| 490 | |||
| 491 | |||
| 492 | def find_choicevals(choice_str, choice_list): | ||
| 493 | """ | ||
| 494 | Take numbers as space-separated string and return vals list from | ||
| 495 | choice_list, empty list if oob. choice_list is a simple python | ||
| 496 | list. | ||
| 497 | """ | ||
| 498 | choice_vals = [] | ||
| 499 | |||
| 500 | choices = choice_str.split() | ||
| 501 | for choice in choices: | ||
| 502 | choice_vals.append(find_choiceval(choice, choice_list)) | ||
| 503 | |||
| 504 | return choice_vals | ||
| 505 | |||
| 506 | |||
| 507 | def default(input_str, name): | ||
| 508 | """ | ||
| 509 | Return default if no input_str, otherwise stripped input_str. | ||
| 510 | """ | ||
| 511 | if not input_str: | ||
| 512 | return name | ||
| 513 | |||
| 514 | return input_str.strip() | ||
| 515 | |||
| 516 | |||
| 517 | def verify_git_repo(giturl): | ||
| 518 | """ | ||
| 519 | Verify that the giturl passed in can be connected to. This can be | ||
| 520 | used as a check for the existence of the given repo and/or basic | ||
| 521 | git remote connectivity. | ||
| 522 | |||
| 523 | Returns True if the connection was successful, fals otherwise | ||
| 524 | """ | ||
| 525 | if not giturl: | ||
| 526 | return False | ||
| 527 | |||
| 528 | gitcmd = "git ls-remote %s > /dev/null 2>&1" % (giturl) | ||
| 529 | rc = subprocess.call(gitcmd, shell=True) | ||
| 530 | if rc == 0: | ||
| 531 | return True | ||
| 532 | |||
| 533 | return False | ||
| 534 | |||
| 535 | |||
| 536 | def get_verified_git_repo(input_str, name): | ||
| 537 | """ | ||
| 538 | Return git repo if verified, otherwise loop forever asking user | ||
| 539 | for filename. | ||
| 540 | """ | ||
| 541 | msg = input_str.strip() + " " | ||
| 542 | |||
| 543 | giturl = default(raw_input(msg), name) | ||
| 544 | |||
| 545 | while True: | ||
| 546 | if verify_git_repo(giturl): | ||
| 547 | return giturl | ||
| 548 | giturl = default(raw_input(msg), name) | ||
| 549 | |||
| 550 | |||
| 551 | def get_verified_file(input_str, name, filename_can_be_null): | ||
| 552 | """ | ||
| 553 | Return filename if the file exists, otherwise loop forever asking | ||
| 554 | user for filename. | ||
| 555 | """ | ||
| 556 | msg = input_str.strip() + " " | ||
| 557 | |||
| 558 | filename = default(raw_input(msg), name) | ||
| 559 | |||
| 560 | while True: | ||
| 561 | if not filename and filename_can_be_null: | ||
| 562 | return filename | ||
| 563 | if os.path.isfile(filename): | ||
| 564 | return filename | ||
| 565 | filename = default(raw_input(msg), name) | ||
| 566 | |||
| 567 | |||
| 568 | def replace_file(replace_this, with_this): | ||
| 569 | """ | ||
| 570 | Replace the given file with the contents of filename, retaining | ||
| 571 | the original filename. | ||
| 572 | """ | ||
| 573 | try: | ||
| 574 | replace_this.close() | ||
| 575 | shutil.copy(with_this, replace_this.name) | ||
| 576 | except IOError: | ||
| 577 | pass | ||
| 578 | |||
| 579 | |||
| 580 | def boolean(input_str, name): | ||
| 581 | """ | ||
| 582 | Return lowercase version of first char in string, or value in name. | ||
| 583 | """ | ||
| 584 | if not input_str: | ||
| 585 | return name | ||
| 586 | |||
| 587 | str = input_str.lower().strip() | ||
| 588 | if str and str[0] == "y" or str[0] == "n": | ||
| 589 | return str[0] | ||
| 590 | else: | ||
| 591 | return name | ||
| 592 | |||
| 593 | |||
| 594 | def strip_base(input_str): | ||
| 595 | """ | ||
| 596 | strip '/base' off the end of input_str, so we can use 'base' in | ||
| 597 | the branch names we present to the user. | ||
| 598 | """ | ||
| 599 | if input_str and input_str.endswith("/base"): | ||
| 600 | return input_str[:-len("/base")] | ||
| 601 | return input_str.strip() | ||
| 602 | |||
| 603 | |||
| 604 | deferred_choices = {} | ||
| 605 | |||
| 606 | def gen_choices_defer(input_line, context, checklist = False): | ||
| 607 | """ | ||
| 608 | Save the context hashed the name of the input item, which will be | ||
| 609 | passed to the gen function later. | ||
| 610 | """ | ||
| 611 | name = input_line.props["name"] | ||
| 612 | |||
| 613 | try: | ||
| 614 | nameappend = input_line.props["nameappend"] | ||
| 615 | except KeyError: | ||
| 616 | nameappend = "" | ||
| 617 | |||
| 618 | try: | ||
| 619 | branches_base = input_line.props["branches_base"] | ||
| 620 | except KeyError: | ||
| 621 | branches_base = "" | ||
| 622 | |||
| 623 | filename = input_line.props["filename"] | ||
| 624 | |||
| 625 | closetag_start = filename.find(CLOSE_TAG) | ||
| 626 | |||
| 627 | if closetag_start != -1: | ||
| 628 | filename = filename[closetag_start + len(CLOSE_TAG):] | ||
| 629 | |||
| 630 | filename = filename.strip() | ||
| 631 | filename = os.path.splitext(filename)[0] | ||
| 632 | |||
| 633 | captured_context = capture_context(context) | ||
| 634 | context["filename"] = filename | ||
| 635 | captured_context["filename"] = filename | ||
| 636 | context["nameappend"] = nameappend | ||
| 637 | captured_context["nameappend"] = nameappend | ||
| 638 | context["branches_base"] = branches_base | ||
| 639 | captured_context["branches_base"] = branches_base | ||
| 640 | |||
| 641 | deferred_choice = (input_line, captured_context, checklist) | ||
| 642 | key = name + "_" + filename + "_" + nameappend | ||
| 643 | deferred_choices[key] = deferred_choice | ||
| 644 | |||
| 645 | |||
| 646 | def invoke_deferred_choices(name): | ||
| 647 | """ | ||
| 648 | Invoke the choice generation function using the context hashed by | ||
| 649 | 'name'. | ||
| 650 | """ | ||
| 651 | deferred_choice = deferred_choices[name] | ||
| 652 | input_line = deferred_choice[0] | ||
| 653 | context = deferred_choice[1] | ||
| 654 | checklist = deferred_choice[2] | ||
| 655 | |||
| 656 | context["name"] = name | ||
| 657 | |||
| 658 | choices = input_line.gen_choices(context, checklist) | ||
| 659 | |||
| 660 | return choices | ||
| 661 | |||
| 662 | |||
| 663 | class ChoicelistInputLine(ListInputLine): | ||
| 664 | """ | ||
| 665 | Base class for choicelist Input lines. | ||
| 666 | props: | ||
| 667 | name: example - "xserver_choice" | ||
| 668 | msg: example - "Please select an xserver for this machine" | ||
| 669 | result: | ||
| 670 | Sets the value of the variable specified by 'name' to whichever Choice was chosen | ||
| 671 | example - xserver_choice = "xserver_vesa" | ||
| 672 | """ | ||
| 673 | def __init__(self, props, tag, lineno): | ||
| 674 | ListInputLine.__init__(self, props, tag, lineno) | ||
| 675 | |||
| 676 | def gen(self, context = None): | ||
| 677 | InputLine.gen(self, context) | ||
| 678 | |||
| 679 | gen_choices_defer(self, context) | ||
| 680 | name = self.props["name"] | ||
| 681 | nameappend = context["nameappend"] | ||
| 682 | filename = context["filename"] | ||
| 683 | |||
| 684 | try: | ||
| 685 | default_choice = self.props["default"] | ||
| 686 | except KeyError: | ||
| 687 | default_choice = "" | ||
| 688 | |||
| 689 | line = name + " = default(invoke_deferred_choices(\"" + name + "_" + filename + "_" + nameappend + "\"), \"" + default_choice + "\")" | ||
| 690 | |||
| 691 | return line | ||
| 692 | |||
| 693 | |||
| 694 | class ListValInputLine(InputLine): | ||
| 695 | """ | ||
| 696 | Abstract base class for choice and checkbox Input lines. | ||
| 697 | """ | ||
| 698 | def __init__(self, props, tag, lineno): | ||
| 699 | InputLine.__init__(self, props, tag, lineno) | ||
| 700 | |||
| 701 | try: | ||
| 702 | self.val = self.props["val"] | ||
| 703 | except KeyError: | ||
| 704 | self.parse_error("No input 'val' property found", self.lineno, self.line) | ||
| 705 | |||
| 706 | try: | ||
| 707 | self.desc = self.props["msg"] | ||
| 708 | except KeyError: | ||
| 709 | self.parse_error("No input 'msg' property found", self.lineno, self.line) | ||
| 710 | |||
| 711 | |||
| 712 | class ChoiceInputLine(ListValInputLine): | ||
| 713 | """ | ||
| 714 | Base class for choicelist item Input lines. | ||
| 715 | """ | ||
| 716 | def __init__(self, props, tag, lineno): | ||
| 717 | ListValInputLine.__init__(self, props, tag, lineno) | ||
| 718 | |||
| 719 | def gen(self, context = None): | ||
| 720 | return None | ||
| 721 | |||
| 722 | |||
| 723 | class ChecklistInputLine(ListInputLine): | ||
| 724 | """ | ||
| 725 | Base class for checklist Input lines. | ||
| 726 | """ | ||
| 727 | def __init__(self, props, tag, lineno): | ||
| 728 | ListInputLine.__init__(self, props, tag, lineno) | ||
| 729 | |||
| 730 | def gen(self, context = None): | ||
| 731 | InputLine.gen(self, context) | ||
| 732 | |||
| 733 | gen_choices_defer(self, context, True) | ||
| 734 | name = self.props["name"] | ||
| 735 | nameappend = context["nameappend"] | ||
| 736 | filename = context["filename"] | ||
| 737 | |||
| 738 | try: | ||
| 739 | default_choice = self.props["default"] | ||
| 740 | except KeyError: | ||
| 741 | default_choice = "" | ||
| 742 | |||
| 743 | line = name + " = default(invoke_deferred_choices(\"" + name + "_" + filename + "_" + nameappend + "\"), \"" + default_choice + "\")" | ||
| 744 | |||
| 745 | return line | ||
| 746 | |||
| 747 | |||
| 748 | class CheckInputLine(ListValInputLine): | ||
| 749 | """ | ||
| 750 | Base class for checklist item Input lines. | ||
| 751 | """ | ||
| 752 | def __init__(self, props, tag, lineno): | ||
| 753 | ListValInputLine.__init__(self, props, tag, lineno) | ||
| 754 | |||
| 755 | def gen(self, context = None): | ||
| 756 | return None | ||
| 757 | |||
| 758 | |||
| 759 | dirname_substitutions = {} | ||
| 760 | |||
| 761 | class SubstrateBase(object): | ||
| 762 | """ | ||
| 763 | Base class for both expanded and unexpanded file and dir container | ||
| 764 | objects. | ||
| 765 | """ | ||
| 766 | def __init__(self, filename, filebase, out_filebase): | ||
| 767 | self.filename = filename | ||
| 768 | self.filebase = filebase | ||
| 769 | self.translated_filename = filename | ||
| 770 | self.out_filebase = out_filebase | ||
| 771 | self.raw_lines = [] | ||
| 772 | self.expanded_lines = [] | ||
| 773 | self.prev_choicelist = None | ||
| 774 | |||
| 775 | def parse_error(self, msg, lineno, line): | ||
| 776 | raise SyntaxError("%s: [%s: %d]: %s" % (msg, self.filename, lineno, line)) | ||
| 777 | |||
| 778 | def expand_input_tag(self, tag, lineno): | ||
| 779 | """ | ||
| 780 | Input tags consist of the word 'input' at the beginning, | ||
| 781 | followed by name:value property pairs which are converted into | ||
| 782 | a dictionary. | ||
| 783 | """ | ||
| 784 | propstr = tag[len(INPUT_TAG):] | ||
| 785 | |||
| 786 | props = dict(prop.split(":", 1) for prop in shlex.split(propstr)) | ||
| 787 | props["filename"] = self.filename | ||
| 788 | |||
| 789 | input_type = props[INPUT_TYPE_PROPERTY] | ||
| 790 | if not props[INPUT_TYPE_PROPERTY]: | ||
| 791 | self.parse_error("No input 'type' property found", lineno, tag) | ||
| 792 | |||
| 793 | if input_type == "boolean": | ||
| 794 | return BooleanInputLine(props, tag, lineno) | ||
| 795 | if input_type == "edit": | ||
| 796 | return EditBoxInputLine(props, tag, lineno) | ||
| 797 | if input_type == "edit-git-repo": | ||
| 798 | return GitRepoEditBoxInputLine(props, tag, lineno) | ||
| 799 | if input_type == "edit-file": | ||
| 800 | return FileEditBoxInputLine(props, tag, lineno) | ||
| 801 | elif input_type == "choicelist": | ||
| 802 | self.prev_choicelist = ChoicelistInputLine(props, tag, lineno) | ||
| 803 | return self.prev_choicelist | ||
| 804 | elif input_type == "choice": | ||
| 805 | if not self.prev_choicelist: | ||
| 806 | self.parse_error("Found 'choice' input tag but no previous choicelist", | ||
| 807 | lineno, tag) | ||
| 808 | choice = ChoiceInputLine(props, tag, lineno) | ||
| 809 | self.prev_choicelist.choices.append(choice) | ||
| 810 | return choice | ||
| 811 | elif input_type == "checklist": | ||
| 812 | return ChecklistInputLine(props, tag, lineno) | ||
| 813 | elif input_type == "check": | ||
| 814 | return CheckInputLine(props, tag, lineno) | ||
| 815 | |||
| 816 | def expand_assignment_tag(self, start, line, lineno): | ||
| 817 | """ | ||
| 818 | Expand all tags in a line. | ||
| 819 | """ | ||
| 820 | expanded_line = AssignmentLine(line.rstrip()) | ||
| 821 | |||
| 822 | while start != -1: | ||
| 823 | end = line.find(CLOSE_TAG, start) | ||
| 824 | if end == -1: | ||
| 825 | self.parse_error("No close tag found for assignment tag", lineno, line) | ||
| 826 | else: | ||
| 827 | name = line[start + len(ASSIGN_TAG):end].strip() | ||
| 828 | expanded_line.add_assignment(start, end + len(CLOSE_TAG), name) | ||
| 829 | start = line.find(ASSIGN_TAG, end) | ||
| 830 | |||
| 831 | return expanded_line | ||
| 832 | |||
| 833 | def expand_tag(self, line, lineno): | ||
| 834 | """ | ||
| 835 | Returns a processed tag line, or None if there was no tag | ||
| 836 | |||
| 837 | The rules for tags are very simple: | ||
| 838 | - No nested tags | ||
| 839 | - Tags start with {{ and end with }} | ||
| 840 | - An assign tag, {{=, can appear anywhere and will | ||
| 841 | be replaced with what the assignment evaluates to | ||
| 842 | - Any other tag occupies the whole line it is on | ||
| 843 | - if there's anything else on the tag line, it's an error | ||
| 844 | - if it starts with 'input', it's an input tag and | ||
| 845 | will only be used for prompting and setting variables | ||
| 846 | - anything else is straight Python | ||
| 847 | - tags are in effect only until the next blank line or tag or 'pass' tag | ||
| 848 | - we don't have indentation in tags, but we need some way to end a block | ||
| 849 | forcefully without blank lines or other tags - that's the 'pass' tag | ||
| 850 | - todo: implement pass tag | ||
| 851 | - directories and filenames can have tags as well, but only assignment | ||
| 852 | and 'if' code lines | ||
| 853 | - directories and filenames are the only case where normal tags can | ||
| 854 | coexist with normal text on the same 'line' | ||
| 855 | """ | ||
| 856 | start = line.find(ASSIGN_TAG) | ||
| 857 | if start != -1: | ||
| 858 | return self.expand_assignment_tag(start, line, lineno) | ||
| 859 | |||
| 860 | start = line.find(OPEN_TAG) | ||
| 861 | if start == -1: | ||
| 862 | return None | ||
| 863 | |||
| 864 | end = line.find(CLOSE_TAG, 0) | ||
| 865 | if end == -1: | ||
| 866 | self.parse_error("No close tag found for open tag", lineno, line) | ||
| 867 | |||
| 868 | tag = line[start + len(OPEN_TAG):end].strip() | ||
| 869 | |||
| 870 | if not tag.lstrip().startswith(INPUT_TAG): | ||
| 871 | return CodeLine(tag) | ||
| 872 | |||
| 873 | return self.expand_input_tag(tag, lineno) | ||
| 874 | |||
| 875 | def append_translated_filename(self, filename): | ||
| 876 | """ | ||
| 877 | Simply append filename to translated_filename | ||
| 878 | """ | ||
| 879 | self.translated_filename = os.path.join(self.translated_filename, filename) | ||
| 880 | |||
| 881 | def get_substituted_file_or_dir_name(self, first_line, tag): | ||
| 882 | """ | ||
| 883 | If file or dir names contain name substitutions, return the name | ||
| 884 | to substitute. Note that this is just the file or dirname and | ||
| 885 | doesn't include the path. | ||
| 886 | """ | ||
| 887 | filename = first_line.find(tag) | ||
| 888 | if filename != -1: | ||
| 889 | filename += len(tag) | ||
| 890 | substituted_filename = first_line[filename:].strip() | ||
| 891 | this = substituted_filename.find(" this") | ||
| 892 | if this != -1: | ||
| 893 | head, tail = os.path.split(self.filename) | ||
| 894 | substituted_filename = substituted_filename[:this + 1] + tail | ||
| 895 | if tag == DIRNAME_TAG: # get rid of .noinstall in dirname | ||
| 896 | substituted_filename = substituted_filename.split('.')[0] | ||
| 897 | |||
| 898 | return substituted_filename | ||
| 899 | |||
| 900 | def get_substituted_filename(self, first_line): | ||
| 901 | """ | ||
| 902 | If a filename contains a name substitution, return the name to | ||
| 903 | substitute. Note that this is just the filename and doesn't | ||
| 904 | include the path. | ||
| 905 | """ | ||
| 906 | return self.get_substituted_file_or_dir_name(first_line, FILENAME_TAG) | ||
| 907 | |||
| 908 | def get_substituted_dirname(self, first_line): | ||
| 909 | """ | ||
| 910 | If a dirname contains a name substitution, return the name to | ||
| 911 | substitute. Note that this is just the dirname and doesn't | ||
| 912 | include the path. | ||
| 913 | """ | ||
| 914 | return self.get_substituted_file_or_dir_name(first_line, DIRNAME_TAG) | ||
| 915 | |||
| 916 | def substitute_filename(self, first_line): | ||
| 917 | """ | ||
| 918 | Find the filename in first_line and append it to translated_filename. | ||
| 919 | """ | ||
| 920 | substituted_filename = self.get_substituted_filename(first_line) | ||
| 921 | self.append_translated_filename(substituted_filename); | ||
| 922 | |||
| 923 | def substitute_dirname(self, first_line): | ||
| 924 | """ | ||
| 925 | Find the dirname in first_line and append it to translated_filename. | ||
| 926 | """ | ||
| 927 | substituted_dirname = self.get_substituted_dirname(first_line) | ||
| 928 | self.append_translated_filename(substituted_dirname); | ||
| 929 | |||
| 930 | def is_filename_substitution(self, line): | ||
| 931 | """ | ||
| 932 | Do we have a filename subustition? | ||
| 933 | """ | ||
| 934 | if line.find(FILENAME_TAG) != -1: | ||
| 935 | return True | ||
| 936 | return False | ||
| 937 | |||
| 938 | def is_dirname_substitution(self, line): | ||
| 939 | """ | ||
| 940 | Do we have a dirname subustition? | ||
| 941 | """ | ||
| 942 | if line.find(DIRNAME_TAG) != -1: | ||
| 943 | return True | ||
| 944 | return False | ||
| 945 | |||
| 946 | def translate_dirname(self, first_line): | ||
| 947 | """ | ||
| 948 | Just save the first_line mapped by filename. The later pass | ||
| 949 | through the directories will look for a dirname.noinstall | ||
| 950 | match and grab the substitution line. | ||
| 951 | """ | ||
| 952 | dirname_substitutions[self.filename] = first_line | ||
| 953 | |||
| 954 | def translate_dirnames_in_path(self, path): | ||
| 955 | """ | ||
| 956 | Translate dirnames below this file or dir, not including tail. | ||
| 957 | dirname_substititions is keyed on actual untranslated filenames. | ||
| 958 | translated_path contains the subsititutions for each element. | ||
| 959 | """ | ||
| 960 | remainder = path[len(self.filebase)+1:] | ||
| 961 | translated_path = untranslated_path = self.filebase | ||
| 962 | |||
| 963 | untranslated_dirs = remainder.split(os.sep) | ||
| 964 | |||
| 965 | for dir in untranslated_dirs: | ||
| 966 | key = os.path.join(untranslated_path, dir + '.noinstall') | ||
| 967 | try: | ||
| 968 | first_line = dirname_substitutions[key] | ||
| 969 | except KeyError: | ||
| 970 | translated_path = os.path.join(translated_path, dir) | ||
| 971 | untranslated_path = os.path.join(untranslated_path, dir) | ||
| 972 | continue | ||
| 973 | substituted_dir = self.get_substituted_dirname(first_line) | ||
| 974 | translated_path = os.path.join(translated_path, substituted_dir) | ||
| 975 | untranslated_path = os.path.join(untranslated_path, dir) | ||
| 976 | |||
| 977 | return translated_path | ||
| 978 | |||
| 979 | def translate_file_or_dir_name(self): | ||
| 980 | """ | ||
| 981 | Originally we were allowed to use open/close/assign tags and python | ||
| 982 | code in the filename, which fit in nicely with the way we | ||
| 983 | processed the templates and generated code. Now that we can't | ||
| 984 | do that, we make those tags proper file contents and have this | ||
| 985 | pass substitute the nice but non-functional names with those | ||
| 986 | 'strange' ones, and then proceed as usual. | ||
| 987 | |||
| 988 | So, if files or matching dir<.noinstall> files contain | ||
| 989 | filename substitutions, this function translates them into the | ||
| 990 | corresponding 'strange' names, which future passes will expand | ||
| 991 | as they always have. The resulting pathname is kept in the | ||
| 992 | file or directory's translated_filename. Another way to think | ||
| 993 | about it is that self.filename is the input filename, and | ||
| 994 | translated_filename is the output filename before expansion. | ||
| 995 | """ | ||
| 996 | # remove leaf file or dirname | ||
| 997 | head, tail = os.path.split(self.filename) | ||
| 998 | translated_path = self.translate_dirnames_in_path(head) | ||
| 999 | self.translated_filename = translated_path | ||
| 1000 | |||
| 1001 | # This is a dirname - does it have a matching .noinstall with | ||
| 1002 | # a substitution? If so, apply the dirname subsititution. | ||
| 1003 | if not os.path.isfile(self.filename): | ||
| 1004 | key = self.filename + ".noinstall" | ||
| 1005 | try: | ||
| 1006 | first_line = dirname_substitutions[key] | ||
| 1007 | except KeyError: | ||
| 1008 | self.append_translated_filename(tail) | ||
| 1009 | return | ||
| 1010 | self.substitute_dirname(first_line) | ||
| 1011 | return | ||
| 1012 | |||
| 1013 | f = open(self.filename) | ||
| 1014 | first_line = f.readline() | ||
| 1015 | f.close() | ||
| 1016 | |||
| 1017 | # This is a normal filename not needing translation, just use | ||
| 1018 | # it as-is. | ||
| 1019 | if not first_line or not first_line.startswith("#"): | ||
| 1020 | self.append_translated_filename(tail) | ||
| 1021 | return | ||
| 1022 | |||
| 1023 | # If we have a filename substitution (first line in the file | ||
| 1024 | # is a FILENAME_TAG line) do the substitution now. If we have | ||
| 1025 | # a dirname substitution (DIRNAME_TAG in dirname.noinstall | ||
| 1026 | # meta-file), hash it so we can apply it when we see the | ||
| 1027 | # matching dirname later. Otherwise we have a regular | ||
| 1028 | # filename, just use it as-is. | ||
| 1029 | if self.is_filename_substitution(first_line): | ||
| 1030 | self.substitute_filename(first_line) | ||
| 1031 | elif self.is_dirname_substitution(first_line): | ||
| 1032 | self.translate_dirname(first_line) | ||
| 1033 | else: | ||
| 1034 | self.append_translated_filename(tail) | ||
| 1035 | |||
| 1036 | def expand_file_or_dir_name(self): | ||
| 1037 | """ | ||
| 1038 | Expand file or dir names into codeline. Dirnames and | ||
| 1039 | filenames can only have assignments or if statements. First | ||
| 1040 | translate if statements into CodeLine + (dirname or filename | ||
| 1041 | creation). | ||
| 1042 | """ | ||
| 1043 | lineno = 0 | ||
| 1044 | |||
| 1045 | line = self.translated_filename[len(self.filebase):] | ||
| 1046 | if line.startswith("/"): | ||
| 1047 | line = line[1:] | ||
| 1048 | opentag_start = -1 | ||
| 1049 | |||
| 1050 | start = line.find(OPEN_TAG) | ||
| 1051 | while start != -1: | ||
| 1052 | if not line[start:].startswith(ASSIGN_TAG): | ||
| 1053 | opentag_start = start | ||
| 1054 | break | ||
| 1055 | start += len(ASSIGN_TAG) | ||
| 1056 | start = line.find(OPEN_TAG, start) | ||
| 1057 | |||
| 1058 | if opentag_start != -1: | ||
| 1059 | end = line.find(CLOSE_TAG, opentag_start) | ||
| 1060 | if end == -1: | ||
| 1061 | self.parse_error("No close tag found for open tag", lineno, line) | ||
| 1062 | # we have a {{ tag i.e. code | ||
| 1063 | tag = line[opentag_start + len(OPEN_TAG):end].strip() | ||
| 1064 | if not tag.lstrip().startswith(IF_TAG): | ||
| 1065 | self.parse_error("Only 'if' tags are allowed in file or directory names", | ||
| 1066 | lineno, line) | ||
| 1067 | self.expanded_lines.append(CodeLine(tag)) | ||
| 1068 | |||
| 1069 | # everything after }} is the actual filename (possibly with assignments) | ||
| 1070 | # everything before is the pathname | ||
| 1071 | line = line[:opentag_start] + line[end + len(CLOSE_TAG):].strip() | ||
| 1072 | |||
| 1073 | assign_start = line.find(ASSIGN_TAG) | ||
| 1074 | if assign_start != -1: | ||
| 1075 | assignment_tag = self.expand_assignment_tag(assign_start, line, lineno) | ||
| 1076 | if isinstance(self, SubstrateFile): | ||
| 1077 | assignment_tag.is_filename = True | ||
| 1078 | assignment_tag.out_filebase = self.out_filebase | ||
| 1079 | elif isinstance(self, SubstrateDir): | ||
| 1080 | assignment_tag.is_dirname = True | ||
| 1081 | assignment_tag.out_filebase = self.out_filebase | ||
| 1082 | self.expanded_lines.append(assignment_tag) | ||
| 1083 | return | ||
| 1084 | |||
| 1085 | normal_line = NormalLine(line) | ||
| 1086 | if isinstance(self, SubstrateFile): | ||
| 1087 | normal_line.is_filename = True | ||
| 1088 | normal_line.out_filebase = self.out_filebase | ||
| 1089 | elif isinstance(self, SubstrateDir): | ||
| 1090 | normal_line.is_dirname = True | ||
| 1091 | normal_line.out_filebase = self.out_filebase | ||
| 1092 | self.expanded_lines.append(normal_line) | ||
| 1093 | |||
| 1094 | def expand(self): | ||
| 1095 | """ | ||
| 1096 | Expand the file or dir name first, eventually this ends up | ||
| 1097 | creating the file or dir. | ||
| 1098 | """ | ||
| 1099 | self.translate_file_or_dir_name() | ||
| 1100 | self.expand_file_or_dir_name() | ||
| 1101 | |||
| 1102 | |||
| 1103 | class SubstrateFile(SubstrateBase): | ||
| 1104 | """ | ||
| 1105 | Container for both expanded and unexpanded substrate files. | ||
| 1106 | """ | ||
| 1107 | def __init__(self, filename, filebase, out_filebase): | ||
| 1108 | SubstrateBase.__init__(self, filename, filebase, out_filebase) | ||
| 1109 | |||
| 1110 | def read(self): | ||
| 1111 | if self.raw_lines: | ||
| 1112 | return | ||
| 1113 | f = open(self.filename) | ||
| 1114 | self.raw_lines = f.readlines() | ||
| 1115 | |||
| 1116 | def expand(self): | ||
| 1117 | """Expand the contents of all template tags in the file.""" | ||
| 1118 | SubstrateBase.expand(self) | ||
| 1119 | self.read() | ||
| 1120 | |||
| 1121 | for lineno, line in enumerate(self.raw_lines): | ||
| 1122 | # only first line can be a filename substitition | ||
| 1123 | if lineno == 0 and line.startswith("#") and FILENAME_TAG in line: | ||
| 1124 | continue # skip it - we've already expanded it | ||
| 1125 | expanded_line = self.expand_tag(line, lineno + 1) # humans not 0-based | ||
| 1126 | if not expanded_line: | ||
| 1127 | expanded_line = NormalLine(line.rstrip()) | ||
| 1128 | self.expanded_lines.append(expanded_line) | ||
| 1129 | |||
| 1130 | def gen(self, context = None): | ||
| 1131 | """Generate the code that generates the BSP.""" | ||
| 1132 | base_indent = 0 | ||
| 1133 | |||
| 1134 | indent = new_indent = base_indent | ||
| 1135 | |||
| 1136 | for line in self.expanded_lines: | ||
| 1137 | genline = line.gen(context) | ||
| 1138 | if not genline: | ||
| 1139 | continue | ||
| 1140 | if isinstance(line, InputLine): | ||
| 1141 | line.generated_line = genline | ||
| 1142 | continue | ||
| 1143 | if genline.startswith(OPEN_START): | ||
| 1144 | if indent == 1: | ||
| 1145 | base_indent = 1 | ||
| 1146 | if indent: | ||
| 1147 | if genline == BLANKLINE_STR or (not genline.startswith(NORMAL_START) | ||
| 1148 | and not genline.startswith(OPEN_START)): | ||
| 1149 | indent = new_indent = base_indent | ||
| 1150 | if genline.endswith(":"): | ||
| 1151 | new_indent = base_indent + 1 | ||
| 1152 | line.generated_line = (indent * INDENT_STR) + genline | ||
| 1153 | indent = new_indent | ||
| 1154 | |||
| 1155 | |||
| 1156 | class SubstrateDir(SubstrateBase): | ||
| 1157 | """ | ||
| 1158 | Container for both expanded and unexpanded substrate dirs. | ||
| 1159 | """ | ||
| 1160 | def __init__(self, filename, filebase, out_filebase): | ||
| 1161 | SubstrateBase.__init__(self, filename, filebase, out_filebase) | ||
| 1162 | |||
| 1163 | def expand(self): | ||
| 1164 | SubstrateBase.expand(self) | ||
| 1165 | |||
| 1166 | def gen(self, context = None): | ||
| 1167 | """Generate the code that generates the BSP.""" | ||
| 1168 | indent = new_indent = 0 | ||
| 1169 | for line in self.expanded_lines: | ||
| 1170 | genline = line.gen(context) | ||
| 1171 | if not genline: | ||
| 1172 | continue | ||
| 1173 | if genline.endswith(":"): | ||
| 1174 | new_indent = 1 | ||
| 1175 | else: | ||
| 1176 | new_indent = 0 | ||
| 1177 | line.generated_line = (indent * INDENT_STR) + genline | ||
| 1178 | indent = new_indent | ||
| 1179 | |||
| 1180 | |||
| 1181 | def expand_target(target, all_files, out_filebase): | ||
| 1182 | """ | ||
| 1183 | Expand the contents of all template tags in the target. This | ||
| 1184 | means removing tags and categorizing or creating lines so that | ||
| 1185 | future passes can process and present input lines and generate the | ||
| 1186 | corresponding lines of the Python program that will be exec'ed to | ||
| 1187 | actually produce the final BSP. 'all_files' includes directories. | ||
| 1188 | """ | ||
| 1189 | for root, dirs, files in os.walk(target): | ||
| 1190 | for file in files: | ||
| 1191 | if file.endswith("~") or file.endswith("#"): | ||
| 1192 | continue | ||
| 1193 | f = os.path.join(root, file) | ||
| 1194 | sfile = SubstrateFile(f, target, out_filebase) | ||
| 1195 | sfile.expand() | ||
| 1196 | all_files.append(sfile) | ||
| 1197 | |||
| 1198 | for dir in dirs: | ||
| 1199 | d = os.path.join(root, dir) | ||
| 1200 | sdir = SubstrateDir(d, target, out_filebase) | ||
| 1201 | sdir.expand() | ||
| 1202 | all_files.append(sdir) | ||
| 1203 | |||
| 1204 | |||
| 1205 | def gen_program_machine_lines(machine, program_lines): | ||
| 1206 | """ | ||
| 1207 | Use the input values we got from the command line. | ||
| 1208 | """ | ||
| 1209 | line = "machine = \"" + machine + "\"" | ||
| 1210 | program_lines.append(line) | ||
| 1211 | |||
| 1212 | line = "layer_name = \"" + machine + "\"" | ||
| 1213 | program_lines.append(line) | ||
| 1214 | |||
| 1215 | |||
| 1216 | def sort_inputlines(input_lines): | ||
| 1217 | """Sort input lines according to priority (position).""" | ||
| 1218 | input_lines.sort(key = lambda l: l.prio) | ||
| 1219 | |||
| 1220 | |||
| 1221 | def find_parent_dependency(lines, depends_on): | ||
| 1222 | for i, line in lines: | ||
| 1223 | if isinstance(line, CodeLine): | ||
| 1224 | continue | ||
| 1225 | if line.props["name"] == depends_on: | ||
| 1226 | return i | ||
| 1227 | |||
| 1228 | return -1 | ||
| 1229 | |||
| 1230 | |||
| 1231 | def process_inputline_dependencies(input_lines, all_inputlines): | ||
| 1232 | """If any input lines depend on others, put the others first.""" | ||
| 1233 | for line in input_lines: | ||
| 1234 | if isinstance(line, InputLineGroup): | ||
| 1235 | group_inputlines = [] | ||
| 1236 | process_inputline_dependencies(line.group, group_inputlines) | ||
| 1237 | line.group = group_inputlines | ||
| 1238 | all_inputlines.append(line) | ||
| 1239 | continue | ||
| 1240 | |||
| 1241 | if isinstance(line, CodeLine) or isinstance(line, NormalLine): | ||
| 1242 | all_inputlines.append(line) | ||
| 1243 | continue | ||
| 1244 | |||
| 1245 | try: | ||
| 1246 | depends_on = line.props["depends-on"] | ||
| 1247 | depends_codeline = "if " + line.props["depends-on"] + " == \"" + line.props["depends-on-val"] + "\":" | ||
| 1248 | all_inputlines.append(CodeLine(depends_codeline)) | ||
| 1249 | all_inputlines.append(line) | ||
| 1250 | except KeyError: | ||
| 1251 | all_inputlines.append(line) | ||
| 1252 | |||
| 1253 | |||
| 1254 | def conditional_filename(filename): | ||
| 1255 | """ | ||
| 1256 | Check if the filename itself contains a conditional statement. If | ||
| 1257 | so, return a codeline for it. | ||
| 1258 | """ | ||
| 1259 | opentag_start = filename.find(OPEN_TAG) | ||
| 1260 | |||
| 1261 | if opentag_start != -1: | ||
| 1262 | if filename[opentag_start:].startswith(ASSIGN_TAG): | ||
| 1263 | return None | ||
| 1264 | end = filename.find(CLOSE_TAG, opentag_start) | ||
| 1265 | if end == -1: | ||
| 1266 | print "No close tag found for open tag in filename %s" % filename | ||
| 1267 | sys.exit(1) | ||
| 1268 | |||
| 1269 | # we have a {{ tag i.e. code | ||
| 1270 | tag = filename[opentag_start + len(OPEN_TAG):end].strip() | ||
| 1271 | if not tag.lstrip().startswith(IF_TAG): | ||
| 1272 | print "Only 'if' tags are allowed in file or directory names, filename: %s" % filename | ||
| 1273 | sys.exit(1) | ||
| 1274 | |||
| 1275 | return CodeLine(tag) | ||
| 1276 | |||
| 1277 | return None | ||
| 1278 | |||
| 1279 | |||
| 1280 | class InputLineGroup(InputLine): | ||
| 1281 | """ | ||
| 1282 | InputLine that does nothing but group other input lines | ||
| 1283 | corresponding to all the input lines in a SubstrateFile so they | ||
| 1284 | can be generated as a group. prio is the only property used. | ||
| 1285 | """ | ||
| 1286 | def __init__(self, codeline): | ||
| 1287 | InputLine.__init__(self, {}, "", 0) | ||
| 1288 | self.group = [] | ||
| 1289 | self.prio = sys.maxint | ||
| 1290 | self.group.append(codeline) | ||
| 1291 | |||
| 1292 | def append(self, line): | ||
| 1293 | self.group.append(line) | ||
| 1294 | if line.prio < self.prio: | ||
| 1295 | self.prio = line.prio | ||
| 1296 | |||
| 1297 | def len(self): | ||
| 1298 | return len(self.group) | ||
| 1299 | |||
| 1300 | |||
| 1301 | def gather_inputlines(files): | ||
| 1302 | """ | ||
| 1303 | Gather all the InputLines - we want to generate them first. | ||
| 1304 | """ | ||
| 1305 | all_inputlines = [] | ||
| 1306 | input_lines = [] | ||
| 1307 | |||
| 1308 | for file in files: | ||
| 1309 | if isinstance(file, SubstrateFile): | ||
| 1310 | group = None | ||
| 1311 | basename = os.path.basename(file.translated_filename) | ||
| 1312 | |||
| 1313 | codeline = conditional_filename(basename) | ||
| 1314 | if codeline: | ||
| 1315 | group = InputLineGroup(codeline) | ||
| 1316 | |||
| 1317 | have_condition = False | ||
| 1318 | condition_to_write = None | ||
| 1319 | for line in file.expanded_lines: | ||
| 1320 | if isinstance(line, CodeLine): | ||
| 1321 | have_condition = True | ||
| 1322 | condition_to_write = line | ||
| 1323 | continue | ||
| 1324 | if isinstance(line, InputLine): | ||
| 1325 | if group: | ||
| 1326 | if condition_to_write: | ||
| 1327 | condition_to_write.prio = line.prio | ||
| 1328 | condition_to_write.discard = True | ||
| 1329 | group.append(condition_to_write) | ||
| 1330 | condition_to_write = None | ||
| 1331 | group.append(line) | ||
| 1332 | else: | ||
| 1333 | if condition_to_write: | ||
| 1334 | condition_to_write.prio = line.prio | ||
| 1335 | condition_to_write.discard = True | ||
| 1336 | input_lines.append(condition_to_write) | ||
| 1337 | condition_to_write = None | ||
| 1338 | input_lines.append(line) | ||
| 1339 | else: | ||
| 1340 | if condition_to_write: | ||
| 1341 | condition_to_write = None | ||
| 1342 | if have_condition: | ||
| 1343 | if not line.line.strip(): | ||
| 1344 | line.discard = True | ||
| 1345 | input_lines.append(line) | ||
| 1346 | have_condition = False | ||
| 1347 | |||
| 1348 | if group and group.len() > 1: | ||
| 1349 | input_lines.append(group) | ||
| 1350 | |||
| 1351 | sort_inputlines(input_lines) | ||
| 1352 | process_inputline_dependencies(input_lines, all_inputlines) | ||
| 1353 | |||
| 1354 | return all_inputlines | ||
| 1355 | |||
| 1356 | |||
| 1357 | def run_program_lines(linelist, codedump): | ||
| 1358 | """ | ||
| 1359 | For a single file, print all the python code into a buf and execute it. | ||
| 1360 | """ | ||
| 1361 | buf = "\n".join(linelist) | ||
| 1362 | |||
| 1363 | if codedump: | ||
| 1364 | of = open("bspgen.out", "w") | ||
| 1365 | of.write(buf) | ||
| 1366 | of.close() | ||
| 1367 | exec buf | ||
| 1368 | |||
| 1369 | |||
| 1370 | def gen_target(files, context = None): | ||
| 1371 | """ | ||
| 1372 | Generate the python code for each file. | ||
| 1373 | """ | ||
| 1374 | for file in files: | ||
| 1375 | file.gen(context) | ||
| 1376 | |||
| 1377 | |||
| 1378 | def gen_program_header_lines(program_lines): | ||
| 1379 | """ | ||
| 1380 | Generate any imports we need. | ||
| 1381 | """ | ||
| 1382 | program_lines.append("current_file = \"\"") | ||
| 1383 | |||
| 1384 | |||
| 1385 | def gen_supplied_property_vals(properties, program_lines): | ||
| 1386 | """ | ||
| 1387 | Generate user-specified entries for input values instead of | ||
| 1388 | generating input prompts. | ||
| 1389 | """ | ||
| 1390 | for name, val in properties.iteritems(): | ||
| 1391 | program_line = name + " = \"" + val + "\"" | ||
| 1392 | program_lines.append(program_line) | ||
| 1393 | |||
| 1394 | |||
| 1395 | def gen_initial_property_vals(input_lines, program_lines): | ||
| 1396 | """ | ||
| 1397 | Generate null or default entries for input values, so we don't | ||
| 1398 | have undefined variables. | ||
| 1399 | """ | ||
| 1400 | for line in input_lines: | ||
| 1401 | if isinstance(line, InputLineGroup): | ||
| 1402 | gen_initial_property_vals(line.group, program_lines) | ||
| 1403 | continue | ||
| 1404 | |||
| 1405 | if isinstance(line, InputLine): | ||
| 1406 | try: | ||
| 1407 | name = line.props["name"] | ||
| 1408 | try: | ||
| 1409 | default_val = "\"" + line.props["default"] + "\"" | ||
| 1410 | except: | ||
| 1411 | default_val = "\"\"" | ||
| 1412 | program_line = name + " = " + default_val | ||
| 1413 | program_lines.append(program_line) | ||
| 1414 | except KeyError: | ||
| 1415 | pass | ||
| 1416 | |||
| 1417 | |||
| 1418 | def gen_program_input_lines(input_lines, program_lines, context, in_group = False): | ||
| 1419 | """ | ||
| 1420 | Generate only the input lines used for prompting the user. For | ||
| 1421 | that, we only have input lines and CodeLines that affect the next | ||
| 1422 | input line. | ||
| 1423 | """ | ||
| 1424 | indent = new_indent = 0 | ||
| 1425 | |||
| 1426 | for line in input_lines: | ||
| 1427 | if isinstance(line, InputLineGroup): | ||
| 1428 | gen_program_input_lines(line.group, program_lines, context, True) | ||
| 1429 | continue | ||
| 1430 | if not line.line.strip(): | ||
| 1431 | continue | ||
| 1432 | |||
| 1433 | genline = line.gen(context) | ||
| 1434 | if not genline: | ||
| 1435 | continue | ||
| 1436 | if genline.endswith(":"): | ||
| 1437 | new_indent += 1 | ||
| 1438 | else: | ||
| 1439 | if indent > 1 or (not in_group and indent): | ||
| 1440 | new_indent -= 1 | ||
| 1441 | |||
| 1442 | line.generated_line = (indent * INDENT_STR) + genline | ||
| 1443 | program_lines.append(line.generated_line) | ||
| 1444 | |||
| 1445 | indent = new_indent | ||
| 1446 | |||
| 1447 | |||
| 1448 | def gen_program_lines(target_files, program_lines): | ||
| 1449 | """ | ||
| 1450 | Generate the program lines that make up the BSP generation | ||
| 1451 | program. This appends the generated lines of all target_files to | ||
| 1452 | program_lines, and skips input lines, which are dealt with | ||
| 1453 | separately, or omitted. | ||
| 1454 | """ | ||
| 1455 | for file in target_files: | ||
| 1456 | if file.filename.endswith("noinstall"): | ||
| 1457 | continue | ||
| 1458 | |||
| 1459 | for line in file.expanded_lines: | ||
| 1460 | if isinstance(line, InputLine): | ||
| 1461 | continue | ||
| 1462 | if line.discard: | ||
| 1463 | continue | ||
| 1464 | |||
| 1465 | program_lines.append(line.generated_line) | ||
| 1466 | |||
| 1467 | |||
| 1468 | def create_context(machine, arch, scripts_path): | ||
| 1469 | """ | ||
| 1470 | Create a context object for use in deferred function invocation. | ||
| 1471 | """ | ||
| 1472 | context = {} | ||
| 1473 | |||
| 1474 | context["machine"] = machine | ||
| 1475 | context["arch"] = arch | ||
| 1476 | context["scripts_path"] = scripts_path | ||
| 1477 | |||
| 1478 | return context | ||
| 1479 | |||
| 1480 | |||
| 1481 | def capture_context(context): | ||
| 1482 | """ | ||
| 1483 | Create a context object for use in deferred function invocation. | ||
| 1484 | """ | ||
| 1485 | captured_context = {} | ||
| 1486 | |||
| 1487 | captured_context["machine"] = context["machine"] | ||
| 1488 | captured_context["arch"] = context["arch"] | ||
| 1489 | captured_context["scripts_path"] = context["scripts_path"] | ||
| 1490 | |||
| 1491 | return captured_context | ||
| 1492 | |||
| 1493 | |||
| 1494 | def expand_targets(context, bsp_output_dir, expand_common=True): | ||
| 1495 | """ | ||
| 1496 | Expand all the tags in both the common and machine-specific | ||
| 1497 | 'targets'. | ||
| 1498 | |||
| 1499 | If expand_common is False, don't expand the common target (this | ||
| 1500 | option is used to create special-purpose layers). | ||
| 1501 | """ | ||
| 1502 | target_files = [] | ||
| 1503 | |||
| 1504 | machine = context["machine"] | ||
| 1505 | arch = context["arch"] | ||
| 1506 | scripts_path = context["scripts_path"] | ||
| 1507 | |||
| 1508 | lib_path = scripts_path + '/lib' | ||
| 1509 | bsp_path = lib_path + '/bsp' | ||
| 1510 | arch_path = bsp_path + '/substrate/target/arch' | ||
| 1511 | |||
| 1512 | if expand_common: | ||
| 1513 | common = os.path.join(arch_path, "common") | ||
| 1514 | expand_target(common, target_files, bsp_output_dir) | ||
| 1515 | |||
| 1516 | arches = os.listdir(arch_path) | ||
| 1517 | if arch not in arches or arch == "common": | ||
| 1518 | print "Invalid karch, exiting\n" | ||
| 1519 | sys.exit(1) | ||
| 1520 | |||
| 1521 | target = os.path.join(arch_path, arch) | ||
| 1522 | expand_target(target, target_files, bsp_output_dir) | ||
| 1523 | |||
| 1524 | gen_target(target_files, context) | ||
| 1525 | |||
| 1526 | return target_files | ||
| 1527 | |||
| 1528 | |||
| 1529 | def yocto_common_create(machine, target, scripts_path, layer_output_dir, codedump, properties_file, properties_str="", expand_common=True): | ||
| 1530 | """ | ||
| 1531 | Common layer-creation code | ||
| 1532 | |||
| 1533 | machine - user-defined machine name (if needed, will generate 'machine' var) | ||
| 1534 | target - the 'target' the layer will be based on, must be one in | ||
| 1535 | scripts/lib/bsp/substrate/target/arch | ||
| 1536 | scripts_path - absolute path to yocto /scripts dir | ||
| 1537 | layer_output_dir - dirname to create for layer | ||
| 1538 | codedump - dump generated code to bspgen.out | ||
| 1539 | properties_file - use values from this file if nonempty i.e no prompting | ||
| 1540 | properties_str - use values from this string if nonempty i.e no prompting | ||
| 1541 | expand_common - boolean, use the contents of (for bsp layers) arch/common | ||
| 1542 | """ | ||
| 1543 | if os.path.exists(layer_output_dir): | ||
| 1544 | print "\nlayer output dir already exists, exiting. (%s)" % layer_output_dir | ||
| 1545 | sys.exit(1) | ||
| 1546 | |||
| 1547 | properties = None | ||
| 1548 | |||
| 1549 | if properties_file: | ||
| 1550 | try: | ||
| 1551 | infile = open(properties_file, "r") | ||
| 1552 | except IOError: | ||
| 1553 | print "Couldn't open properties file %s for reading, exiting" % properties_file | ||
| 1554 | sys.exit(1) | ||
| 1555 | |||
| 1556 | properties = json.load(infile) | ||
| 1557 | |||
| 1558 | if properties_str and not properties: | ||
| 1559 | properties = json.loads(properties_str) | ||
| 1560 | |||
| 1561 | os.mkdir(layer_output_dir) | ||
| 1562 | |||
| 1563 | context = create_context(machine, target, scripts_path) | ||
| 1564 | target_files = expand_targets(context, layer_output_dir, expand_common) | ||
| 1565 | |||
| 1566 | input_lines = gather_inputlines(target_files) | ||
| 1567 | |||
| 1568 | program_lines = [] | ||
| 1569 | |||
| 1570 | gen_program_header_lines(program_lines) | ||
| 1571 | |||
| 1572 | gen_initial_property_vals(input_lines, program_lines) | ||
| 1573 | |||
| 1574 | if properties: | ||
| 1575 | gen_supplied_property_vals(properties, program_lines) | ||
| 1576 | |||
| 1577 | gen_program_machine_lines(machine, program_lines) | ||
| 1578 | |||
| 1579 | if not properties: | ||
| 1580 | gen_program_input_lines(input_lines, program_lines, context) | ||
| 1581 | |||
| 1582 | gen_program_lines(target_files, program_lines) | ||
| 1583 | |||
| 1584 | run_program_lines(program_lines, codedump) | ||
| 1585 | |||
| 1586 | |||
| 1587 | def yocto_layer_create(layer_name, scripts_path, layer_output_dir, codedump, properties_file, properties=""): | ||
| 1588 | """ | ||
| 1589 | Create yocto layer | ||
| 1590 | |||
| 1591 | layer_name - user-defined layer name | ||
| 1592 | scripts_path - absolute path to yocto /scripts dir | ||
| 1593 | layer_output_dir - dirname to create for layer | ||
| 1594 | codedump - dump generated code to bspgen.out | ||
| 1595 | properties_file - use values from this file if nonempty i.e no prompting | ||
| 1596 | properties - use values from this string if nonempty i.e no prompting | ||
| 1597 | """ | ||
| 1598 | yocto_common_create(layer_name, "layer", scripts_path, layer_output_dir, codedump, properties_file, properties, False) | ||
| 1599 | |||
| 1600 | print "\nNew layer created in %s.\n" % (layer_output_dir) | ||
| 1601 | print "Don't forget to add it to your BBLAYERS (for details see %s\README)." % (layer_output_dir) | ||
| 1602 | |||
| 1603 | |||
| 1604 | def yocto_bsp_create(machine, arch, scripts_path, bsp_output_dir, codedump, properties_file, properties=None): | ||
| 1605 | """ | ||
| 1606 | Create bsp | ||
| 1607 | |||
| 1608 | machine - user-defined machine name | ||
| 1609 | arch - the arch the bsp will be based on, must be one in | ||
| 1610 | scripts/lib/bsp/substrate/target/arch | ||
| 1611 | scripts_path - absolute path to yocto /scripts dir | ||
| 1612 | bsp_output_dir - dirname to create for BSP | ||
| 1613 | codedump - dump generated code to bspgen.out | ||
| 1614 | properties_file - use values from this file if nonempty i.e no prompting | ||
| 1615 | properties - use values from this string if nonempty i.e no prompting | ||
| 1616 | """ | ||
| 1617 | yocto_common_create(machine, arch, scripts_path, bsp_output_dir, codedump, properties_file, properties) | ||
| 1618 | |||
| 1619 | print "\nNew %s BSP created in %s" % (arch, bsp_output_dir) | ||
| 1620 | |||
| 1621 | |||
| 1622 | def print_dict(items, indent = 0): | ||
| 1623 | """ | ||
| 1624 | Print the values in a possibly nested dictionary. | ||
| 1625 | """ | ||
| 1626 | for key, val in items.iteritems(): | ||
| 1627 | print " "*indent + "\"%s\" :" % key, | ||
| 1628 | if type(val) == dict: | ||
| 1629 | print "{" | ||
| 1630 | print_dict(val, indent + 1) | ||
| 1631 | print " "*indent + "}" | ||
| 1632 | else: | ||
| 1633 | print "%s" % val | ||
| 1634 | |||
| 1635 | |||
| 1636 | def get_properties(input_lines): | ||
| 1637 | """ | ||
| 1638 | Get the complete set of properties for all the input items in the | ||
| 1639 | BSP, as a possibly nested dictionary. | ||
| 1640 | """ | ||
| 1641 | properties = {} | ||
| 1642 | |||
| 1643 | for line in input_lines: | ||
| 1644 | if isinstance(line, InputLineGroup): | ||
| 1645 | statement = line.group[0].line | ||
| 1646 | group_properties = get_properties(line.group) | ||
| 1647 | properties[statement] = group_properties | ||
| 1648 | continue | ||
| 1649 | |||
| 1650 | if not isinstance(line, InputLine): | ||
| 1651 | continue | ||
| 1652 | |||
| 1653 | if isinstance(line, ChoiceInputLine): | ||
| 1654 | continue | ||
| 1655 | |||
| 1656 | props = line.props | ||
| 1657 | item = {} | ||
| 1658 | name = props["name"] | ||
| 1659 | for key, val in props.items(): | ||
| 1660 | if not key == "name": | ||
| 1661 | item[key] = val | ||
| 1662 | properties[name] = item | ||
| 1663 | |||
| 1664 | return properties | ||
| 1665 | |||
| 1666 | |||
| 1667 | def yocto_layer_list_properties(arch, scripts_path, properties_file, expand_common=True): | ||
| 1668 | """ | ||
| 1669 | List the complete set of properties for all the input items in the | ||
| 1670 | layer. If properties_file is non-null, write the complete set of | ||
| 1671 | properties as a nested JSON object corresponding to a possibly | ||
| 1672 | nested dictionary. | ||
| 1673 | """ | ||
| 1674 | context = create_context("unused", arch, scripts_path) | ||
| 1675 | target_files = expand_targets(context, "unused", expand_common) | ||
| 1676 | |||
| 1677 | input_lines = gather_inputlines(target_files) | ||
| 1678 | |||
| 1679 | properties = get_properties(input_lines) | ||
| 1680 | if properties_file: | ||
| 1681 | try: | ||
| 1682 | of = open(properties_file, "w") | ||
| 1683 | except IOError: | ||
| 1684 | print "Couldn't open properties file %s for writing, exiting" % properties_file | ||
| 1685 | sys.exit(1) | ||
| 1686 | |||
| 1687 | json.dump(properties, of) | ||
| 1688 | |||
| 1689 | print_dict(properties) | ||
| 1690 | |||
| 1691 | |||
| 1692 | def split_nested_property(property): | ||
| 1693 | """ | ||
| 1694 | A property name of the form x.y describes a nested property | ||
| 1695 | i.e. the property y is contained within x and can be addressed | ||
| 1696 | using standard JSON syntax for nested properties. Note that if a | ||
| 1697 | property name itself contains '.', it should be contained in | ||
| 1698 | double quotes. | ||
| 1699 | """ | ||
| 1700 | splittable_property = "" | ||
| 1701 | in_quotes = False | ||
| 1702 | for c in property: | ||
| 1703 | if c == '.' and not in_quotes: | ||
| 1704 | splittable_property += '\n' | ||
| 1705 | continue | ||
| 1706 | if c == '"': | ||
| 1707 | in_quotes = not in_quotes | ||
| 1708 | splittable_property += c | ||
| 1709 | |||
| 1710 | split_properties = splittable_property.split('\n') | ||
| 1711 | |||
| 1712 | if len(split_properties) > 1: | ||
| 1713 | return split_properties | ||
| 1714 | |||
| 1715 | return None | ||
| 1716 | |||
| 1717 | |||
| 1718 | def find_input_line_group(substring, input_lines): | ||
| 1719 | """ | ||
| 1720 | Find and return the InputLineGroup containing the specified substring. | ||
| 1721 | """ | ||
| 1722 | for line in input_lines: | ||
| 1723 | if isinstance(line, InputLineGroup): | ||
| 1724 | if substring in line.group[0].line: | ||
| 1725 | return line | ||
| 1726 | |||
| 1727 | return None | ||
| 1728 | |||
| 1729 | |||
| 1730 | def find_input_line(name, input_lines): | ||
| 1731 | """ | ||
| 1732 | Find the input line with the specified name. | ||
| 1733 | """ | ||
| 1734 | for line in input_lines: | ||
| 1735 | if isinstance(line, InputLineGroup): | ||
| 1736 | l = find_input_line(name, line.group) | ||
| 1737 | if l: | ||
| 1738 | return l | ||
| 1739 | |||
| 1740 | if isinstance(line, InputLine): | ||
| 1741 | try: | ||
| 1742 | if line.props["name"] == name: | ||
| 1743 | return line | ||
| 1744 | if line.props["name"] + "_" + line.props["nameappend"] == name: | ||
| 1745 | return line | ||
| 1746 | except KeyError: | ||
| 1747 | pass | ||
| 1748 | |||
| 1749 | return None | ||
| 1750 | |||
| 1751 | |||
| 1752 | def print_values(type, values_list): | ||
| 1753 | """ | ||
| 1754 | Print the values in the given list of values. | ||
| 1755 | """ | ||
| 1756 | if type == "choicelist": | ||
| 1757 | for value in values_list: | ||
| 1758 | print "[\"%s\", \"%s\"]" % (value[0], value[1]) | ||
| 1759 | elif type == "boolean": | ||
| 1760 | for value in values_list: | ||
| 1761 | print "[\"%s\", \"%s\"]" % (value[0], value[1]) | ||
| 1762 | |||
| 1763 | |||
| 1764 | def yocto_layer_list_property_values(arch, property, scripts_path, properties_file, expand_common=True): | ||
| 1765 | """ | ||
| 1766 | List the possible values for a given input property. If | ||
| 1767 | properties_file is non-null, write the complete set of properties | ||
| 1768 | as a JSON object corresponding to an array of possible values. | ||
| 1769 | """ | ||
| 1770 | context = create_context("unused", arch, scripts_path) | ||
| 1771 | context["name"] = property | ||
| 1772 | |||
| 1773 | target_files = expand_targets(context, "unused", expand_common) | ||
| 1774 | |||
| 1775 | input_lines = gather_inputlines(target_files) | ||
| 1776 | |||
| 1777 | properties = get_properties(input_lines) | ||
| 1778 | |||
| 1779 | nested_properties = split_nested_property(property) | ||
| 1780 | if nested_properties: | ||
| 1781 | # currently the outer property of a nested property always | ||
| 1782 | # corresponds to an input line group | ||
| 1783 | input_line_group = find_input_line_group(nested_properties[0], input_lines) | ||
| 1784 | if input_line_group: | ||
| 1785 | input_lines[:] = input_line_group.group[1:] | ||
| 1786 | # The inner property of a nested property name is the | ||
| 1787 | # actual property name we want, so reset to that | ||
| 1788 | property = nested_properties[1] | ||
| 1789 | |||
| 1790 | input_line = find_input_line(property, input_lines) | ||
| 1791 | if not input_line: | ||
| 1792 | print "Couldn't find values for property %s" % property | ||
| 1793 | return | ||
| 1794 | |||
| 1795 | values_list = [] | ||
| 1796 | |||
| 1797 | type = input_line.props["type"] | ||
| 1798 | if type == "boolean": | ||
| 1799 | values_list.append(["y", "n"]) | ||
| 1800 | elif type == "choicelist" or type == "checklist": | ||
| 1801 | try: | ||
| 1802 | gen_fn = input_line.props["gen"] | ||
| 1803 | if nested_properties: | ||
| 1804 | context["filename"] = nested_properties[0] | ||
| 1805 | try: | ||
| 1806 | context["branches_base"] = input_line.props["branches_base"] | ||
| 1807 | except KeyError: | ||
| 1808 | context["branches_base"] = None | ||
| 1809 | values_list = input_line.gen_choices_list(context, False) | ||
| 1810 | except KeyError: | ||
| 1811 | for choice in input_line.choices: | ||
| 1812 | choicepair = [] | ||
| 1813 | choicepair.append(choice.val) | ||
| 1814 | choicepair.append(choice.desc) | ||
| 1815 | values_list.append(choicepair) | ||
| 1816 | |||
| 1817 | if properties_file: | ||
| 1818 | try: | ||
| 1819 | of = open(properties_file, "w") | ||
| 1820 | except IOError: | ||
| 1821 | print "Couldn't open properties file %s for writing, exiting" % properties_file | ||
| 1822 | sys.exit(1) | ||
| 1823 | |||
| 1824 | json.dump(values_list, of) | ||
| 1825 | |||
| 1826 | print_values(type, values_list) | ||
| 1827 | |||
| 1828 | |||
| 1829 | def yocto_bsp_list(args, scripts_path, properties_file): | ||
| 1830 | """ | ||
| 1831 | Print available architectures, or the complete list of properties | ||
| 1832 | defined by the BSP, or the possible values for a particular BSP | ||
| 1833 | property. | ||
| 1834 | """ | ||
| 1835 | if len(args) < 1: | ||
| 1836 | return False | ||
| 1837 | |||
| 1838 | if args[0] == "karch": | ||
| 1839 | lib_path = scripts_path + '/lib' | ||
| 1840 | bsp_path = lib_path + '/bsp' | ||
| 1841 | arch_path = bsp_path + '/substrate/target/arch' | ||
| 1842 | print "Architectures available:" | ||
| 1843 | for arch in os.listdir(arch_path): | ||
| 1844 | if arch == "common" or arch == "layer": | ||
| 1845 | continue | ||
| 1846 | print " %s" % arch | ||
| 1847 | return True | ||
| 1848 | else: | ||
| 1849 | arch = args[0] | ||
| 1850 | |||
| 1851 | if len(args) < 2 or len(args) > 3: | ||
| 1852 | return False | ||
| 1853 | |||
| 1854 | if len(args) == 2: | ||
| 1855 | if args[1] == "properties": | ||
| 1856 | yocto_layer_list_properties(arch, scripts_path, properties_file) | ||
| 1857 | else: | ||
| 1858 | return False | ||
| 1859 | |||
| 1860 | if len(args) == 3: | ||
| 1861 | if args[1] == "property": | ||
| 1862 | yocto_layer_list_property_values(arch, args[2], scripts_path, properties_file) | ||
| 1863 | else: | ||
| 1864 | return False | ||
| 1865 | |||
| 1866 | return True | ||
| 1867 | |||
| 1868 | |||
| 1869 | def yocto_layer_list(args, scripts_path, properties_file): | ||
| 1870 | """ | ||
| 1871 | Print the complete list of input properties defined by the layer, | ||
| 1872 | or the possible values for a particular layer property. | ||
| 1873 | """ | ||
| 1874 | if len(args) < 1: | ||
| 1875 | return False | ||
| 1876 | |||
| 1877 | if len(args) < 1 or len(args) > 2: | ||
| 1878 | return False | ||
| 1879 | |||
| 1880 | if len(args) == 1: | ||
| 1881 | if args[0] == "properties": | ||
| 1882 | yocto_layer_list_properties("layer", scripts_path, properties_file, False) | ||
| 1883 | else: | ||
| 1884 | return False | ||
| 1885 | |||
| 1886 | if len(args) == 2: | ||
| 1887 | if args[0] == "property": | ||
| 1888 | yocto_layer_list_property_values("layer", args[1], scripts_path, properties_file, False) | ||
| 1889 | else: | ||
| 1890 | return False | ||
| 1891 | |||
| 1892 | return True | ||
| 1893 | |||
| 1894 | |||
| 1895 | def map_standard_kbranch(need_new_kbranch, new_kbranch, existing_kbranch): | ||
| 1896 | """ | ||
| 1897 | Return the linux-yocto bsp branch to use with the specified | ||
| 1898 | kbranch. This handles the -standard variants for 3.4 and 3.8; the | ||
| 1899 | other variants don't need mappings. | ||
| 1900 | """ | ||
| 1901 | if need_new_kbranch == "y": | ||
| 1902 | kbranch = new_kbranch | ||
| 1903 | else: | ||
| 1904 | kbranch = existing_kbranch | ||
| 1905 | |||
| 1906 | if kbranch.startswith("standard/common-pc-64"): | ||
| 1907 | return "bsp/common-pc-64/common-pc-64-standard.scc" | ||
| 1908 | if kbranch.startswith("standard/common-pc"): | ||
| 1909 | return "bsp/common-pc/common-pc-standard.scc" | ||
| 1910 | else: | ||
| 1911 | return "ktypes/standard/standard.scc" | ||
| 1912 | |||
| 1913 | |||
| 1914 | def map_preempt_rt_kbranch(need_new_kbranch, new_kbranch, existing_kbranch): | ||
| 1915 | """ | ||
| 1916 | Return the linux-yocto bsp branch to use with the specified | ||
| 1917 | kbranch. This handles the -preempt-rt variants for 3.4 and 3.8; | ||
| 1918 | the other variants don't need mappings. | ||
| 1919 | """ | ||
| 1920 | if need_new_kbranch == "y": | ||
| 1921 | kbranch = new_kbranch | ||
| 1922 | else: | ||
| 1923 | kbranch = existing_kbranch | ||
| 1924 | |||
| 1925 | if kbranch.startswith("standard/preempt-rt/common-pc-64"): | ||
| 1926 | return "bsp/common-pc-64/common-pc-64-preempt-rt.scc" | ||
| 1927 | if kbranch.startswith("standard/preempt-rt/common-pc"): | ||
| 1928 | return "bsp/common-pc/common-pc-preempt-rt.scc" | ||
| 1929 | else: | ||
| 1930 | return "ktypes/preempt-rt/preempt-rt.scc" | ||
| 1931 | |||
| 1932 | |||
| 1933 | def map_tiny_kbranch(need_new_kbranch, new_kbranch, existing_kbranch): | ||
| 1934 | """ | ||
| 1935 | Return the linux-yocto bsp branch to use with the specified | ||
| 1936 | kbranch. This handles the -tiny variants for 3.4 and 3.8; the | ||
| 1937 | other variants don't need mappings. | ||
| 1938 | """ | ||
| 1939 | if need_new_kbranch == "y": | ||
| 1940 | kbranch = new_kbranch | ||
| 1941 | else: | ||
| 1942 | kbranch = existing_kbranch | ||
| 1943 | |||
| 1944 | if kbranch.startswith("standard/tiny/common-pc"): | ||
| 1945 | return "bsp/common-pc/common-pc-tiny.scc" | ||
| 1946 | else: | ||
| 1947 | return "ktypes/tiny/tiny.scc" | ||
diff --git a/scripts/lib/bsp/help.py b/scripts/lib/bsp/help.py new file mode 100644 index 0000000000..7c436d6be0 --- /dev/null +++ b/scripts/lib/bsp/help.py | |||
| @@ -0,0 +1,1043 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2012, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This module implements some basic help invocation functions along | ||
| 22 | # with the bulk of the help topic text for the Yocto BSP Tools. | ||
| 23 | # | ||
| 24 | # AUTHORS | ||
| 25 | # Tom Zanussi <tom.zanussi (at] intel.com> | ||
| 26 | # | ||
| 27 | |||
| 28 | import subprocess | ||
| 29 | import logging | ||
| 30 | |||
| 31 | |||
| 32 | def subcommand_error(args): | ||
| 33 | logging.info("invalid subcommand %s" % args[0]) | ||
| 34 | |||
| 35 | |||
| 36 | def display_help(subcommand, subcommands): | ||
| 37 | """ | ||
| 38 | Display help for subcommand. | ||
| 39 | """ | ||
| 40 | if subcommand not in subcommands: | ||
| 41 | return False | ||
| 42 | |||
| 43 | help = subcommands.get(subcommand, subcommand_error)[2] | ||
| 44 | pager = subprocess.Popen('less', stdin=subprocess.PIPE) | ||
| 45 | pager.communicate(help) | ||
| 46 | |||
| 47 | return True | ||
| 48 | |||
| 49 | |||
| 50 | def yocto_help(args, usage_str, subcommands): | ||
| 51 | """ | ||
| 52 | Subcommand help dispatcher. | ||
| 53 | """ | ||
| 54 | if len(args) == 1 or not display_help(args[1], subcommands): | ||
| 55 | print(usage_str) | ||
| 56 | |||
| 57 | |||
| 58 | def invoke_subcommand(args, parser, main_command_usage, subcommands): | ||
| 59 | """ | ||
| 60 | Dispatch to subcommand handler borrowed from combo-layer. | ||
| 61 | Should use argparse, but has to work in 2.6. | ||
| 62 | """ | ||
| 63 | if not args: | ||
| 64 | logging.error("No subcommand specified, exiting") | ||
| 65 | parser.print_help() | ||
| 66 | elif args[0] == "help": | ||
| 67 | yocto_help(args, main_command_usage, subcommands) | ||
| 68 | elif args[0] not in subcommands: | ||
| 69 | logging.error("Unsupported subcommand %s, exiting\n" % (args[0])) | ||
| 70 | parser.print_help() | ||
| 71 | else: | ||
| 72 | usage = subcommands.get(args[0], subcommand_error)[1] | ||
| 73 | subcommands.get(args[0], subcommand_error)[0](args[1:], usage) | ||
| 74 | |||
| 75 | |||
| 76 | ## | ||
| 77 | # yocto-bsp help and usage strings | ||
| 78 | ## | ||
| 79 | |||
| 80 | yocto_bsp_usage = """ | ||
| 81 | |||
| 82 | Create a customized Yocto BSP layer. | ||
| 83 | |||
| 84 | usage: yocto-bsp [--version] [--help] COMMAND [ARGS] | ||
| 85 | |||
| 86 | Current 'yocto-bsp' commands are: | ||
| 87 | create Create a new Yocto BSP | ||
| 88 | list List available values for options and BSP properties | ||
| 89 | |||
| 90 | See 'yocto-bsp help COMMAND' for more information on a specific command. | ||
| 91 | """ | ||
| 92 | |||
| 93 | yocto_bsp_help_usage = """ | ||
| 94 | |||
| 95 | usage: yocto-bsp help <subcommand> | ||
| 96 | |||
| 97 | This command displays detailed help for the specified subcommand. | ||
| 98 | """ | ||
| 99 | |||
| 100 | yocto_bsp_create_usage = """ | ||
| 101 | |||
| 102 | Create a new Yocto BSP | ||
| 103 | |||
| 104 | usage: yocto-bsp create <bsp-name> <karch> [-o <DIRNAME> | --outdir <DIRNAME>] | ||
| 105 | [-i <JSON PROPERTY FILE> | --infile <JSON PROPERTY_FILE>] | ||
| 106 | |||
| 107 | This command creates a Yocto BSP based on the specified parameters. | ||
| 108 | The new BSP will be a new Yocto BSP layer contained by default within | ||
| 109 | the top-level directory specified as 'meta-bsp-name'. The -o option | ||
| 110 | can be used to place the BSP layer in a directory with a different | ||
| 111 | name and location. | ||
| 112 | |||
| 113 | The value of the 'karch' parameter determines the set of files that | ||
| 114 | will be generated for the BSP, along with the specific set of | ||
| 115 | 'properties' that will be used to fill out the BSP-specific portions | ||
| 116 | of the BSP. The possible values for the 'karch' paramter can be | ||
| 117 | listed via 'yocto-bsp list karch'. | ||
| 118 | |||
| 119 | NOTE: Once created, you should add your new layer to your | ||
| 120 | bblayers.conf file in order for it to be subsequently seen and | ||
| 121 | modified by the yocto-kernel tool. | ||
| 122 | |||
| 123 | See 'yocto bsp help create' for more detailed instructions. | ||
| 124 | """ | ||
| 125 | |||
| 126 | yocto_bsp_create_help = """ | ||
| 127 | |||
| 128 | NAME | ||
| 129 | yocto-bsp create - Create a new Yocto BSP | ||
| 130 | |||
| 131 | SYNOPSIS | ||
| 132 | yocto-bsp create <bsp-name> <karch> [-o <DIRNAME> | --outdir <DIRNAME>] | ||
| 133 | [-i <JSON PROPERTY FILE> | --infile <JSON PROPERTY_FILE>] | ||
| 134 | |||
| 135 | DESCRIPTION | ||
| 136 | This command creates a Yocto BSP based on the specified | ||
| 137 | parameters. The new BSP will be a new Yocto BSP layer contained | ||
| 138 | by default within the top-level directory specified as | ||
| 139 | 'meta-bsp-name'. The -o option can be used to place the BSP layer | ||
| 140 | in a directory with a different name and location. | ||
| 141 | |||
| 142 | The value of the 'karch' parameter determines the set of files | ||
| 143 | that will be generated for the BSP, along with the specific set of | ||
| 144 | 'properties' that will be used to fill out the BSP-specific | ||
| 145 | portions of the BSP. The possible values for the 'karch' paramter | ||
| 146 | can be listed via 'yocto-bsp list karch'. | ||
| 147 | |||
| 148 | The BSP-specific properties that define the values that will be | ||
| 149 | used to generate a particular BSP can be specified on the | ||
| 150 | command-line using the -i option and supplying a JSON object | ||
| 151 | consisting of the set of name:value pairs needed by the BSP. | ||
| 152 | |||
| 153 | If the -i option is not used, the user will be interactively | ||
| 154 | prompted for each of the required property values, which will then | ||
| 155 | be used as values for BSP generation. | ||
| 156 | |||
| 157 | The set of properties available for a given architecture can be | ||
| 158 | listed using the 'yocto-bsp list' command. | ||
| 159 | |||
| 160 | Specifying -c causes the Python code generated and executed to | ||
| 161 | create the BSP to be dumped to the 'bspgen.out' file in the | ||
| 162 | current directory, and is useful for debugging. | ||
| 163 | |||
| 164 | NOTE: Once created, you should add your new layer to your | ||
| 165 | bblayers.conf file in order for it to be subsequently seen and | ||
| 166 | modified by the yocto-kernel tool. | ||
| 167 | |||
| 168 | For example, assuming your poky repo is at /path/to/poky, your new | ||
| 169 | BSP layer is at /path/to/poky/meta-mybsp, and your build directory | ||
| 170 | is /path/to/build: | ||
| 171 | |||
| 172 | $ gedit /path/to/build/conf/bblayers.conf | ||
| 173 | |||
| 174 | BBLAYERS ?= " \\ | ||
| 175 | /path/to/poky/meta \\ | ||
| 176 | /path/to/poky/meta-yocto \\ | ||
| 177 | /path/to/poky/meta-mybsp \\ | ||
| 178 | " | ||
| 179 | """ | ||
| 180 | |||
| 181 | yocto_bsp_list_usage = """ | ||
| 182 | |||
| 183 | usage: yocto-bsp list karch | ||
| 184 | yocto-bsp list <karch> properties | ||
| 185 | [-o <JSON PROPERTY FILE> | --outfile <JSON PROPERTY_FILE>] | ||
| 186 | yocto-bsp list <karch> property <xxx> | ||
| 187 | [-o <JSON PROPERTY FILE> | --outfile <JSON PROPERTY_FILE>] | ||
| 188 | |||
| 189 | This command enumerates the complete set of possible values for a | ||
| 190 | specified option or property needed by the BSP creation process. | ||
| 191 | |||
| 192 | The first form enumerates all the possible values that exist and can | ||
| 193 | be specified for the 'karch' parameter to the 'yocto bsp create' | ||
| 194 | command. | ||
| 195 | |||
| 196 | The second form enumerates all the possible properties that exist and | ||
| 197 | must have values specified for them in the 'yocto bsp create' command | ||
| 198 | for the given 'karch'. | ||
| 199 | |||
| 200 | The third form enumerates all the possible values that exist and can | ||
| 201 | be specified for any of the enumerable properties of the given | ||
| 202 | 'karch' in the 'yocto bsp create' command. | ||
| 203 | |||
| 204 | See 'yocto-bsp help list' for more details. | ||
| 205 | """ | ||
| 206 | |||
| 207 | yocto_bsp_list_help = """ | ||
| 208 | |||
| 209 | NAME | ||
| 210 | yocto-bsp list - List available values for options and BSP properties | ||
| 211 | |||
| 212 | SYNOPSIS | ||
| 213 | yocto-bsp list karch | ||
| 214 | yocto-bsp list <karch> properties | ||
| 215 | [--o <JSON PROPERTY FILE> | -outfile <JSON PROPERTY_FILE>] | ||
| 216 | yocto-bsp list <karch> property <xxx> | ||
| 217 | [--o <JSON PROPERTY FILE> | -outfile <JSON PROPERTY_FILE>] | ||
| 218 | |||
| 219 | DESCRIPTION | ||
| 220 | This command enumerates the complete set of possible values for a | ||
| 221 | specified option or property needed by the BSP creation process. | ||
| 222 | |||
| 223 | The first form enumerates all the possible values that exist and | ||
| 224 | can be specified for the 'karch' parameter to the 'yocto bsp | ||
| 225 | create' command. Example output for the 'list karch' command: | ||
| 226 | |||
| 227 | $ yocto-bsp list karch | ||
| 228 | Architectures available: | ||
| 229 | arm | ||
| 230 | powerpc | ||
| 231 | i386 | ||
| 232 | mips | ||
| 233 | x86_64 | ||
| 234 | qemu | ||
| 235 | |||
| 236 | The second form enumerates all the possible properties that exist | ||
| 237 | and must have values specified for them in the 'yocto bsp create' | ||
| 238 | command for the given 'karch'. This command is mainly meant to | ||
| 239 | allow the development user interface alternatives to the default | ||
| 240 | text-based prompting interface. If the -o option is specified, | ||
| 241 | the list of properties, in addition to being displayed, will be | ||
| 242 | written to the specified file as a JSON object. In this case, the | ||
| 243 | object will consist of the set of name:value pairs corresponding | ||
| 244 | to the (possibly nested) dictionary of properties defined by the | ||
| 245 | input statements used by the BSP. Some example output for the | ||
| 246 | 'list properties' command: | ||
| 247 | |||
| 248 | $ yocto-bsp list arm properties | ||
| 249 | "touchscreen" : { | ||
| 250 | "msg" : Does your BSP have a touchscreen? (y/N) | ||
| 251 | "default" : n | ||
| 252 | "type" : boolean | ||
| 253 | } | ||
| 254 | "uboot_loadaddress" : { | ||
| 255 | "msg" : Please specify a value for UBOOT_LOADADDRESS. | ||
| 256 | "default" : 0x80008000 | ||
| 257 | "type" : edit | ||
| 258 | "prio" : 40 | ||
| 259 | } | ||
| 260 | "kernel_choice" : { | ||
| 261 | "prio" : 10 | ||
| 262 | "default" : linux-yocto_3.2 | ||
| 263 | "depends-on" : use_default_kernel | ||
| 264 | "depends-on-val" : n | ||
| 265 | "msg" : Please choose the kernel to use in this BSP => | ||
| 266 | "type" : choicelist | ||
| 267 | "gen" : bsp.kernel.kernels | ||
| 268 | } | ||
| 269 | "if kernel_choice == "linux-yocto_3.0":" : { | ||
| 270 | "base_kbranch_linux_yocto_3_0" : { | ||
| 271 | "prio" : 20 | ||
| 272 | "default" : yocto/standard | ||
| 273 | "depends-on" : new_kbranch_linux_yocto_3_0 | ||
| 274 | "depends-on-val" : y | ||
| 275 | "msg" : Please choose a machine branch to base this BSP on => | ||
| 276 | "type" : choicelist | ||
| 277 | "gen" : bsp.kernel.all_branches | ||
| 278 | } | ||
| 279 | . | ||
| 280 | . | ||
| 281 | . | ||
| 282 | |||
| 283 | Each entry in the output consists of the name of the input element | ||
| 284 | e.g. "touchscreen", followed by the properties defined for that | ||
| 285 | element enclosed in braces. This information should provide | ||
| 286 | sufficient information to create a complete user interface with. | ||
| 287 | Two features of the scheme provide for conditional input. First, | ||
| 288 | if a Python "if" statement appears in place of an input element | ||
| 289 | name, the set of enclosed input elements apply and should be | ||
| 290 | presented to the user only if the 'if' statement evaluates to | ||
| 291 | true. The test in the if statement will always reference another | ||
| 292 | input element in the list, which means that the element being | ||
| 293 | tested should be presented to the user before the elements | ||
| 294 | enclosed by the if block. Secondly, in a similar way, some | ||
| 295 | elements contain "depends-on" and depends-on-val" tags, which mean | ||
| 296 | that the affected input element should only be presented to the | ||
| 297 | user if the element it depends on has already been presented to | ||
| 298 | the user and the user has selected the specified value for that | ||
| 299 | element. | ||
| 300 | |||
| 301 | The third form enumerates all the possible values that exist and | ||
| 302 | can be specified for any of the enumerable properties of the given | ||
| 303 | 'karch' in the 'yocto bsp create' command. If the -o option is | ||
| 304 | specified, the list of values for the given property, in addition | ||
| 305 | to being displayed, will be written to the specified file as a | ||
| 306 | JSON object. In this case, the object will consist of the set of | ||
| 307 | name:value pairs corresponding to the array of property values | ||
| 308 | associated with the property. | ||
| 309 | |||
| 310 | $ yocto-bsp list i386 property xserver_choice | ||
| 311 | ["xserver_vesa", "VESA xserver support"] | ||
| 312 | ["xserver_i915", "i915 xserver support"] | ||
| 313 | |||
| 314 | $ yocto-bsp list arm property base_kbranch_linux_yocto_3_0 | ||
| 315 | Getting branches from remote repo git://git.yoctoproject.org/linux-yocto-3.0... | ||
| 316 | ["yocto/base", "yocto/base"] | ||
| 317 | ["yocto/eg20t", "yocto/eg20t"] | ||
| 318 | ["yocto/gma500", "yocto/gma500"] | ||
| 319 | ["yocto/pvr", "yocto/pvr"] | ||
| 320 | ["yocto/standard/arm-versatile-926ejs", "yocto/standard/arm-versatile-926ejs"] | ||
| 321 | ["yocto/standard/base", "yocto/standard/base"] | ||
| 322 | ["yocto/standard/cedartrail", "yocto/standard/cedartrail"] | ||
| 323 | . | ||
| 324 | . | ||
| 325 | . | ||
| 326 | ["yocto/standard/qemu-ppc32", "yocto/standard/qemu-ppc32"] | ||
| 327 | ["yocto/standard/routerstationpro", "yocto/standard/routerstationpro"] | ||
| 328 | |||
| 329 | The third form as well is meant mainly for developers of | ||
| 330 | alternative interfaces - it allows the developer to fetch the | ||
| 331 | possible values for a given input element on-demand. This | ||
| 332 | on-demand capability is especially valuable for elements that | ||
| 333 | require relatively expensive remote operations to fulfill, such as | ||
| 334 | the example that returns the set of branches available in a remote | ||
| 335 | git tree above. | ||
| 336 | |||
| 337 | """ | ||
| 338 | |||
| 339 | ## | ||
| 340 | # yocto-kernel help and usage strings | ||
| 341 | ## | ||
| 342 | |||
| 343 | yocto_kernel_usage = """ | ||
| 344 | |||
| 345 | Modify and list Yocto BSP kernel config items and patches. | ||
| 346 | |||
| 347 | usage: yocto-kernel [--version] [--help] COMMAND [ARGS] | ||
| 348 | |||
| 349 | Current 'yocto-kernel' commands are: | ||
| 350 | config list List the modifiable set of bare kernel config options for a BSP | ||
| 351 | config add Add or modify bare kernel config options for a BSP | ||
| 352 | config rm Remove bare kernel config options from a BSP | ||
| 353 | patch list List the patches associated with a BSP | ||
| 354 | patch add Patch the Yocto kernel for a BSP | ||
| 355 | patch rm Remove patches from a BSP | ||
| 356 | feature list List the features used by a BSP | ||
| 357 | feature add Have a BSP use a feature | ||
| 358 | feature rm Have a BSP stop using a feature | ||
| 359 | features list List the features available to BSPs | ||
| 360 | feature describe Describe a particular feature | ||
| 361 | feature create Create a new BSP-local feature | ||
| 362 | feature destroy Remove a BSP-local feature | ||
| 363 | |||
| 364 | See 'yocto-kernel help COMMAND' for more information on a specific command. | ||
| 365 | |||
| 366 | """ | ||
| 367 | |||
| 368 | |||
| 369 | yocto_kernel_help_usage = """ | ||
| 370 | |||
| 371 | usage: yocto-kernel help <subcommand> | ||
| 372 | |||
| 373 | This command displays detailed help for the specified subcommand. | ||
| 374 | """ | ||
| 375 | |||
| 376 | yocto_kernel_config_list_usage = """ | ||
| 377 | |||
| 378 | List the modifiable set of bare kernel config options for a BSP | ||
| 379 | |||
| 380 | usage: yocto-kernel config list <bsp-name> | ||
| 381 | |||
| 382 | This command lists the 'modifiable' config items for a BSP i.e. the | ||
| 383 | items which are eligible for modification or removal by other | ||
| 384 | yocto-kernel commands. | ||
| 385 | |||
| 386 | 'modifiable' config items are the config items contained a BSP's | ||
| 387 | user-config.cfg base config. | ||
| 388 | """ | ||
| 389 | |||
| 390 | |||
| 391 | yocto_kernel_config_list_help = """ | ||
| 392 | |||
| 393 | NAME | ||
| 394 | yocto-kernel config list - List the modifiable set of bare kernel | ||
| 395 | config options for a BSP | ||
| 396 | |||
| 397 | SYNOPSIS | ||
| 398 | yocto-kernel config list <bsp-name> | ||
| 399 | |||
| 400 | DESCRIPTION | ||
| 401 | This command lists the 'modifiable' config items for a BSP | ||
| 402 | i.e. the items which are eligible for modification or removal by | ||
| 403 | other yocto-kernel commands. | ||
| 404 | """ | ||
| 405 | |||
| 406 | |||
| 407 | yocto_kernel_config_add_usage = """ | ||
| 408 | |||
| 409 | Add or modify bare kernel config options for a BSP | ||
| 410 | |||
| 411 | usage: yocto-kernel config add <bsp-name> [<CONFIG_XXX=x> ...] | ||
| 412 | |||
| 413 | This command adds one or more CONFIG_XXX=x items to a BSP's user-config.cfg | ||
| 414 | base config. | ||
| 415 | """ | ||
| 416 | |||
| 417 | |||
| 418 | yocto_kernel_config_add_help = """ | ||
| 419 | |||
| 420 | NAME | ||
| 421 | yocto-kernel config add - Add or modify bare kernel config options | ||
| 422 | for a BSP | ||
| 423 | |||
| 424 | SYNOPSIS | ||
| 425 | yocto-kernel config add <bsp-name> [<CONFIG_XXX=x> ...] | ||
| 426 | |||
| 427 | DESCRIPTION | ||
| 428 | This command adds one or more CONFIG_XXX=x items to a BSP's | ||
| 429 | foo.cfg base config. | ||
| 430 | |||
| 431 | NOTE: It's up to the user to determine whether or not the config | ||
| 432 | options being added make sense or not - this command does no | ||
| 433 | sanity checking or verification of any kind to ensure that a | ||
| 434 | config option really makes sense and will actually be set in in | ||
| 435 | the final config. For example, if a config option depends on | ||
| 436 | other config options, it will be turned off by kconfig if the | ||
| 437 | other options aren't set correctly. | ||
| 438 | """ | ||
| 439 | |||
| 440 | |||
| 441 | yocto_kernel_config_rm_usage = """ | ||
| 442 | |||
| 443 | Remove bare kernel config options from a BSP | ||
| 444 | |||
| 445 | usage: yocto-kernel config rm <bsp-name> | ||
| 446 | |||
| 447 | This command removes (turns off) one or more CONFIG_XXX items from a | ||
| 448 | BSP's user-config.cfg base config. | ||
| 449 | |||
| 450 | The set of config items available to be removed by this command for a | ||
| 451 | BSP is listed and the user prompted for the specific items to remove. | ||
| 452 | """ | ||
| 453 | |||
| 454 | |||
| 455 | yocto_kernel_config_rm_help = """ | ||
| 456 | |||
| 457 | NAME | ||
| 458 | yocto-kernel config rm - Remove bare kernel config options from a | ||
| 459 | BSP | ||
| 460 | |||
| 461 | SYNOPSIS | ||
| 462 | yocto-kernel config rm <bsp-name> | ||
| 463 | |||
| 464 | DESCRIPTION | ||
| 465 | This command removes (turns off) one or more CONFIG_XXX items from a | ||
| 466 | BSP's user-config.cfg base config. | ||
| 467 | |||
| 468 | The set of config items available to be removed by this command | ||
| 469 | for a BSP is listed and the user prompted for the specific items | ||
| 470 | to remove. | ||
| 471 | """ | ||
| 472 | |||
| 473 | |||
| 474 | yocto_kernel_patch_list_usage = """ | ||
| 475 | |||
| 476 | List the patches associated with the kernel for a BSP | ||
| 477 | |||
| 478 | usage: yocto-kernel patch list <bsp-name> | ||
| 479 | |||
| 480 | This command lists the patches associated with a BSP. | ||
| 481 | |||
| 482 | NOTE: this only applies to patches listed in the kernel recipe's | ||
| 483 | user-patches.scc file (and currently repeated in its SRC_URI). | ||
| 484 | """ | ||
| 485 | |||
| 486 | |||
| 487 | yocto_kernel_patch_list_help = """ | ||
| 488 | |||
| 489 | NAME | ||
| 490 | yocto-kernel patch list - List the patches associated with the kernel | ||
| 491 | for a BSP | ||
| 492 | |||
| 493 | SYNOPSIS | ||
| 494 | yocto-kernel patch list <bsp-name> | ||
| 495 | |||
| 496 | DESCRIPTION | ||
| 497 | This command lists the patches associated with a BSP. | ||
| 498 | |||
| 499 | NOTE: this only applies to patches listed in the kernel recipe's | ||
| 500 | user-patches.scc file (and currently repeated in its SRC_URI). | ||
| 501 | """ | ||
| 502 | |||
| 503 | |||
| 504 | yocto_kernel_patch_add_usage = """ | ||
| 505 | |||
| 506 | Patch the Yocto kernel for a specific BSP | ||
| 507 | |||
| 508 | usage: yocto-kernel patch add <bsp-name> [<PATCH> ...] | ||
| 509 | |||
| 510 | This command adds one or more patches to a BSP's machine branch. The | ||
| 511 | patch will be added to the BSP's linux-yocto kernel user-patches.scc | ||
| 512 | file (and currently repeated in its SRC_URI) and will be guaranteed | ||
| 513 | to be applied in the order specified. | ||
| 514 | """ | ||
| 515 | |||
| 516 | |||
| 517 | yocto_kernel_patch_add_help = """ | ||
| 518 | |||
| 519 | NAME | ||
| 520 | yocto-kernel patch add - Patch the Yocto kernel for a specific BSP | ||
| 521 | |||
| 522 | SYNOPSIS | ||
| 523 | yocto-kernel patch add <bsp-name> [<PATCH> ...] | ||
| 524 | |||
| 525 | DESCRIPTION | ||
| 526 | This command adds one or more patches to a BSP's machine branch. | ||
| 527 | The patch will be added to the BSP's linux-yocto kernel | ||
| 528 | user-patches.scc file (and currently repeated in its SRC_URI) and | ||
| 529 | will be guaranteed to be applied in the order specified. | ||
| 530 | |||
| 531 | NOTE: It's up to the user to determine whether or not the patches | ||
| 532 | being added makes sense or not - this command does no sanity | ||
| 533 | checking or verification of any kind to ensure that a patch can | ||
| 534 | actually be applied to the BSP's kernel branch; it's assumed that | ||
| 535 | the user has already done that. | ||
| 536 | """ | ||
| 537 | |||
| 538 | |||
| 539 | yocto_kernel_patch_rm_usage = """ | ||
| 540 | |||
| 541 | Remove a patch from the Yocto kernel for a specific BSP | ||
| 542 | |||
| 543 | usage: yocto-kernel patch rm <bsp-name> | ||
| 544 | |||
| 545 | This command removes one or more patches from a BSP's machine branch. | ||
| 546 | The patch will be removed from the BSP's linux-yocto kernel | ||
| 547 | user-patches.scc file (and currently repeated in its SRC_URI) and | ||
| 548 | kernel SRC_URI dir. | ||
| 549 | |||
| 550 | The set of patches available to be removed by this command for a BSP | ||
| 551 | is listed and the user prompted for the specific patches to remove. | ||
| 552 | """ | ||
| 553 | |||
| 554 | |||
| 555 | yocto_kernel_patch_rm_help = """ | ||
| 556 | |||
| 557 | NAME | ||
| 558 | yocto-kernel patch rm - Remove a patch from the Yocto kernel for a specific BSP | ||
| 559 | |||
| 560 | SYNOPSIS | ||
| 561 | yocto-kernel patch rm <bsp-name> | ||
| 562 | |||
| 563 | DESCRIPTION | ||
| 564 | This command removes one or more patches from a BSP's machine | ||
| 565 | branch. The patch will be removed from the BSP's linux-yocto | ||
| 566 | kernel user-patches.scc file (and currently repeated in its | ||
| 567 | SRC_URI). | ||
| 568 | |||
| 569 | The set of patches available to be removed by this command for a | ||
| 570 | BSP is listed and the user prompted for the specific patches to | ||
| 571 | remove. | ||
| 572 | """ | ||
| 573 | |||
| 574 | yocto_kernel_feature_list_usage = """ | ||
| 575 | |||
| 576 | List the BSP features that are being used by a BSP | ||
| 577 | |||
| 578 | usage: yocto-kernel feature list <bsp-name> | ||
| 579 | |||
| 580 | This command lists the features being used by a BSP i.e. the features | ||
| 581 | which are eligible for modification or removal by other yocto-kernel | ||
| 582 | commands. | ||
| 583 | |||
| 584 | 'modifiable' features are the features listed in a BSP's | ||
| 585 | user-features.scc file. | ||
| 586 | """ | ||
| 587 | |||
| 588 | |||
| 589 | yocto_kernel_feature_list_help = """ | ||
| 590 | |||
| 591 | NAME | ||
| 592 | yocto-kernel feature list - List the modifiable set of features | ||
| 593 | being used by a BSP | ||
| 594 | |||
| 595 | SYNOPSIS | ||
| 596 | yocto-kernel feature list <bsp-name> | ||
| 597 | |||
| 598 | DESCRIPTION | ||
| 599 | This command lists the 'modifiable' features being used by a BSP | ||
| 600 | i.e. the features which are eligible for modification or removal | ||
| 601 | by other yocto-kernel commands. | ||
| 602 | """ | ||
| 603 | |||
| 604 | |||
| 605 | yocto_kernel_feature_add_usage = """ | ||
| 606 | |||
| 607 | Add to or modify the list of features being used for a BSP | ||
| 608 | |||
| 609 | usage: yocto-kernel feature add <bsp-name> [/xxxx/yyyy/feature.scc ...] | ||
| 610 | |||
| 611 | This command adds one or more feature items to a BSP's kernel | ||
| 612 | user-features.scc file, which is the file used to manage features in | ||
| 613 | a yocto-bsp-generated BSP. Features to be added must be specified as | ||
| 614 | fully-qualified feature names. | ||
| 615 | """ | ||
| 616 | |||
| 617 | |||
| 618 | yocto_kernel_feature_add_help = """ | ||
| 619 | |||
| 620 | NAME | ||
| 621 | yocto-kernel feature add - Add to or modify the list of features | ||
| 622 | being used for a BSP | ||
| 623 | |||
| 624 | SYNOPSIS | ||
| 625 | yocto-kernel feature add <bsp-name> [/xxxx/yyyy/feature.scc ...] | ||
| 626 | |||
| 627 | DESCRIPTION | ||
| 628 | This command adds one or more feature items to a BSP's | ||
| 629 | user-features.scc file, which is the file used to manage features | ||
| 630 | in a yocto-bsp-generated BSP. Features to be added must be | ||
| 631 | specified as fully-qualified feature names. | ||
| 632 | """ | ||
| 633 | |||
| 634 | |||
| 635 | yocto_kernel_feature_rm_usage = """ | ||
| 636 | |||
| 637 | Remove a feature from the list of features being used for a BSP | ||
| 638 | |||
| 639 | usage: yocto-kernel feature rm <bsp-name> | ||
| 640 | |||
| 641 | This command removes (turns off) one or more features from a BSP's | ||
| 642 | user-features.scc file, which is the file used to manage features in | ||
| 643 | a yocto-bsp-generated BSP. | ||
| 644 | |||
| 645 | The set of features available to be removed by this command for a BSP | ||
| 646 | is listed and the user prompted for the specific items to remove. | ||
| 647 | """ | ||
| 648 | |||
| 649 | |||
| 650 | yocto_kernel_feature_rm_help = """ | ||
| 651 | |||
| 652 | NAME | ||
| 653 | yocto-kernel feature rm - Remove a feature from the list of | ||
| 654 | features being used for a BSP | ||
| 655 | |||
| 656 | SYNOPSIS | ||
| 657 | yocto-kernel feature rm <bsp-name> | ||
| 658 | |||
| 659 | DESCRIPTION | ||
| 660 | This command removes (turns off) one or more features from a BSP's | ||
| 661 | user-features.scc file, which is the file used to manage features | ||
| 662 | in a yocto-bsp-generated BSP. | ||
| 663 | |||
| 664 | The set of features available to be removed by this command for a | ||
| 665 | BSP is listed and the user prompted for the specific items to | ||
| 666 | remove. | ||
| 667 | """ | ||
| 668 | |||
| 669 | |||
| 670 | yocto_kernel_available_features_list_usage = """ | ||
| 671 | |||
| 672 | List the set of kernel features available to a BSP | ||
| 673 | |||
| 674 | usage: yocto-kernel features list <bsp-name> | ||
| 675 | |||
| 676 | This command lists the complete set of kernel features available to a | ||
| 677 | BSP. This includes the features contained in linux-yocto meta | ||
| 678 | branches as well as recipe-space features defined locally to the BSP. | ||
| 679 | """ | ||
| 680 | |||
| 681 | |||
| 682 | yocto_kernel_available_features_list_help = """ | ||
| 683 | |||
| 684 | NAME | ||
| 685 | yocto-kernel features list - List the set of kernel features | ||
| 686 | available to a BSP | ||
| 687 | |||
| 688 | SYNOPSIS | ||
| 689 | yocto-kernel features list <bsp-name> | ||
| 690 | |||
| 691 | DESCRIPTION | ||
| 692 | This command lists the complete set of kernel features available | ||
| 693 | to a BSP. This includes the features contained in linux-yocto | ||
| 694 | meta branches as well as recipe-space features defined locally to | ||
| 695 | the BSP. | ||
| 696 | """ | ||
| 697 | |||
| 698 | |||
| 699 | yocto_kernel_feature_describe_usage = """ | ||
| 700 | |||
| 701 | Print the description and compatibility information for a given kernel feature | ||
| 702 | |||
| 703 | usage: yocto-kernel feature describe <bsp-name> [/xxxx/yyyy/feature.scc ...] | ||
| 704 | |||
| 705 | This command prints the description and compatibility of a specific | ||
| 706 | feature in the format 'description [compatibility]. | ||
| 707 | """ | ||
| 708 | |||
| 709 | |||
| 710 | yocto_kernel_feature_describe_help = """ | ||
| 711 | |||
| 712 | NAME | ||
| 713 | yocto-kernel feature describe - print the description and | ||
| 714 | compatibility information for a given kernel feature | ||
| 715 | |||
| 716 | SYNOPSIS | ||
| 717 | yocto-kernel feature describe <bsp-name> [/xxxx/yyyy/feature.scc ...] | ||
| 718 | |||
| 719 | DESCRIPTION | ||
| 720 | This command prints the description and compatibility of a | ||
| 721 | specific feature in the format 'description [compatibility]. If | ||
| 722 | the feature doesn't define a description or compatibility, a | ||
| 723 | string with generic unknown values will be printed. | ||
| 724 | """ | ||
| 725 | |||
| 726 | |||
| 727 | yocto_kernel_feature_create_usage = """ | ||
| 728 | |||
| 729 | Create a recipe-space kernel feature in a BSP | ||
| 730 | |||
| 731 | usage: yocto-kernel feature create <bsp-name> newfeature.scc \ | ||
| 732 | "Feature Description" capabilities [<CONFIG_XXX=x> ...] [<PATCH> ...] | ||
| 733 | |||
| 734 | This command creates a new kernel feature from the bare config | ||
| 735 | options and patches specified on the command-line. | ||
| 736 | """ | ||
| 737 | |||
| 738 | |||
| 739 | yocto_kernel_feature_create_help = """ | ||
| 740 | |||
| 741 | NAME | ||
| 742 | yocto-kernel feature create - create a recipe-space kernel feature | ||
| 743 | in a BSP | ||
| 744 | |||
| 745 | SYNOPSIS | ||
| 746 | yocto-kernel feature create <bsp-name> newfeature.scc \ | ||
| 747 | "Feature Description" capabilities [<CONFIG_XXX=x> ...] [<PATCH> ...] | ||
| 748 | |||
| 749 | DESCRIPTION | ||
| 750 | This command creates a new kernel feature from the bare config | ||
| 751 | options and patches specified on the command-line. The new | ||
| 752 | feature will be created in recipe-space, specifically in either | ||
| 753 | the kernel .bbappend's /files/cfg or /files/features subdirectory, | ||
| 754 | depending on whether or not the feature contains config items only | ||
| 755 | or config items along with patches. The named feature must end | ||
| 756 | with .scc and must not contain a feature directory to contain the | ||
| 757 | feature (this will be determined automatically), and a feature | ||
| 758 | decription in double-quotes along with a capabilities string | ||
| 759 | (which for the time being can be one of: 'all' or 'board'). | ||
| 760 | """ | ||
| 761 | |||
| 762 | |||
| 763 | yocto_kernel_feature_destroy_usage = """ | ||
| 764 | |||
| 765 | Destroy a recipe-space kernel feature in a BSP | ||
| 766 | |||
| 767 | usage: yocto-kernel feature destroy <bsp-name> feature.scc | ||
| 768 | |||
| 769 | This command destroys a kernel feature defined in the specified BSP's | ||
| 770 | recipe-space kernel definition. | ||
| 771 | """ | ||
| 772 | |||
| 773 | |||
| 774 | yocto_kernel_feature_destroy_help = """ | ||
| 775 | |||
| 776 | NAME | ||
| 777 | yocto-kernel feature destroy <bsp-name> feature.scc - destroy a | ||
| 778 | recipe-space kernel feature in a BSP | ||
| 779 | |||
| 780 | SYNOPSIS | ||
| 781 | yocto-kernel feature destroy <bsp-name> feature.scc | ||
| 782 | |||
| 783 | DESCRIPTION | ||
| 784 | This command destroys a kernel feature defined in the specified | ||
| 785 | BSP's recipe-space kernel definition. The named feature must end | ||
| 786 | with .scc and must not contain a feature directory to contain the | ||
| 787 | feature (this will be determined automatically). If the kernel | ||
| 788 | feature is in use by a BSP, it can't be removed until the BSP | ||
| 789 | stops using it (see yocto-kernel feature rm to stop using it). | ||
| 790 | """ | ||
| 791 | |||
| 792 | ## | ||
| 793 | # yocto-layer help and usage strings | ||
| 794 | ## | ||
| 795 | |||
| 796 | yocto_layer_usage = """ | ||
| 797 | |||
| 798 | Create a generic Yocto layer. | ||
| 799 | |||
| 800 | usage: yocto-layer [--version] [--help] COMMAND [ARGS] | ||
| 801 | |||
| 802 | Current 'yocto-layer' commands are: | ||
| 803 | create Create a new generic Yocto layer | ||
| 804 | list List available values for input options and properties | ||
| 805 | |||
| 806 | See 'yocto-layer help COMMAND' for more information on a specific command. | ||
| 807 | """ | ||
| 808 | |||
| 809 | yocto_layer_help_usage = """ | ||
| 810 | |||
| 811 | usage: yocto-layer help <subcommand> | ||
| 812 | |||
| 813 | This command displays detailed help for the specified subcommand. | ||
| 814 | """ | ||
| 815 | |||
| 816 | yocto_layer_create_usage = """ | ||
| 817 | |||
| 818 | Create a new generic Yocto layer | ||
| 819 | |||
| 820 | usage: yocto-layer create <layer-name> [layer_priority] | ||
| 821 | [-o <DIRNAME> | --outdir <DIRNAME>] | ||
| 822 | [-i <JSON PROPERTY FILE> | --infile <JSON PROPERTY_FILE>] | ||
| 823 | |||
| 824 | This command creates a generic Yocto layer based on the specified | ||
| 825 | parameters. The new layer will be a new Yocto layer contained by | ||
| 826 | default within the top-level directory specified as | ||
| 827 | 'meta-layer-name'. The -o option can be used to place the layer in a | ||
| 828 | directory with a different name and location. | ||
| 829 | |||
| 830 | If layer_priority is specified, a simple layer will be created using | ||
| 831 | the given layer priority, and the user will not be prompted for | ||
| 832 | further input. | ||
| 833 | |||
| 834 | NOTE: Once created, you should add your new layer to your | ||
| 835 | bblayers.conf file in order for it to be subsequently seen and | ||
| 836 | modified by the yocto-kernel tool. Instructions for doing this can | ||
| 837 | be found in the README file generated in the layer's top-level | ||
| 838 | directory. | ||
| 839 | |||
| 840 | See 'yocto layer help create' for more detailed instructions. | ||
| 841 | """ | ||
| 842 | |||
| 843 | yocto_layer_create_help = """ | ||
| 844 | |||
| 845 | NAME | ||
| 846 | yocto-layer create - Create a new generic Yocto layer | ||
| 847 | |||
| 848 | SYNOPSIS | ||
| 849 | yocto-layer create <layer-name> [layer_priority] | ||
| 850 | [-o <DIRNAME> | --outdir <DIRNAME>] | ||
| 851 | [-i <JSON PROPERTY FILE> | --infile <JSON PROPERTY_FILE>] | ||
| 852 | |||
| 853 | DESCRIPTION | ||
| 854 | This command creates a generic Yocto layer based on the specified | ||
| 855 | parameters. The new layer will be a new Yocto layer contained by | ||
| 856 | default within the top-level directory specified as | ||
| 857 | 'meta-layer-name'. The -o option can be used to place the layer | ||
| 858 | in a directory with a different name and location. | ||
| 859 | |||
| 860 | If layer_priority is specified, a simple layer will be created | ||
| 861 | using the given layer priority, and the user will not be prompted | ||
| 862 | for further input. | ||
| 863 | |||
| 864 | The layer-specific properties that define the values that will be | ||
| 865 | used to generate the layer can be specified on the command-line | ||
| 866 | using the -i option and supplying a JSON object consisting of the | ||
| 867 | set of name:value pairs needed by the layer. | ||
| 868 | |||
| 869 | If the -i option is not used, the user will be interactively | ||
| 870 | prompted for each of the required property values, which will then | ||
| 871 | be used as values for layer generation. | ||
| 872 | |||
| 873 | The set of properties available can be listed using the | ||
| 874 | 'yocto-layer list' command. | ||
| 875 | |||
| 876 | Specifying -c causes the Python code generated and executed to | ||
| 877 | create the layer to be dumped to the 'bspgen.out' file in the | ||
| 878 | current directory, and is useful for debugging. | ||
| 879 | |||
| 880 | NOTE: Once created, you should add your new layer to your | ||
| 881 | bblayers.conf file in order for it to be subsequently seen and | ||
| 882 | modified by the yocto-kernel tool. Instructions for doing this | ||
| 883 | can be found in the README file generated in the layer's top-level | ||
| 884 | directory. | ||
| 885 | |||
| 886 | For example, assuming your poky repo is at /path/to/poky, your new | ||
| 887 | layer is at /path/to/poky/meta-mylayer, and your build directory | ||
| 888 | is /path/to/build: | ||
| 889 | |||
| 890 | $ gedit /path/to/build/conf/bblayers.conf | ||
| 891 | |||
| 892 | BBLAYERS ?= " \\ | ||
| 893 | /path/to/poky/meta \\ | ||
| 894 | /path/to/poky/meta-yocto \\ | ||
| 895 | /path/to/poky/meta-mylayer \\ | ||
| 896 | " | ||
| 897 | """ | ||
| 898 | |||
| 899 | yocto_layer_list_usage = """ | ||
| 900 | |||
| 901 | usage: yocto-layer list properties | ||
| 902 | [-o <JSON PROPERTY FILE> | --outfile <JSON PROPERTY_FILE>] | ||
| 903 | yocto-layer list property <xxx> | ||
| 904 | [-o <JSON PROPERTY FILE> | --outfile <JSON PROPERTY_FILE>] | ||
| 905 | |||
| 906 | This command enumerates the complete set of possible values for a | ||
| 907 | specified option or property needed by the layer creation process. | ||
| 908 | |||
| 909 | The first form enumerates all the possible properties that exist and | ||
| 910 | must have values specified for them in the 'yocto-layer create' | ||
| 911 | command. | ||
| 912 | |||
| 913 | The second form enumerates all the possible values that exist and can | ||
| 914 | be specified for any of the enumerable properties in the 'yocto-layer | ||
| 915 | create' command. | ||
| 916 | |||
| 917 | See 'yocto-layer help list' for more details. | ||
| 918 | """ | ||
| 919 | |||
| 920 | yocto_layer_list_help = """ | ||
| 921 | |||
| 922 | NAME | ||
| 923 | yocto-layer list - List available values for layer input options and properties | ||
| 924 | |||
| 925 | SYNOPSIS | ||
| 926 | yocto-layer list properties | ||
| 927 | [--o <JSON PROPERTY FILE> | -outfile <JSON PROPERTY_FILE>] | ||
| 928 | yocto-layer list property <xxx> | ||
| 929 | [--o <JSON PROPERTY FILE> | -outfile <JSON PROPERTY_FILE>] | ||
| 930 | |||
| 931 | DESCRIPTION | ||
| 932 | This command enumerates the complete set of possible values for a | ||
| 933 | specified option or property needed by the layer creation process. | ||
| 934 | |||
| 935 | The first form enumerates all the possible properties that exist | ||
| 936 | and must have values specified for them in the 'yocto-layer | ||
| 937 | create' command. This command is mainly meant to aid the | ||
| 938 | development of user interface alternatives to the default | ||
| 939 | text-based prompting interface. If the -o option is specified, | ||
| 940 | the list of properties, in addition to being displayed, will be | ||
| 941 | written to the specified file as a JSON object. In this case, the | ||
| 942 | object will consist of the set of name:value pairs corresponding | ||
| 943 | to the (possibly nested) dictionary of properties defined by the | ||
| 944 | input statements used by the BSP. Some example output for the | ||
| 945 | 'list properties' command: | ||
| 946 | |||
| 947 | $ yocto-layer list properties | ||
| 948 | "example_bbappend_name" : { | ||
| 949 | "default" : example | ||
| 950 | "msg" : Please enter the name you'd like to use for your bbappend file: | ||
| 951 | "type" : edit | ||
| 952 | "prio" : 20 | ||
| 953 | "filename" : /home/trz/yocto/yocto-layer-dev/scripts/lib/bsp/substrate/target/arch/layer/layer-questions.noinstall | ||
| 954 | } | ||
| 955 | "create_example_recipe" : { | ||
| 956 | "default" : n | ||
| 957 | "msg" : Would you like to have an example recipe created? (y/n) | ||
| 958 | "type" : boolean | ||
| 959 | "prio" : 20 | ||
| 960 | "filename" : /home/trz/yocto/yocto-layer-dev/scripts/lib/bsp/substrate/target/arch/layer/layer-questions.noinstall | ||
| 961 | } | ||
| 962 | "example_recipe_name" : { | ||
| 963 | "default" : example | ||
| 964 | "msg" : Please enter the name you'd like to use for your example recipe: | ||
| 965 | "type" : edit | ||
| 966 | "prio" : 20 | ||
| 967 | "filename" : /home/trz/yocto/yocto-layer-dev/scripts/lib/bsp/substrate/target/arch/layer/layer-questions.noinstall | ||
| 968 | } | ||
| 969 | "layer_priority" : { | ||
| 970 | "default" : 6 | ||
| 971 | "msg" : Please enter the layer priority you'd like to use for the layer: | ||
| 972 | "type" : edit | ||
| 973 | "prio" : 20 | ||
| 974 | "filename" : /home/trz/yocto/yocto-layer-dev/scripts/lib/bsp/substrate/target/arch/layer/layer-questions.noinstall | ||
| 975 | } | ||
| 976 | "create_example_bbappend" : { | ||
| 977 | "default" : n | ||
| 978 | "msg" : Would you like to have an example bbappend file created? (y/n) | ||
| 979 | "type" : boolean | ||
| 980 | "prio" : 20 | ||
| 981 | "filename" : /home/trz/yocto/yocto-layer-dev/scripts/lib/bsp/substrate/target/arch/layer/layer-questions.noinstall | ||
| 982 | } | ||
| 983 | "example_bbappend_version" : { | ||
| 984 | "default" : 0.1 | ||
| 985 | "msg" : Please enter the version number you'd like to use for your bbappend file (this should match the recipe you're appending to): | ||
| 986 | "type" : edit | ||
| 987 | "prio" : 20 | ||
| 988 | "filename" : /home/trz/yocto/yocto-layer-dev/scripts/lib/bsp/substrate/target/arch/layer/layer-questions.noinstall | ||
| 989 | } | ||
| 990 | |||
| 991 | Each entry in the output consists of the name of the input element | ||
| 992 | e.g. "layer_priority", followed by the properties defined for that | ||
| 993 | element enclosed in braces. This information should provide | ||
| 994 | sufficient information to create a complete user interface. Two | ||
| 995 | features of the scheme provide for conditional input. First, if a | ||
| 996 | Python "if" statement appears in place of an input element name, | ||
| 997 | the set of enclosed input elements apply and should be presented | ||
| 998 | to the user only if the 'if' statement evaluates to true. The | ||
| 999 | test in the if statement will always reference another input | ||
| 1000 | element in the list, which means that the element being tested | ||
| 1001 | should be presented to the user before the elements enclosed by | ||
| 1002 | the if block. Secondly, in a similar way, some elements contain | ||
| 1003 | "depends-on" and depends-on-val" tags, which mean that the | ||
| 1004 | affected input element should only be presented to the user if the | ||
| 1005 | element it depends on has already been presented to the user and | ||
| 1006 | the user has selected the specified value for that element. | ||
| 1007 | |||
| 1008 | The second form enumerates all the possible values that exist and | ||
| 1009 | can be specified for any of the enumerable properties in the | ||
| 1010 | 'yocto-layer create' command. If the -o option is specified, the | ||
| 1011 | list of values for the given property, in addition to being | ||
| 1012 | displayed, will be written to the specified file as a JSON object. | ||
| 1013 | In this case, the object will consist of the set of name:value | ||
| 1014 | pairs corresponding to the array of property values associated | ||
| 1015 | with the property. | ||
| 1016 | |||
| 1017 | $ yocto-layer list property layer_priority | ||
| 1018 | [no output - layer_priority is a text field that has no enumerable values] | ||
| 1019 | |||
| 1020 | The second form as well is meant mainly for developers of | ||
| 1021 | alternative interfaces - it allows the developer to fetch the | ||
| 1022 | possible values for a given input element on-demand. This | ||
| 1023 | on-demand capability is especially valuable for elements that | ||
| 1024 | require relatively expensive remote operations to fulfill, such as | ||
| 1025 | the example that returns the set of branches available in a remote | ||
| 1026 | git tree above. | ||
| 1027 | |||
| 1028 | """ | ||
| 1029 | |||
| 1030 | ## | ||
| 1031 | # test code | ||
| 1032 | ## | ||
| 1033 | |||
| 1034 | test_bsp_properties = { | ||
| 1035 | 'smp': 'yes', | ||
| 1036 | 'touchscreen': 'yes', | ||
| 1037 | 'keyboard': 'no', | ||
| 1038 | 'xserver': 'yes', | ||
| 1039 | 'xserver_choice': 'xserver-i915', | ||
| 1040 | 'features': ['goodfeature', 'greatfeature'], | ||
| 1041 | 'tunefile': 'tune-quark', | ||
| 1042 | } | ||
| 1043 | |||
diff --git a/scripts/lib/bsp/kernel.py b/scripts/lib/bsp/kernel.py new file mode 100644 index 0000000000..ba68b60fcb --- /dev/null +++ b/scripts/lib/bsp/kernel.py | |||
| @@ -0,0 +1,1071 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2012, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This module implements the kernel-related functions used by | ||
| 22 | # 'yocto-kernel' to manage kernel config items and patches for Yocto | ||
| 23 | # BSPs. | ||
| 24 | # | ||
| 25 | # AUTHORS | ||
| 26 | # Tom Zanussi <tom.zanussi (at] intel.com> | ||
| 27 | # | ||
| 28 | |||
| 29 | import sys | ||
| 30 | import os | ||
| 31 | import shutil | ||
| 32 | from tags import * | ||
| 33 | import glob | ||
| 34 | import subprocess | ||
| 35 | from engine import create_context | ||
| 36 | |||
| 37 | |||
| 38 | def find_bblayers(): | ||
| 39 | """ | ||
| 40 | Find and return a sanitized list of the layers found in BBLAYERS. | ||
| 41 | """ | ||
| 42 | try: | ||
| 43 | builddir = os.environ["BUILDDIR"] | ||
| 44 | except KeyError: | ||
| 45 | print "BUILDDIR not found, exiting. (Did you forget to source oe-init-build-env?)" | ||
| 46 | sys.exit(1) | ||
| 47 | bblayers_conf = os.path.join(builddir, "conf/bblayers.conf") | ||
| 48 | |||
| 49 | layers = [] | ||
| 50 | |||
| 51 | bitbake_env_cmd = "bitbake -e" | ||
| 52 | bitbake_env_lines = subprocess.Popen(bitbake_env_cmd, shell=True, | ||
| 53 | stdout=subprocess.PIPE).stdout.read() | ||
| 54 | |||
| 55 | if not bitbake_env_lines: | ||
| 56 | print "Couldn't get '%s' output, exiting." % bitbake_env_cmd | ||
| 57 | sys.exit(1) | ||
| 58 | |||
| 59 | for line in bitbake_env_lines.split('\n'): | ||
| 60 | bblayers = get_line_val(line, "BBLAYERS") | ||
| 61 | if (bblayers): | ||
| 62 | break | ||
| 63 | |||
| 64 | if not bblayers: | ||
| 65 | print "Couldn't find BBLAYERS in %s output, exiting." % \ | ||
| 66 | bitbake_env_cmd | ||
| 67 | sys.exit(1) | ||
| 68 | |||
| 69 | raw_layers = bblayers.split() | ||
| 70 | |||
| 71 | for layer in raw_layers: | ||
| 72 | if layer == 'BBLAYERS' or '=' in layer: | ||
| 73 | continue | ||
| 74 | layers.append(layer) | ||
| 75 | |||
| 76 | return layers | ||
| 77 | |||
| 78 | |||
| 79 | def get_line_val(line, key): | ||
| 80 | """ | ||
| 81 | Extract the value from the VAR="val" string | ||
| 82 | """ | ||
| 83 | if line.startswith(key + "="): | ||
| 84 | stripped_line = line.split('=')[1] | ||
| 85 | stripped_line = stripped_line.replace('\"', '') | ||
| 86 | return stripped_line | ||
| 87 | return None | ||
| 88 | |||
| 89 | |||
| 90 | def find_meta_layer(): | ||
| 91 | """ | ||
| 92 | Find and return the meta layer in BBLAYERS. | ||
| 93 | """ | ||
| 94 | layers = find_bblayers() | ||
| 95 | |||
| 96 | for layer in layers: | ||
| 97 | if layer.endswith("meta"): | ||
| 98 | return layer | ||
| 99 | |||
| 100 | return None | ||
| 101 | |||
| 102 | |||
| 103 | def find_bsp_layer(machine): | ||
| 104 | """ | ||
| 105 | Find and return a machine's BSP layer in BBLAYERS. | ||
| 106 | """ | ||
| 107 | layers = find_bblayers() | ||
| 108 | |||
| 109 | for layer in layers: | ||
| 110 | if layer.endswith(machine): | ||
| 111 | return layer | ||
| 112 | |||
| 113 | print "Unable to find the BSP layer for machine %s." % machine | ||
| 114 | print "Please make sure it is listed in bblayers.conf" | ||
| 115 | sys.exit(1) | ||
| 116 | |||
| 117 | |||
| 118 | def gen_choices_str(choices): | ||
| 119 | """ | ||
| 120 | Generate a numbered list of choices from a list of choices for | ||
| 121 | display to the user. | ||
| 122 | """ | ||
| 123 | choices_str = "" | ||
| 124 | |||
| 125 | for i, choice in enumerate(choices): | ||
| 126 | choices_str += "\t" + str(i + 1) + ") " + choice + "\n" | ||
| 127 | |||
| 128 | return choices_str | ||
| 129 | |||
| 130 | |||
| 131 | def open_user_file(scripts_path, machine, userfile, mode): | ||
| 132 | """ | ||
| 133 | Find one of the user files (user-config.cfg, user-patches.scc) | ||
| 134 | associated with the machine (could be in files/, | ||
| 135 | linux-yocto-custom/, etc). Returns the open file if found, None | ||
| 136 | otherwise. | ||
| 137 | |||
| 138 | The caller is responsible for closing the file returned. | ||
| 139 | """ | ||
| 140 | layer = find_bsp_layer(machine) | ||
| 141 | linuxdir = os.path.join(layer, "recipes-kernel/linux") | ||
| 142 | linuxdir_list = os.listdir(linuxdir) | ||
| 143 | for fileobj in linuxdir_list: | ||
| 144 | fileobj_path = os.path.join(linuxdir, fileobj) | ||
| 145 | if os.path.isdir(fileobj_path): | ||
| 146 | userfile_name = os.path.join(fileobj_path, userfile) | ||
| 147 | try: | ||
| 148 | f = open(userfile_name, mode) | ||
| 149 | return f | ||
| 150 | except IOError: | ||
| 151 | continue | ||
| 152 | return None | ||
| 153 | |||
| 154 | |||
| 155 | def read_config_items(scripts_path, machine): | ||
| 156 | """ | ||
| 157 | Find and return a list of config items (CONFIG_XXX) in a machine's | ||
| 158 | user-defined config fragment [${machine}-user-config.cfg]. | ||
| 159 | """ | ||
| 160 | config_items = [] | ||
| 161 | |||
| 162 | f = open_user_file(scripts_path, machine, machine+"-user-config.cfg", "r") | ||
| 163 | lines = f.readlines() | ||
| 164 | for line in lines: | ||
| 165 | s = line.strip() | ||
| 166 | if s and not s.startswith("#"): | ||
| 167 | config_items.append(s) | ||
| 168 | f.close() | ||
| 169 | |||
| 170 | return config_items | ||
| 171 | |||
| 172 | |||
| 173 | def write_config_items(scripts_path, machine, config_items): | ||
| 174 | """ | ||
| 175 | Write (replace) the list of config items (CONFIG_XXX) in a | ||
| 176 | machine's user-defined config fragment [${machine}=user-config.cfg]. | ||
| 177 | """ | ||
| 178 | f = open_user_file(scripts_path, machine, machine+"-user-config.cfg", "w") | ||
| 179 | for item in config_items: | ||
| 180 | f.write(item + "\n") | ||
| 181 | f.close() | ||
| 182 | |||
| 183 | kernel_contents_changed(scripts_path, machine) | ||
| 184 | |||
| 185 | |||
| 186 | def yocto_kernel_config_list(scripts_path, machine): | ||
| 187 | """ | ||
| 188 | Display the list of config items (CONFIG_XXX) in a machine's | ||
| 189 | user-defined config fragment [${machine}-user-config.cfg]. | ||
| 190 | """ | ||
| 191 | config_items = read_config_items(scripts_path, machine) | ||
| 192 | |||
| 193 | print "The current set of machine-specific kernel config items for %s is:" % machine | ||
| 194 | print gen_choices_str(config_items) | ||
| 195 | |||
| 196 | |||
| 197 | def yocto_kernel_config_rm(scripts_path, machine): | ||
| 198 | """ | ||
| 199 | Display the list of config items (CONFIG_XXX) in a machine's | ||
| 200 | user-defined config fragment [${machine}-user-config.cfg], prompt the user | ||
| 201 | for one or more to remove, and remove them. | ||
| 202 | """ | ||
| 203 | config_items = read_config_items(scripts_path, machine) | ||
| 204 | |||
| 205 | print "Specify the kernel config items to remove:" | ||
| 206 | input = raw_input(gen_choices_str(config_items)) | ||
| 207 | rm_choices = input.split() | ||
| 208 | rm_choices.sort() | ||
| 209 | |||
| 210 | removed = [] | ||
| 211 | |||
| 212 | for choice in reversed(rm_choices): | ||
| 213 | try: | ||
| 214 | idx = int(choice) - 1 | ||
| 215 | except ValueError: | ||
| 216 | print "Invalid choice (%s), exiting" % choice | ||
| 217 | sys.exit(1) | ||
| 218 | if idx < 0 or idx >= len(config_items): | ||
| 219 | print "Invalid choice (%d), exiting" % (idx + 1) | ||
| 220 | sys.exit(1) | ||
| 221 | removed.append(config_items.pop(idx)) | ||
| 222 | |||
| 223 | write_config_items(scripts_path, machine, config_items) | ||
| 224 | |||
| 225 | print "Removed items:" | ||
| 226 | for r in removed: | ||
| 227 | print "\t%s" % r | ||
| 228 | |||
| 229 | |||
| 230 | def yocto_kernel_config_add(scripts_path, machine, config_items): | ||
| 231 | """ | ||
| 232 | Add one or more config items (CONFIG_XXX) to a machine's | ||
| 233 | user-defined config fragment [${machine}-user-config.cfg]. | ||
| 234 | """ | ||
| 235 | new_items = [] | ||
| 236 | dup_items = [] | ||
| 237 | |||
| 238 | cur_items = read_config_items(scripts_path, machine) | ||
| 239 | |||
| 240 | for item in config_items: | ||
| 241 | if not item.startswith("CONFIG") or (not "=y" in item and not "=m" in item): | ||
| 242 | print "Invalid config item (%s), exiting" % item | ||
| 243 | sys.exit(1) | ||
| 244 | if item not in cur_items and item not in new_items: | ||
| 245 | new_items.append(item) | ||
| 246 | else: | ||
| 247 | dup_items.append(item) | ||
| 248 | |||
| 249 | if len(new_items) > 0: | ||
| 250 | cur_items.extend(new_items) | ||
| 251 | write_config_items(scripts_path, machine, cur_items) | ||
| 252 | print "Added item%s:" % ("" if len(new_items)==1 else "s") | ||
| 253 | for n in new_items: | ||
| 254 | print "\t%s" % n | ||
| 255 | |||
| 256 | if len(dup_items) > 0: | ||
| 257 | output="The following item%s already exist%s in the current configuration, ignoring %s:" % \ | ||
| 258 | (("","s", "it") if len(dup_items)==1 else ("s", "", "them" )) | ||
| 259 | print output | ||
| 260 | for n in dup_items: | ||
| 261 | print "\t%s" % n | ||
| 262 | |||
| 263 | def find_current_kernel(bsp_layer, machine): | ||
| 264 | """ | ||
| 265 | Determine the kernel and version currently being used in the BSP. | ||
| 266 | """ | ||
| 267 | machine_conf = os.path.join(bsp_layer, "conf/machine/" + machine + ".conf") | ||
| 268 | |||
| 269 | preferred_kernel = preferred_kernel_version = preferred_version_varname = None | ||
| 270 | |||
| 271 | f = open(machine_conf, "r") | ||
| 272 | lines = f.readlines() | ||
| 273 | for line in lines: | ||
| 274 | if line.strip().startswith("PREFERRED_PROVIDER_virtual/kernel"): | ||
| 275 | preferred_kernel = line.split()[-1] | ||
| 276 | preferred_kernel = preferred_kernel.replace('\"','') | ||
| 277 | preferred_version_varname = "PREFERRED_VERSION_" + preferred_kernel | ||
| 278 | if preferred_version_varname and line.strip().startswith(preferred_version_varname): | ||
| 279 | preferred_kernel_version = line.split()[-1] | ||
| 280 | preferred_kernel_version = preferred_kernel_version.replace('\"','') | ||
| 281 | preferred_kernel_version = preferred_kernel_version.replace('%','') | ||
| 282 | |||
| 283 | if preferred_kernel and preferred_kernel_version: | ||
| 284 | return preferred_kernel + "_" + preferred_kernel_version | ||
| 285 | elif preferred_kernel: | ||
| 286 | return preferred_kernel | ||
| 287 | |||
| 288 | |||
| 289 | def find_filesdir(scripts_path, machine): | ||
| 290 | """ | ||
| 291 | Find the name of the 'files' dir associated with the machine | ||
| 292 | (could be in files/, linux-yocto-custom/, etc). Returns the name | ||
| 293 | of the files dir if found, None otherwise. | ||
| 294 | """ | ||
| 295 | layer = find_bsp_layer(machine) | ||
| 296 | filesdir = None | ||
| 297 | linuxdir = os.path.join(layer, "recipes-kernel/linux") | ||
| 298 | linuxdir_list = os.listdir(linuxdir) | ||
| 299 | for fileobj in linuxdir_list: | ||
| 300 | fileobj_path = os.path.join(linuxdir, fileobj) | ||
| 301 | if os.path.isdir(fileobj_path): | ||
| 302 | # this could be files/ or linux-yocto-custom/, we have no way of distinguishing | ||
| 303 | # so we take the first (and normally only) dir we find as the 'filesdir' | ||
| 304 | filesdir = fileobj_path | ||
| 305 | |||
| 306 | return filesdir | ||
| 307 | |||
| 308 | |||
| 309 | def read_patch_items(scripts_path, machine): | ||
| 310 | """ | ||
| 311 | Find and return a list of patch items in a machine's user-defined | ||
| 312 | patch list [${machine}-user-patches.scc]. | ||
| 313 | """ | ||
| 314 | patch_items = [] | ||
| 315 | |||
| 316 | f = open_user_file(scripts_path, machine, machine+"-user-patches.scc", "r") | ||
| 317 | lines = f.readlines() | ||
| 318 | for line in lines: | ||
| 319 | s = line.strip() | ||
| 320 | if s and not s.startswith("#"): | ||
| 321 | fields = s.split() | ||
| 322 | if not fields[0] == "patch": | ||
| 323 | continue | ||
| 324 | patch_items.append(fields[1]) | ||
| 325 | f.close() | ||
| 326 | |||
| 327 | return patch_items | ||
| 328 | |||
| 329 | |||
| 330 | def write_patch_items(scripts_path, machine, patch_items): | ||
| 331 | """ | ||
| 332 | Write (replace) the list of patches in a machine's user-defined | ||
| 333 | patch list [${machine}-user-patches.scc]. | ||
| 334 | """ | ||
| 335 | f = open_user_file(scripts_path, machine, machine+"-user-patches.scc", "w") | ||
| 336 | for item in patch_items: | ||
| 337 | f.write("patch " + item + "\n") | ||
| 338 | f.close() | ||
| 339 | |||
| 340 | kernel_contents_changed(scripts_path, machine) | ||
| 341 | |||
| 342 | |||
| 343 | def yocto_kernel_patch_list(scripts_path, machine): | ||
| 344 | """ | ||
| 345 | Display the list of patches in a machine's user-defined patch list | ||
| 346 | [${machine}-user-patches.scc]. | ||
| 347 | """ | ||
| 348 | patches = read_patch_items(scripts_path, machine) | ||
| 349 | |||
| 350 | print "The current set of machine-specific patches for %s is:" % machine | ||
| 351 | print gen_choices_str(patches) | ||
| 352 | |||
| 353 | |||
| 354 | def yocto_kernel_patch_rm(scripts_path, machine): | ||
| 355 | """ | ||
| 356 | Remove one or more patches from a machine's user-defined patch | ||
| 357 | list [${machine}-user-patches.scc]. | ||
| 358 | """ | ||
| 359 | patches = read_patch_items(scripts_path, machine) | ||
| 360 | |||
| 361 | print "Specify the patches to remove:" | ||
| 362 | input = raw_input(gen_choices_str(patches)) | ||
| 363 | rm_choices = input.split() | ||
| 364 | rm_choices.sort() | ||
| 365 | |||
| 366 | removed = [] | ||
| 367 | |||
| 368 | filesdir = find_filesdir(scripts_path, machine) | ||
| 369 | if not filesdir: | ||
| 370 | print "Couldn't rm patch(es) since we couldn't find a 'files' dir" | ||
| 371 | sys.exit(1) | ||
| 372 | |||
| 373 | for choice in reversed(rm_choices): | ||
| 374 | try: | ||
| 375 | idx = int(choice) - 1 | ||
| 376 | except ValueError: | ||
| 377 | print "Invalid choice (%s), exiting" % choice | ||
| 378 | sys.exit(1) | ||
| 379 | if idx < 0 or idx >= len(patches): | ||
| 380 | print "Invalid choice (%d), exiting" % (idx + 1) | ||
| 381 | sys.exit(1) | ||
| 382 | filesdir_patch = os.path.join(filesdir, patches[idx]) | ||
| 383 | if os.path.isfile(filesdir_patch): | ||
| 384 | os.remove(filesdir_patch) | ||
| 385 | removed.append(patches[idx]) | ||
| 386 | patches.pop(idx) | ||
| 387 | |||
| 388 | write_patch_items(scripts_path, machine, patches) | ||
| 389 | |||
| 390 | print "Removed patches:" | ||
| 391 | for r in removed: | ||
| 392 | print "\t%s" % r | ||
| 393 | |||
| 394 | |||
| 395 | def yocto_kernel_patch_add(scripts_path, machine, patches): | ||
| 396 | """ | ||
| 397 | Add one or more patches to a machine's user-defined patch list | ||
| 398 | [${machine}-user-patches.scc]. | ||
| 399 | """ | ||
| 400 | existing_patches = read_patch_items(scripts_path, machine) | ||
| 401 | |||
| 402 | for patch in patches: | ||
| 403 | if os.path.basename(patch) in existing_patches: | ||
| 404 | print "Couldn't add patch (%s) since it's already been added" % os.path.basename(patch) | ||
| 405 | sys.exit(1) | ||
| 406 | |||
| 407 | filesdir = find_filesdir(scripts_path, machine) | ||
| 408 | if not filesdir: | ||
| 409 | print "Couldn't add patch (%s) since we couldn't find a 'files' dir to add it to" % os.path.basename(patch) | ||
| 410 | sys.exit(1) | ||
| 411 | |||
| 412 | new_patches = [] | ||
| 413 | |||
| 414 | for patch in patches: | ||
| 415 | if not os.path.isfile(patch): | ||
| 416 | print "Couldn't find patch (%s), exiting" % patch | ||
| 417 | sys.exit(1) | ||
| 418 | basename = os.path.basename(patch) | ||
| 419 | filesdir_patch = os.path.join(filesdir, basename) | ||
| 420 | shutil.copyfile(patch, filesdir_patch) | ||
| 421 | new_patches.append(basename) | ||
| 422 | |||
| 423 | cur_items = read_patch_items(scripts_path, machine) | ||
| 424 | cur_items.extend(new_patches) | ||
| 425 | write_patch_items(scripts_path, machine, cur_items) | ||
| 426 | |||
| 427 | print "Added patches:" | ||
| 428 | for n in new_patches: | ||
| 429 | print "\t%s" % n | ||
| 430 | |||
| 431 | |||
| 432 | def inc_pr(line): | ||
| 433 | """ | ||
| 434 | Add 1 to the PR value in the given bbappend PR line. For the PR | ||
| 435 | lines in kernel .bbappends after modifications. Handles PRs of | ||
| 436 | the form PR := "${PR}.1" as well as PR = "r0". | ||
| 437 | """ | ||
| 438 | idx = line.find("\"") | ||
| 439 | |||
| 440 | pr_str = line[idx:] | ||
| 441 | pr_str = pr_str.replace('\"','') | ||
| 442 | fields = pr_str.split('.') | ||
| 443 | if len(fields) > 1: | ||
| 444 | fields[1] = str(int(fields[1]) + 1) | ||
| 445 | pr_str = "\"" + '.'.join(fields) + "\"\n" | ||
| 446 | else: | ||
| 447 | pr_val = pr_str[1:] | ||
| 448 | pr_str = "\"" + "r" + str(int(pr_val) + 1) + "\"\n" | ||
| 449 | idx2 = line.find("\"", idx + 1) | ||
| 450 | line = line[:idx] + pr_str | ||
| 451 | |||
| 452 | return line | ||
| 453 | |||
| 454 | |||
| 455 | def kernel_contents_changed(scripts_path, machine): | ||
| 456 | """ | ||
| 457 | Do what we need to do to notify the system that the kernel | ||
| 458 | recipe's contents have changed. | ||
| 459 | """ | ||
| 460 | layer = find_bsp_layer(machine) | ||
| 461 | |||
| 462 | kernel = find_current_kernel(layer, machine) | ||
| 463 | if not kernel: | ||
| 464 | print "Couldn't determine the kernel for this BSP, exiting." | ||
| 465 | sys.exit(1) | ||
| 466 | |||
| 467 | kernel_bbfile = os.path.join(layer, "recipes-kernel/linux/" + kernel + ".bbappend") | ||
| 468 | if not os.path.isfile(kernel_bbfile): | ||
| 469 | kernel_bbfile = os.path.join(layer, "recipes-kernel/linux/" + kernel + ".bb") | ||
| 470 | if not os.path.isfile(kernel_bbfile): | ||
| 471 | return | ||
| 472 | kernel_bbfile_prev = kernel_bbfile + ".prev" | ||
| 473 | shutil.copyfile(kernel_bbfile, kernel_bbfile_prev) | ||
| 474 | |||
| 475 | ifile = open(kernel_bbfile_prev, "r") | ||
| 476 | ofile = open(kernel_bbfile, "w") | ||
| 477 | ifile_lines = ifile.readlines() | ||
| 478 | for ifile_line in ifile_lines: | ||
| 479 | if ifile_line.strip().startswith("PR"): | ||
| 480 | ifile_line = inc_pr(ifile_line) | ||
| 481 | ofile.write(ifile_line) | ||
| 482 | ofile.close() | ||
| 483 | ifile.close() | ||
| 484 | |||
| 485 | |||
| 486 | def kernels(context): | ||
| 487 | """ | ||
| 488 | Return the list of available kernels in the BSP i.e. corresponding | ||
| 489 | to the kernel .bbappends found in the layer. | ||
| 490 | """ | ||
| 491 | archdir = os.path.join(context["scripts_path"], "lib/bsp/substrate/target/arch/" + context["arch"]) | ||
| 492 | kerndir = os.path.join(archdir, "recipes-kernel/linux") | ||
| 493 | bbglob = os.path.join(kerndir, "*.bbappend") | ||
| 494 | |||
| 495 | bbappends = glob.glob(bbglob) | ||
| 496 | |||
| 497 | kernels = [] | ||
| 498 | |||
| 499 | for kernel in bbappends: | ||
| 500 | filename = os.path.splitext(os.path.basename(kernel))[0] | ||
| 501 | idx = filename.find(CLOSE_TAG) | ||
| 502 | if idx != -1: | ||
| 503 | filename = filename[idx + len(CLOSE_TAG):].strip() | ||
| 504 | kernels.append(filename) | ||
| 505 | |||
| 506 | kernels.append("custom") | ||
| 507 | |||
| 508 | return kernels | ||
| 509 | |||
| 510 | |||
| 511 | def extract_giturl(file): | ||
| 512 | """ | ||
| 513 | Extract the git url of the kernel repo from the kernel recipe's | ||
| 514 | SRC_URI. | ||
| 515 | """ | ||
| 516 | url = None | ||
| 517 | f = open(file, "r") | ||
| 518 | lines = f.readlines() | ||
| 519 | for line in lines: | ||
| 520 | line = line.strip() | ||
| 521 | if line.startswith("SRC_URI"): | ||
| 522 | line = line[len("SRC_URI"):].strip() | ||
| 523 | if line.startswith("="): | ||
| 524 | line = line[1:].strip() | ||
| 525 | if line.startswith("\""): | ||
| 526 | line = line[1:].strip() | ||
| 527 | prot = "git" | ||
| 528 | for s in line.split(";"): | ||
| 529 | if s.startswith("git://"): | ||
| 530 | url = s | ||
| 531 | if s.startswith("protocol="): | ||
| 532 | prot = s.split("=")[1] | ||
| 533 | if url: | ||
| 534 | url = prot + url[3:] | ||
| 535 | return url | ||
| 536 | |||
| 537 | |||
| 538 | def find_giturl(context): | ||
| 539 | """ | ||
| 540 | Find the git url of the kernel repo from the kernel recipe's | ||
| 541 | SRC_URI. | ||
| 542 | """ | ||
| 543 | name = context["name"] | ||
| 544 | filebase = context["filename"] | ||
| 545 | scripts_path = context["scripts_path"] | ||
| 546 | |||
| 547 | meta_layer = find_meta_layer() | ||
| 548 | |||
| 549 | kerndir = os.path.join(meta_layer, "recipes-kernel/linux") | ||
| 550 | bbglob = os.path.join(kerndir, "*.bb") | ||
| 551 | bbs = glob.glob(bbglob) | ||
| 552 | for kernel in bbs: | ||
| 553 | filename = os.path.splitext(os.path.basename(kernel))[0] | ||
| 554 | if filename in filebase: | ||
| 555 | giturl = extract_giturl(kernel) | ||
| 556 | return giturl | ||
| 557 | |||
| 558 | return None | ||
| 559 | |||
| 560 | |||
| 561 | def read_features(scripts_path, machine): | ||
| 562 | """ | ||
| 563 | Find and return a list of features in a machine's user-defined | ||
| 564 | features fragment [${machine}-user-features.scc]. | ||
| 565 | """ | ||
| 566 | features = [] | ||
| 567 | |||
| 568 | f = open_user_file(scripts_path, machine, machine+"-user-features.scc", "r") | ||
| 569 | lines = f.readlines() | ||
| 570 | for line in lines: | ||
| 571 | s = line.strip() | ||
| 572 | if s and not s.startswith("#"): | ||
| 573 | feature_include = s.split() | ||
| 574 | features.append(feature_include[1].strip()) | ||
| 575 | f.close() | ||
| 576 | |||
| 577 | return features | ||
| 578 | |||
| 579 | |||
| 580 | def write_features(scripts_path, machine, features): | ||
| 581 | """ | ||
| 582 | Write (replace) the list of feature items in a | ||
| 583 | machine's user-defined features fragment [${machine}=user-features.cfg]. | ||
| 584 | """ | ||
| 585 | f = open_user_file(scripts_path, machine, machine+"-user-features.scc", "w") | ||
| 586 | for item in features: | ||
| 587 | f.write("include " + item + "\n") | ||
| 588 | f.close() | ||
| 589 | |||
| 590 | kernel_contents_changed(scripts_path, machine) | ||
| 591 | |||
| 592 | |||
| 593 | def yocto_kernel_feature_list(scripts_path, machine): | ||
| 594 | """ | ||
| 595 | Display the list of features used in a machine's user-defined | ||
| 596 | features fragment [${machine}-user-features.scc]. | ||
| 597 | """ | ||
| 598 | features = read_features(scripts_path, machine) | ||
| 599 | |||
| 600 | print "The current set of machine-specific features for %s is:" % machine | ||
| 601 | print gen_choices_str(features) | ||
| 602 | |||
| 603 | |||
| 604 | def yocto_kernel_feature_rm(scripts_path, machine): | ||
| 605 | """ | ||
| 606 | Display the list of features used in a machine's user-defined | ||
| 607 | features fragment [${machine}-user-features.scc], prompt the user | ||
| 608 | for one or more to remove, and remove them. | ||
| 609 | """ | ||
| 610 | features = read_features(scripts_path, machine) | ||
| 611 | |||
| 612 | print "Specify the features to remove:" | ||
| 613 | input = raw_input(gen_choices_str(features)) | ||
| 614 | rm_choices = input.split() | ||
| 615 | rm_choices.sort() | ||
| 616 | |||
| 617 | removed = [] | ||
| 618 | |||
| 619 | for choice in reversed(rm_choices): | ||
| 620 | try: | ||
| 621 | idx = int(choice) - 1 | ||
| 622 | except ValueError: | ||
| 623 | print "Invalid choice (%s), exiting" % choice | ||
| 624 | sys.exit(1) | ||
| 625 | if idx < 0 or idx >= len(features): | ||
| 626 | print "Invalid choice (%d), exiting" % (idx + 1) | ||
| 627 | sys.exit(1) | ||
| 628 | removed.append(features.pop(idx)) | ||
| 629 | |||
| 630 | write_features(scripts_path, machine, features) | ||
| 631 | |||
| 632 | print "Removed features:" | ||
| 633 | for r in removed: | ||
| 634 | print "\t%s" % r | ||
| 635 | |||
| 636 | |||
| 637 | def yocto_kernel_feature_add(scripts_path, machine, features): | ||
| 638 | """ | ||
| 639 | Add one or more features a machine's user-defined features | ||
| 640 | fragment [${machine}-user-features.scc]. | ||
| 641 | """ | ||
| 642 | new_items = [] | ||
| 643 | |||
| 644 | for item in features: | ||
| 645 | if not item.endswith(".scc"): | ||
| 646 | print "Invalid feature (%s), exiting" % item | ||
| 647 | sys.exit(1) | ||
| 648 | new_items.append(item) | ||
| 649 | |||
| 650 | cur_items = read_features(scripts_path, machine) | ||
| 651 | cur_items.extend(new_items) | ||
| 652 | |||
| 653 | write_features(scripts_path, machine, cur_items) | ||
| 654 | |||
| 655 | print "Added features:" | ||
| 656 | for n in new_items: | ||
| 657 | print "\t%s" % n | ||
| 658 | |||
| 659 | |||
| 660 | def find_feature_url(git_url): | ||
| 661 | """ | ||
| 662 | Find the url of the kern-features.rc kernel for the kernel repo | ||
| 663 | specified from the BSP's kernel recipe SRC_URI. | ||
| 664 | """ | ||
| 665 | feature_url = "" | ||
| 666 | if git_url.startswith("git://"): | ||
| 667 | git_url = git_url[len("git://"):].strip() | ||
| 668 | s = git_url.split("/") | ||
| 669 | if s[1].endswith(".git"): | ||
| 670 | s[1] = s[1][:len(s[1]) - len(".git")] | ||
| 671 | feature_url = "http://" + s[0] + "/cgit/cgit.cgi/" + s[1] + \ | ||
| 672 | "/plain/meta/cfg/kern-features.rc?h=meta" | ||
| 673 | |||
| 674 | return feature_url | ||
| 675 | |||
| 676 | |||
| 677 | def find_feature_desc(lines): | ||
| 678 | """ | ||
| 679 | Find the feature description and compatibility in the passed-in | ||
| 680 | set of lines. Returns a string string of the form 'desc | ||
| 681 | [compat]'. | ||
| 682 | """ | ||
| 683 | desc = "no description available" | ||
| 684 | compat = "unknown" | ||
| 685 | |||
| 686 | for line in lines: | ||
| 687 | idx = line.find("KFEATURE_DESCRIPTION") | ||
| 688 | if idx != -1: | ||
| 689 | desc = line[idx + len("KFEATURE_DESCRIPTION"):].strip() | ||
| 690 | if desc.startswith("\""): | ||
| 691 | desc = desc[1:] | ||
| 692 | if desc.endswith("\""): | ||
| 693 | desc = desc[:-1] | ||
| 694 | else: | ||
| 695 | idx = line.find("KFEATURE_COMPATIBILITY") | ||
| 696 | if idx != -1: | ||
| 697 | compat = line[idx + len("KFEATURE_COMPATIBILITY"):].strip() | ||
| 698 | |||
| 699 | return desc + " [" + compat + "]" | ||
| 700 | |||
| 701 | |||
| 702 | def print_feature_descs(layer, feature_dir): | ||
| 703 | """ | ||
| 704 | Print the feature descriptions for the features in feature_dir. | ||
| 705 | """ | ||
| 706 | kernel_files_features = os.path.join(layer, "recipes-kernel/linux/files/" + | ||
| 707 | feature_dir) | ||
| 708 | for root, dirs, files in os.walk(kernel_files_features): | ||
| 709 | for file in files: | ||
| 710 | if file.endswith("~") or file.endswith("#"): | ||
| 711 | continue | ||
| 712 | if file.endswith(".scc"): | ||
| 713 | fullpath = os.path.join(layer, "recipes-kernel/linux/files/" + | ||
| 714 | feature_dir + "/" + file) | ||
| 715 | f = open(fullpath) | ||
| 716 | feature_desc = find_feature_desc(f.readlines()) | ||
| 717 | print feature_dir + "/" + file + ": " + feature_desc | ||
| 718 | |||
| 719 | |||
| 720 | def yocto_kernel_available_features_list(scripts_path, machine): | ||
| 721 | """ | ||
| 722 | Display the list of all the kernel features available for use in | ||
| 723 | BSPs, as gathered from the set of feature sources. | ||
| 724 | """ | ||
| 725 | layer = find_bsp_layer(machine) | ||
| 726 | kernel = find_current_kernel(layer, machine) | ||
| 727 | if not kernel: | ||
| 728 | print "Couldn't determine the kernel for this BSP, exiting." | ||
| 729 | sys.exit(1) | ||
| 730 | |||
| 731 | context = create_context(machine, "arch", scripts_path) | ||
| 732 | context["name"] = "name" | ||
| 733 | context["filename"] = kernel | ||
| 734 | giturl = find_giturl(context) | ||
| 735 | feature_url = find_feature_url(giturl) | ||
| 736 | |||
| 737 | feature_cmd = "wget -q -O - " + feature_url | ||
| 738 | tmp = subprocess.Popen(feature_cmd, shell=True, stdout=subprocess.PIPE).stdout.read() | ||
| 739 | |||
| 740 | print "The current set of kernel features available to %s is:\n" % machine | ||
| 741 | |||
| 742 | if tmp: | ||
| 743 | tmpline = tmp.split("\n") | ||
| 744 | in_kernel_options = False | ||
| 745 | for line in tmpline: | ||
| 746 | if not "=" in line: | ||
| 747 | if in_kernel_options: | ||
| 748 | break | ||
| 749 | if "kernel-options" in line: | ||
| 750 | in_kernel_options = True | ||
| 751 | continue | ||
| 752 | if in_kernel_options: | ||
| 753 | feature_def = line.split("=") | ||
| 754 | feature_type = feature_def[0].strip() | ||
| 755 | feature = feature_def[1].strip() | ||
| 756 | desc = get_feature_desc(giturl, feature) | ||
| 757 | print "%s: %s" % (feature, desc) | ||
| 758 | |||
| 759 | print "[local]" | ||
| 760 | |||
| 761 | print_feature_descs(layer, "cfg") | ||
| 762 | print_feature_descs(layer, "features") | ||
| 763 | |||
| 764 | |||
| 765 | def find_feature_desc_url(git_url, feature): | ||
| 766 | """ | ||
| 767 | Find the url of the kernel feature in the kernel repo specified | ||
| 768 | from the BSP's kernel recipe SRC_URI. | ||
| 769 | """ | ||
| 770 | feature_desc_url = "" | ||
| 771 | if git_url.startswith("git://"): | ||
| 772 | git_url = git_url[len("git://"):].strip() | ||
| 773 | s = git_url.split("/") | ||
| 774 | if s[1].endswith(".git"): | ||
| 775 | s[1] = s[1][:len(s[1]) - len(".git")] | ||
| 776 | feature_desc_url = "http://" + s[0] + "/cgit/cgit.cgi/" + s[1] + \ | ||
| 777 | "/plain/meta/cfg/kernel-cache/" + feature + "?h=meta" | ||
| 778 | |||
| 779 | return feature_desc_url | ||
| 780 | |||
| 781 | |||
| 782 | def get_feature_desc(git_url, feature): | ||
| 783 | """ | ||
| 784 | Return a feature description of the form 'description [compatibility] | ||
| 785 | BSPs, as gathered from the set of feature sources. | ||
| 786 | """ | ||
| 787 | feature_desc_url = find_feature_desc_url(git_url, feature) | ||
| 788 | feature_desc_cmd = "wget -q -O - " + feature_desc_url | ||
| 789 | tmp = subprocess.Popen(feature_desc_cmd, shell=True, stdout=subprocess.PIPE).stdout.read() | ||
| 790 | |||
| 791 | return find_feature_desc(tmp.split("\n")) | ||
| 792 | |||
| 793 | |||
| 794 | def yocto_kernel_feature_describe(scripts_path, machine, feature): | ||
| 795 | """ | ||
| 796 | Display the description of a specific kernel feature available for | ||
| 797 | use in a BSP. | ||
| 798 | """ | ||
| 799 | layer = find_bsp_layer(machine) | ||
| 800 | |||
| 801 | kernel = find_current_kernel(layer, machine) | ||
| 802 | if not kernel: | ||
| 803 | print "Couldn't determine the kernel for this BSP, exiting." | ||
| 804 | sys.exit(1) | ||
| 805 | |||
| 806 | context = create_context(machine, "arch", scripts_path) | ||
| 807 | context["name"] = "name" | ||
| 808 | context["filename"] = kernel | ||
| 809 | giturl = find_giturl(context) | ||
| 810 | |||
| 811 | desc = get_feature_desc(giturl, feature) | ||
| 812 | |||
| 813 | print desc | ||
| 814 | |||
| 815 | |||
| 816 | def check_feature_name(feature_name): | ||
| 817 | """ | ||
| 818 | Sanity-check the feature name for create/destroy. Return False if not OK. | ||
| 819 | """ | ||
| 820 | if not feature_name.endswith(".scc"): | ||
| 821 | print "Invalid feature name (must end with .scc) [%s], exiting" % feature_name | ||
| 822 | return False | ||
| 823 | |||
| 824 | if "/" in feature_name: | ||
| 825 | print "Invalid feature name (don't specify directory) [%s], exiting" % feature_name | ||
| 826 | return False | ||
| 827 | |||
| 828 | return True | ||
| 829 | |||
| 830 | |||
| 831 | def check_create_input(feature_items): | ||
| 832 | """ | ||
| 833 | Sanity-check the create input. Return False if not OK. | ||
| 834 | """ | ||
| 835 | if not check_feature_name(feature_items[0]): | ||
| 836 | return False | ||
| 837 | |||
| 838 | if feature_items[1].endswith(".patch") or feature_items[1].startswith("CONFIG_"): | ||
| 839 | print "Missing description and/or compatibilty [%s], exiting" % feature_items[1] | ||
| 840 | return False | ||
| 841 | |||
| 842 | if feature_items[2].endswith(".patch") or feature_items[2].startswith("CONFIG_"): | ||
| 843 | print "Missing description and/or compatibility [%s], exiting" % feature_items[1] | ||
| 844 | return False | ||
| 845 | |||
| 846 | return True | ||
| 847 | |||
| 848 | |||
| 849 | def yocto_kernel_feature_create(scripts_path, machine, feature_items): | ||
| 850 | """ | ||
| 851 | Create a recipe-space kernel feature in a BSP. | ||
| 852 | """ | ||
| 853 | if not check_create_input(feature_items): | ||
| 854 | sys.exit(1) | ||
| 855 | |||
| 856 | feature = feature_items[0] | ||
| 857 | feature_basename = feature.split(".")[0] | ||
| 858 | feature_description = feature_items[1] | ||
| 859 | feature_compat = feature_items[2] | ||
| 860 | |||
| 861 | patches = [] | ||
| 862 | cfg_items = [] | ||
| 863 | |||
| 864 | for item in feature_items[3:]: | ||
| 865 | if item.endswith(".patch"): | ||
| 866 | patches.append(item) | ||
| 867 | elif item.startswith("CONFIG"): | ||
| 868 | if ("=y" in item or "=m" in item): | ||
| 869 | cfg_items.append(item) | ||
| 870 | else: | ||
| 871 | print "Invalid feature item (must be .patch or CONFIG_*) [%s], exiting" % item | ||
| 872 | sys.exit(1) | ||
| 873 | |||
| 874 | feature_dirname = "cfg" | ||
| 875 | if patches: | ||
| 876 | feature_dirname = "features" | ||
| 877 | |||
| 878 | filesdir = find_filesdir(scripts_path, machine) | ||
| 879 | if not filesdir: | ||
| 880 | print "Couldn't add feature (%s), no 'files' dir found" % feature | ||
| 881 | sys.exit(1) | ||
| 882 | |||
| 883 | featdir = os.path.join(filesdir, feature_dirname) | ||
| 884 | if not os.path.exists(featdir): | ||
| 885 | os.mkdir(featdir) | ||
| 886 | |||
| 887 | for patch in patches: | ||
| 888 | if not os.path.isfile(patch): | ||
| 889 | print "Couldn't find patch (%s), exiting" % patch | ||
| 890 | sys.exit(1) | ||
| 891 | basename = os.path.basename(patch) | ||
| 892 | featdir_patch = os.path.join(featdir, basename) | ||
| 893 | shutil.copyfile(patch, featdir_patch) | ||
| 894 | |||
| 895 | new_cfg_filename = os.path.join(featdir, feature_basename + ".cfg") | ||
| 896 | new_cfg_file = open(new_cfg_filename, "w") | ||
| 897 | for cfg_item in cfg_items: | ||
| 898 | new_cfg_file.write(cfg_item + "\n") | ||
| 899 | new_cfg_file.close() | ||
| 900 | |||
| 901 | new_feature_filename = os.path.join(featdir, feature_basename + ".scc") | ||
| 902 | new_feature_file = open(new_feature_filename, "w") | ||
| 903 | new_feature_file.write("define KFEATURE_DESCRIPTION \"" + feature_description + "\"\n") | ||
| 904 | new_feature_file.write("define KFEATURE_COMPATIBILITY " + feature_compat + "\n\n") | ||
| 905 | |||
| 906 | for patch in patches: | ||
| 907 | patch_dir, patch_file = os.path.split(patch) | ||
| 908 | new_feature_file.write("patch " + patch_file + "\n") | ||
| 909 | |||
| 910 | new_feature_file.write("kconf non-hardware " + feature_basename + ".cfg\n") | ||
| 911 | new_feature_file.close() | ||
| 912 | |||
| 913 | print "Added feature:" | ||
| 914 | print "\t%s" % feature_dirname + "/" + feature | ||
| 915 | |||
| 916 | |||
| 917 | def feature_in_use(scripts_path, machine, feature): | ||
| 918 | """ | ||
| 919 | Determine whether the specified feature is in use by the BSP. | ||
| 920 | Return True if so, False otherwise. | ||
| 921 | """ | ||
| 922 | features = read_features(scripts_path, machine) | ||
| 923 | for f in features: | ||
| 924 | if f == feature: | ||
| 925 | return True | ||
| 926 | return False | ||
| 927 | |||
| 928 | |||
| 929 | def feature_remove(scripts_path, machine, feature): | ||
| 930 | """ | ||
| 931 | Remove the specified feature from the available recipe-space | ||
| 932 | features defined for the BSP. | ||
| 933 | """ | ||
| 934 | features = read_features(scripts_path, machine) | ||
| 935 | new_features = [] | ||
| 936 | for f in features: | ||
| 937 | if f == feature: | ||
| 938 | continue | ||
| 939 | new_features.append(f) | ||
| 940 | write_features(scripts_path, machine, new_features) | ||
| 941 | |||
| 942 | |||
| 943 | def yocto_kernel_feature_destroy(scripts_path, machine, feature): | ||
| 944 | """ | ||
| 945 | Remove a recipe-space kernel feature from a BSP. | ||
| 946 | """ | ||
| 947 | if not check_feature_name(feature): | ||
| 948 | sys.exit(1) | ||
| 949 | |||
| 950 | if feature_in_use(scripts_path, machine, "features/" + feature) or \ | ||
| 951 | feature_in_use(scripts_path, machine, "cfg/" + feature): | ||
| 952 | print "Feature %s is in use (use 'feature rm' to un-use it first), exiting" % feature | ||
| 953 | sys.exit(1) | ||
| 954 | |||
| 955 | filesdir = find_filesdir(scripts_path, machine) | ||
| 956 | if not filesdir: | ||
| 957 | print "Couldn't destroy feature (%s), no 'files' dir found" % feature | ||
| 958 | sys.exit(1) | ||
| 959 | |||
| 960 | feature_dirname = "features" | ||
| 961 | featdir = os.path.join(filesdir, feature_dirname) | ||
| 962 | if not os.path.exists(featdir): | ||
| 963 | print "Couldn't find feature directory (%s)" % feature_dirname | ||
| 964 | sys.exit(1) | ||
| 965 | |||
| 966 | feature_fqn = os.path.join(featdir, feature) | ||
| 967 | if not os.path.exists(feature_fqn): | ||
| 968 | feature_dirname = "cfg" | ||
| 969 | featdir = os.path.join(filesdir, feature_dirname) | ||
| 970 | if not os.path.exists(featdir): | ||
| 971 | print "Couldn't find feature directory (%s)" % feature_dirname | ||
| 972 | sys.exit(1) | ||
| 973 | feature_fqn = os.path.join(featdir, feature_filename) | ||
| 974 | if not os.path.exists(feature_fqn): | ||
| 975 | print "Couldn't find feature (%s)" % feature | ||
| 976 | sys.exit(1) | ||
| 977 | |||
| 978 | f = open(feature_fqn, "r") | ||
| 979 | lines = f.readlines() | ||
| 980 | for line in lines: | ||
| 981 | s = line.strip() | ||
| 982 | if s.startswith("patch ") or s.startswith("kconf "): | ||
| 983 | split_line = s.split() | ||
| 984 | filename = os.path.join(featdir, split_line[-1]) | ||
| 985 | if os.path.exists(filename): | ||
| 986 | os.remove(filename) | ||
| 987 | f.close() | ||
| 988 | os.remove(feature_fqn) | ||
| 989 | |||
| 990 | feature_remove(scripts_path, machine, feature) | ||
| 991 | |||
| 992 | print "Removed feature:" | ||
| 993 | print "\t%s" % feature_dirname + "/" + feature | ||
| 994 | |||
| 995 | |||
| 996 | def base_branches(context): | ||
| 997 | """ | ||
| 998 | Return a list of the base branches found in the kernel git repo. | ||
| 999 | """ | ||
| 1000 | giturl = find_giturl(context) | ||
| 1001 | |||
| 1002 | print "Getting branches from remote repo %s..." % giturl | ||
| 1003 | |||
| 1004 | gitcmd = "git ls-remote %s *heads* 2>&1" % (giturl) | ||
| 1005 | tmp = subprocess.Popen(gitcmd, shell=True, stdout=subprocess.PIPE).stdout.read() | ||
| 1006 | |||
| 1007 | branches = [] | ||
| 1008 | |||
| 1009 | if tmp: | ||
| 1010 | tmpline = tmp.split("\n") | ||
| 1011 | for line in tmpline: | ||
| 1012 | if len(line)==0: | ||
| 1013 | break; | ||
| 1014 | if not line.endswith("base"): | ||
| 1015 | continue; | ||
| 1016 | idx = line.find("refs/heads/") | ||
| 1017 | kbranch = line[idx + len("refs/heads/"):] | ||
| 1018 | if kbranch.find("/") == -1 and kbranch.find("base") == -1: | ||
| 1019 | continue | ||
| 1020 | idx = kbranch.find("base") | ||
| 1021 | branches.append(kbranch[:idx - 1]) | ||
| 1022 | |||
| 1023 | return branches | ||
| 1024 | |||
| 1025 | |||
| 1026 | def all_branches(context): | ||
| 1027 | """ | ||
| 1028 | Return a list of all the branches found in the kernel git repo. | ||
| 1029 | """ | ||
| 1030 | giturl = find_giturl(context) | ||
| 1031 | |||
| 1032 | print "Getting branches from remote repo %s..." % giturl | ||
| 1033 | |||
| 1034 | gitcmd = "git ls-remote %s *heads* 2>&1" % (giturl) | ||
| 1035 | tmp = subprocess.Popen(gitcmd, shell=True, stdout=subprocess.PIPE).stdout.read() | ||
| 1036 | |||
| 1037 | branches = [] | ||
| 1038 | |||
| 1039 | base_prefixes = None | ||
| 1040 | |||
| 1041 | try: | ||
| 1042 | branches_base = context["branches_base"] | ||
| 1043 | if branches_base: | ||
| 1044 | base_prefixes = branches_base.split(":") | ||
| 1045 | except KeyError: | ||
| 1046 | pass | ||
| 1047 | |||
| 1048 | arch = context["arch"] | ||
| 1049 | |||
| 1050 | if tmp: | ||
| 1051 | tmpline = tmp.split("\n") | ||
| 1052 | for line in tmpline: | ||
| 1053 | if len(line)==0: | ||
| 1054 | break; | ||
| 1055 | idx = line.find("refs/heads/") | ||
| 1056 | kbranch = line[idx + len("refs/heads/"):] | ||
| 1057 | kbranch_prefix = kbranch.rsplit("/", 1)[0] | ||
| 1058 | |||
| 1059 | if base_prefixes: | ||
| 1060 | for base_prefix in base_prefixes: | ||
| 1061 | if kbranch_prefix == base_prefix: | ||
| 1062 | branches.append(kbranch) | ||
| 1063 | continue | ||
| 1064 | |||
| 1065 | if (kbranch.find("/") != -1 and | ||
| 1066 | (kbranch.find("standard") != -1 or kbranch.find("base") != -1) or | ||
| 1067 | kbranch == "base"): | ||
| 1068 | branches.append(kbranch) | ||
| 1069 | continue | ||
| 1070 | |||
| 1071 | return branches | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/.gitignore b/scripts/lib/bsp/substrate/target/arch/arm/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/.gitignore | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-graphics/xorg-xserver/xserver-xf86-config/machine.noinstall b/scripts/lib/bsp/substrate/target/arch/arm/recipes-graphics/xorg-xserver/xserver-xf86-config/machine.noinstall new file mode 100644 index 0000000000..b442d02d57 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-graphics/xorg-xserver/xserver-xf86-config/machine.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{=machine}} | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-graphics/xorg-xserver/xserver-xf86-config/machine/xorg.conf b/scripts/lib/bsp/substrate/target/arch/arm/recipes-graphics/xorg-xserver/xserver-xf86-config/machine/xorg.conf new file mode 100644 index 0000000000..bc52893e2a --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-graphics/xorg-xserver/xserver-xf86-config/machine/xorg.conf | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | # yocto-bsp-filename {{ if xserver == "y": }} this | ||
| 2 | Section "Module" | ||
| 3 | Load "extmod" | ||
| 4 | Load "dbe" | ||
| 5 | Load "glx" | ||
| 6 | Load "freetype" | ||
| 7 | Load "type1" | ||
| 8 | Load "record" | ||
| 9 | Load "dri" | ||
| 10 | EndSection | ||
| 11 | |||
| 12 | Section "Monitor" | ||
| 13 | Identifier "Builtin Default Monitor" | ||
| 14 | EndSection | ||
| 15 | |||
| 16 | Section "Device" | ||
| 17 | Identifier "Builtin Default fbdev Device 0" | ||
| 18 | Driver "omapfb" | ||
| 19 | EndSection | ||
| 20 | |||
| 21 | Section "Screen" | ||
| 22 | Identifier "Builtin Default fbdev Screen 0" | ||
| 23 | Device "Builtin Default fbdev Device 0" | ||
| 24 | Monitor "Builtin Default Monitor" | ||
| 25 | EndSection | ||
| 26 | |||
| 27 | Section "ServerLayout" | ||
| 28 | Identifier "Builtin Default Layout" | ||
| 29 | Screen "Builtin Default fbdev Screen 0" | ||
| 30 | EndSection | ||
| 31 | |||
| 32 | Section "ServerFlags" | ||
| 33 | Option "DontZap" "0" | ||
| 34 | EndSection | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend b/scripts/lib/bsp/substrate/target/arch/arm/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend new file mode 100644 index 0000000000..30830031ed --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | # yocto-bsp-filename {{ if xserver == "y": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files.noinstall b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files.noinstall new file mode 100644 index 0000000000..1e0d92c55c --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{ if kernel_choice != "custom": }} files | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-non_hardware.cfg b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-non_hardware.cfg new file mode 100644 index 0000000000..9bfc90c6f2 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-non_hardware.cfg | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-non_hardware.cfg | ||
| 2 | # | ||
| 3 | # Miscellaneous filesystems | ||
| 4 | # | ||
| 5 | CONFIG_NFS_DEF_FILE_IO_SIZE=1024 | ||
| 6 | |||
| 7 | # | ||
| 8 | # Multiple Device Support | ||
| 9 | # | ||
| 10 | # CONFIG_MD is not set | ||
| 11 | |||
| 12 | # Kernel Features | ||
| 13 | # | ||
| 14 | CONFIG_NO_HZ=y | ||
| 15 | |||
| 16 | # | ||
| 17 | # CPUIdle | ||
| 18 | # | ||
| 19 | CONFIG_CPU_IDLE=y | ||
| 20 | CONFIG_CPU_IDLE_GOV_LADDER=y | ||
| 21 | CONFIG_CPU_IDLE_GOV_MENU=y | ||
| 22 | |||
| 23 | # | ||
| 24 | # Kernel hacking | ||
| 25 | # | ||
| 26 | CONFIG_DEBUG_FS=y | ||
| 27 | |||
| 28 | # | ||
| 29 | # Power management options | ||
| 30 | # | ||
| 31 | CONFIG_PM_DEBUG=y | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-preempt-rt.scc b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-preempt-rt.scc new file mode 100644 index 0000000000..ca5f3b5be9 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-preempt-rt.scc | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-preempt-rt.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE preempt-rt | ||
| 4 | define KARCH arm | ||
| 5 | |||
| 6 | include {{=map_preempt_rt_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
| 11 | |||
| 12 | # default policy for preempt-rt kernels | ||
| 13 | include features/latencytop/latencytop.scc | ||
| 14 | include features/profiling/profiling.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-standard.scc b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-standard.scc new file mode 100644 index 0000000000..9014c2c97e --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-standard.scc | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-standard.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE standard | ||
| 4 | define KARCH arm | ||
| 5 | |||
| 6 | include {{=map_standard_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
| 11 | |||
| 12 | # default policy for standard kernels | ||
| 13 | include features/latencytop/latencytop.scc | ||
| 14 | include features/profiling/profiling.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-tiny.scc b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-tiny.scc new file mode 100644 index 0000000000..3f1c252232 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-tiny.scc | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-tiny.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE tiny | ||
| 4 | define KARCH arm | ||
| 5 | |||
| 6 | include {{=map_tiny_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-user-config.cfg b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-user-config.cfg new file mode 100644 index 0000000000..47489e44e9 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-user-config.cfg | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-config.cfg | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-user-features.scc b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-user-features.scc new file mode 100644 index 0000000000..582759e612 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-user-features.scc | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-features.scc | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-user-patches.scc b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-user-patches.scc new file mode 100644 index 0000000000..97f747fa07 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine-user-patches.scc | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-patches.scc | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine.cfg b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine.cfg new file mode 100644 index 0000000000..a2e1ae0f75 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine.cfg | |||
| @@ -0,0 +1,321 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.cfg | ||
| 2 | # | ||
| 3 | # System Type | ||
| 4 | # | ||
| 5 | CONFIG_ARCH_OMAP=y | ||
| 6 | |||
| 7 | # | ||
| 8 | # TI OMAP Implementations | ||
| 9 | # | ||
| 10 | # CONFIG_ARCH_OMAP2 is not set | ||
| 11 | CONFIG_ARCH_OMAP3=y | ||
| 12 | |||
| 13 | # | ||
| 14 | # TI OMAP Common Features | ||
| 15 | # | ||
| 16 | CONFIG_ARCH_OMAP2PLUS=y | ||
| 17 | |||
| 18 | # | ||
| 19 | # OMAP Feature Selections | ||
| 20 | # | ||
| 21 | CONFIG_OMAP_32K_TIMER=y | ||
| 22 | CONFIG_OMAP_32K_TIMER_HZ=128 | ||
| 23 | CONFIG_OMAP_DM_TIMER=y | ||
| 24 | CONFIG_OMAP_RESET_CLOCKS=y | ||
| 25 | CONFIG_OMAP_SMARTREFLEX=y | ||
| 26 | CONFIG_OMAP_SMARTREFLEX_CLASS3=y | ||
| 27 | CONFIG_OMAP_MBOX_FWK=m | ||
| 28 | CONFIG_OMAP_MBOX_KFIFO_SIZE=256 | ||
| 29 | |||
| 30 | # | ||
| 31 | # OMAP Board Type | ||
| 32 | # | ||
| 33 | CONFIG_MACH_OMAP3_BEAGLE=y | ||
| 34 | |||
| 35 | # | ||
| 36 | # Processor Features | ||
| 37 | # | ||
| 38 | CONFIG_ARM_THUMBEE=y | ||
| 39 | CONFIG_ARM_ERRATA_430973=y | ||
| 40 | |||
| 41 | # | ||
| 42 | # Kernel Features | ||
| 43 | # | ||
| 44 | CONFIG_LEDS=y | ||
| 45 | |||
| 46 | |||
| 47 | # | ||
| 48 | # Serial drivers | ||
| 49 | # | ||
| 50 | CONFIG_SERIAL_OMAP=y | ||
| 51 | CONFIG_SERIAL_OMAP_CONSOLE=y | ||
| 52 | |||
| 53 | # | ||
| 54 | # At least one emulation must be selected | ||
| 55 | # | ||
| 56 | CONFIG_VFP=y | ||
| 57 | CONFIG_NEON=y | ||
| 58 | |||
| 59 | # | ||
| 60 | # Power management options | ||
| 61 | # | ||
| 62 | CONFIG_PM=y | ||
| 63 | CONFIG_PM_RUNTIME=y | ||
| 64 | |||
| 65 | # | ||
| 66 | # Generic Driver Options | ||
| 67 | # | ||
| 68 | CONFIG_MTD=y | ||
| 69 | CONFIG_MTD_CMDLINE_PARTS=y | ||
| 70 | # | ||
| 71 | # User Modules And Translation Layers | ||
| 72 | # | ||
| 73 | CONFIG_MTD_BLKDEVS=y | ||
| 74 | CONFIG_MTD_BLOCK=y | ||
| 75 | |||
| 76 | # | ||
| 77 | # RAM/ROM/Flash chip drivers | ||
| 78 | # | ||
| 79 | CONFIG_MTD_CFI=y | ||
| 80 | CONFIG_MTD_CFI_INTELEXT=y | ||
| 81 | |||
| 82 | # | ||
| 83 | # Disk-On-Chip Device Drivers | ||
| 84 | # | ||
| 85 | CONFIG_MTD_NAND=y | ||
| 86 | |||
| 87 | CONFIG_MTD_NAND_OMAP2=y | ||
| 88 | |||
| 89 | CONFIG_MTD_UBI=y | ||
| 90 | |||
| 91 | # | ||
| 92 | # SCSI device support | ||
| 93 | # | ||
| 94 | CONFIG_SCSI=y | ||
| 95 | |||
| 96 | # | ||
| 97 | # SCSI support type (disk, tape, CD-ROM) | ||
| 98 | # | ||
| 99 | CONFIG_BLK_DEV_SD=y | ||
| 100 | |||
| 101 | # | ||
| 102 | # Ethernet (10 or 100Mbit) | ||
| 103 | # | ||
| 104 | CONFIG_SMSC911X=y | ||
| 105 | CONFIG_USB_NET_SMSC95XX=y | ||
| 106 | |||
| 107 | # | ||
| 108 | # Userland interfaces | ||
| 109 | # | ||
| 110 | CONFIG_INPUT_EVDEV=y | ||
| 111 | |||
| 112 | # | ||
| 113 | # Input Device Drivers | ||
| 114 | # | ||
| 115 | CONFIG_KEYBOARD_TWL4030=y | ||
| 116 | CONFIG_INPUT_TOUCHSCREEN=y | ||
| 117 | CONFIG_TOUCHSCREEN_ADS7846=y | ||
| 118 | |||
| 119 | # | ||
| 120 | # Miscellaneous I2C Chip support | ||
| 121 | # | ||
| 122 | CONFIG_I2C=y | ||
| 123 | CONFIG_I2C_OMAP=y | ||
| 124 | CONFIG_SPI=y | ||
| 125 | CONFIG_SPI_MASTER=y | ||
| 126 | CONFIG_SPI_OMAP24XX=y | ||
| 127 | |||
| 128 | # | ||
| 129 | # I2C GPIO expanders: | ||
| 130 | # | ||
| 131 | CONFIG_GPIO_TWL4030=y | ||
| 132 | |||
| 133 | # | ||
| 134 | # SPI GPIO expanders: | ||
| 135 | # | ||
| 136 | CONFIG_OMAP_WATCHDOG=y | ||
| 137 | CONFIG_WATCHDOG_NOWAYOUT=y | ||
| 138 | |||
| 139 | # | ||
| 140 | # Multifunction device drivers | ||
| 141 | # | ||
| 142 | CONFIG_TWL4030_CORE=y | ||
| 143 | CONFIG_REGULATOR=y | ||
| 144 | CONFIG_REGULATOR_DUMMY=y | ||
| 145 | CONFIG_REGULATOR_TWL4030=y | ||
| 146 | |||
| 147 | # | ||
| 148 | # Graphics support | ||
| 149 | # | ||
| 150 | CONFIG_FB=y | ||
| 151 | CONFIG_DRM=m | ||
| 152 | # CONFIG_VGASTATE is not set | ||
| 153 | # CONFIG_VIDEO_OUTPUT_CONTROL is not set | ||
| 154 | # CONFIG_FIRMWARE_EDID is not set | ||
| 155 | # CONFIG_FB_DDC is not set | ||
| 156 | # CONFIG_FB_BOOT_VESA_SUPPORT is not set | ||
| 157 | CONFIG_FB_CFB_FILLRECT=y | ||
| 158 | CONFIG_FB_CFB_COPYAREA=y | ||
| 159 | CONFIG_FB_CFB_IMAGEBLIT=y | ||
| 160 | # CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set | ||
| 161 | # CONFIG_FB_SYS_FILLRECT is not set | ||
| 162 | # CONFIG_FB_SYS_COPYAREA is not set | ||
| 163 | # CONFIG_FB_SYS_IMAGEBLIT is not set | ||
| 164 | # CONFIG_FB_FOREIGN_ENDIAN is not set | ||
| 165 | # CONFIG_FB_SYS_FOPS is not set | ||
| 166 | # CONFIG_FB_SVGALIB is not set | ||
| 167 | # CONFIG_FB_MACMODES is not set | ||
| 168 | # CONFIG_FB_BACKLIGHT is not set | ||
| 169 | CONFIG_FB_MODE_HELPERS=y | ||
| 170 | # CONFIG_FB_TILEBLITTING is not set | ||
| 171 | |||
| 172 | # | ||
| 173 | # Frame buffer hardware drivers | ||
| 174 | # | ||
| 175 | # CONFIG_FB_S1D13XXX is not set | ||
| 176 | # CONFIG_FB_TMIO is not set | ||
| 177 | # CONFIG_FB_VIRTUAL is not set | ||
| 178 | # CONFIG_FB_METRONOME is not set | ||
| 179 | # CONFIG_FB_MB862XX is not set | ||
| 180 | # CONFIG_FB_BROADSHEET is not set | ||
| 181 | # CONFIG_FB_OMAP_BOOTLOADER_INIT is not set | ||
| 182 | CONFIG_OMAP2_VRAM=y | ||
| 183 | CONFIG_OMAP2_VRFB=y | ||
| 184 | CONFIG_OMAP2_DSS=y | ||
| 185 | CONFIG_OMAP2_VRAM_SIZE=14 | ||
| 186 | CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y | ||
| 187 | # CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS is not set | ||
| 188 | CONFIG_OMAP2_DSS_DPI=y | ||
| 189 | # CONFIG_OMAP2_DSS_RFBI is not set | ||
| 190 | CONFIG_OMAP2_DSS_VENC=y | ||
| 191 | # CONFIG_OMAP2_DSS_SDI is not set | ||
| 192 | CONFIG_OMAP2_DSS_DSI=y | ||
| 193 | # CONFIG_OMAP2_DSS_FAKE_VSYNC is not set | ||
| 194 | CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0 | ||
| 195 | CONFIG_FB_OMAP2=y | ||
| 196 | CONFIG_FB_OMAP2_DEBUG_SUPPORT=y | ||
| 197 | CONFIG_FB_OMAP2_NUM_FBS=2 | ||
| 198 | |||
| 199 | # | ||
| 200 | # OMAP2/3 Display Device Drivers | ||
| 201 | # | ||
| 202 | CONFIG_PANEL_GENERIC_DPI=y | ||
| 203 | CONFIG_PANEL_DVI=y | ||
| 204 | CONFIG_PANEL_SHARP_LS037V7DW01=y | ||
| 205 | # CONFIG_PANEL_LGPHILIPS_LB035Q02 is not set | ||
| 206 | # CONFIG_PANEL_TAAL is not set | ||
| 207 | CONFIG_PANEL_TPO_TD043MTEA1=m | ||
| 208 | # CONFIG_BACKLIGHT_LCD_SUPPORT is not set | ||
| 209 | CONFIG_BACKLIGHT_CLASS_DEVICE=y | ||
| 210 | |||
| 211 | # | ||
| 212 | # Display device support | ||
| 213 | # | ||
| 214 | CONFIG_DISPLAY_SUPPORT=y | ||
| 215 | CONFIG_DUMMY_CONSOLE=y | ||
| 216 | # CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set | ||
| 217 | CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y | ||
| 218 | # CONFIG_FONTS is not set | ||
| 219 | CONFIG_FONT_8x8=y | ||
| 220 | CONFIG_FONT_8x16=y | ||
| 221 | # CONFIG_LOGO_LINUX_MONO is not set | ||
| 222 | # CONFIG_LOGO_LINUX_VGA16 is not set | ||
| 223 | |||
| 224 | # | ||
| 225 | # Console display driver support | ||
| 226 | # | ||
| 227 | CONFIG_FRAMEBUFFER_CONSOLE=y | ||
| 228 | CONFIG_LOGO=y | ||
| 229 | # CONFIG_VGA_CONSOLE is not set | ||
| 230 | |||
| 231 | # DMA Devices | ||
| 232 | CONFIG_DMADEVICES=y | ||
| 233 | CONFIG_DMA_OMAP=y | ||
| 234 | CONFIG_DMA_OF=y | ||
| 235 | |||
| 236 | CONFIG_SOUND=y | ||
| 237 | CONFIG_SND=y | ||
| 238 | CONFIG_SND_SOC=y | ||
| 239 | CONFIG_SND_OMAP_SOC=y | ||
| 240 | CONFIG_SND_OMAP_SOC_OMAP_TWL4030=y | ||
| 241 | |||
| 242 | # | ||
| 243 | # USB Input Devices | ||
| 244 | # | ||
| 245 | CONFIG_USB=y | ||
| 246 | CONFIG_USB_SUPPORT=y | ||
| 247 | |||
| 248 | # | ||
| 249 | # Miscellaneous USB options | ||
| 250 | # | ||
| 251 | CONFIG_USB_OTG=y | ||
| 252 | # CONFIG_USB_OTG_WHITELIST is not set | ||
| 253 | |||
| 254 | # | ||
| 255 | # USB Host Controller Drivers | ||
| 256 | # | ||
| 257 | CONFIG_USB_EHCI_HCD=y | ||
| 258 | CONFIG_USB_EHCI_TT_NEWSCHED=y | ||
| 259 | CONFIG_USB_EHCI_ROOT_HUB_TT=y | ||
| 260 | CONFIG_USB_MUSB_HDRC=y | ||
| 261 | CONFIG_USB_MUSB_OMAP2PLUS=y | ||
| 262 | CONFIG_USB_OMAP=y | ||
| 263 | |||
| 264 | # | ||
| 265 | # OMAP 343x high speed USB support | ||
| 266 | # | ||
| 267 | CONFIG_USB_MUSB_OTG=y | ||
| 268 | CONFIG_USB_GADGET_MUSB_HDRC=y | ||
| 269 | CONFIG_USB_MUSB_HDRC_HCD=y | ||
| 270 | CONFIG_USB_INVENTRA_DMA=y | ||
| 271 | |||
| 272 | # | ||
| 273 | # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' | ||
| 274 | # | ||
| 275 | |||
| 276 | # | ||
| 277 | # may also be needed; see USB_STORAGE Help for more information | ||
| 278 | # | ||
| 279 | CONFIG_USB_STORAGE=y | ||
| 280 | |||
| 281 | # | ||
| 282 | # USB Miscellaneous drivers | ||
| 283 | # | ||
| 284 | CONFIG_USB_GADGET=y | ||
| 285 | CONFIG_USB_GADGET_DUALSPEED=y | ||
| 286 | CONFIG_USB_OTG_UTILS=y | ||
| 287 | CONFIG_TWL4030_USB=y | ||
| 288 | |||
| 289 | # USB gadget modules | ||
| 290 | CONFIG_USB_G_NCM=y | ||
| 291 | CONFIG_USB_MASS_STORAGE=y | ||
| 292 | |||
| 293 | CONFIG_MMC=y | ||
| 294 | |||
| 295 | # | ||
| 296 | # MMC/SD Host Controller Drivers | ||
| 297 | # | ||
| 298 | CONFIG_MMC_OMAP_HS=y | ||
| 299 | |||
| 300 | # | ||
| 301 | # Real Time Clock | ||
| 302 | # | ||
| 303 | CONFIG_RTC_LIB=y | ||
| 304 | CONFIG_RTC_CLASS=y | ||
| 305 | CONFIG_RTC_DRV_TWL4030=y | ||
| 306 | |||
| 307 | # | ||
| 308 | # DOS/FAT/NT Filesystems | ||
| 309 | # | ||
| 310 | CONFIG_VFAT_FS=y | ||
| 311 | |||
| 312 | # | ||
| 313 | # Multimedia core support | ||
| 314 | # | ||
| 315 | |||
| 316 | # CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set | ||
| 317 | |||
| 318 | # | ||
| 319 | # Advanced Power Management Emulation support | ||
| 320 | # | ||
| 321 | CONFIG_APM_EMULATION=y | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine.scc b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine.scc new file mode 100644 index 0000000000..828400df40 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/files/machine.scc | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.scc | ||
| 2 | kconf hardware {{=machine}}.cfg | ||
| 3 | kconf non-hardware {{machine}}-non_hardware.cfg | ||
| 4 | |||
| 5 | include features/usb-net/usb-net.scc | ||
| 6 | |||
| 7 | kconf hardware {{=machine}}-user-config.cfg | ||
| 8 | include {{=machine}}-user-patches.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/kernel-list.noinstall b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/kernel-list.noinstall new file mode 100644 index 0000000000..a04e6c7852 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/kernel-list.noinstall | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | {{ if kernel_choice != "custom": }} | ||
| 2 | {{ input type:"boolean" name:"use_default_kernel" prio:"10" msg:"Would you like to use the default (3.14) kernel? (y/n)" default:"y"}} | ||
| 3 | |||
| 4 | {{ if kernel_choice != "custom" and use_default_kernel == "n": }} | ||
| 5 | {{ input type:"choicelist" name:"kernel_choice" gen:"bsp.kernel.kernels" prio:"10" msg:"Please choose the kernel to use in this BSP:" default:"linux-yocto_3.14"}} | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto-dev.bbappend b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto-dev.bbappend new file mode 100644 index 0000000000..2fa6231cbf --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto-dev.bbappend | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-dev": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 8 | |||
| 9 | {{ if need_new_kbranch == "y": }} | ||
| 10 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 11 | |||
| 12 | {{ if need_new_kbranch == "n": }} | ||
| 13 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 14 | |||
| 15 | {{ if need_new_kbranch == "n": }} | ||
| 16 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 17 | |||
| 18 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Would you like SMP support? (y/n)" default:"y"}} | ||
| 19 | {{ if smp == "y": }} | ||
| 20 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 21 | |||
| 22 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 23 | file://{{=machine}}-user-config.cfg \ | ||
| 24 | file://{{=machine}}-user-patches.scc \ | ||
| 25 | file://{{=machine}}-user-features.scc \ | ||
| 26 | " | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend new file mode 100644 index 0000000000..35b0958582 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-rt_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-preempt-rt.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-rt_{{=machine}} ?= "f35992f80c81dc5fa1a97165dfd5cbb84661f7cb" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-rt_{{=machine}} ?= "1b534b2f8bbe9b8a773268cfa30a4850346f6f5f" | ||
| 33 | #LINUX_VERSION = "3.10.9" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend new file mode 100644 index 0000000000..f04dd0cce4 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-tiny_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-tiny.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-tiny_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-tiny_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.10.9" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend new file mode 100644 index 0000000000..471ccbcc3e --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-tiny_3.14": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-tiny.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-tiny_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-tiny_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.14" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto_3.10.bbappend new file mode 100644 index 0000000000..badb3aa239 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto_{{=machine}} ?= "19f7e43b54aef08d58135ed2a897d77b624b320a" | ||
| 32 | #SRCREV_meta_pn-linux-yocto_{{=machine}} ?= "459165c1dd61c4e843c36e6a1abeb30949a20ba7" | ||
| 33 | #LINUX_VERSION = "3.10.9" \ No newline at end of file | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto_3.14.bbappend b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto_3.14.bbappend new file mode 100644 index 0000000000..1e1cc51315 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/arm/recipes-kernel/linux/linux-yocto_3.14.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto_3.14": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.14" \ No newline at end of file | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/COPYING.MIT b/scripts/lib/bsp/substrate/target/arch/common/COPYING.MIT new file mode 100644 index 0000000000..fb950dc69f --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/COPYING.MIT | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 2 | of this software and associated documentation files (the "Software"), to deal | ||
| 3 | in the Software without restriction, including without limitation the rights | ||
| 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 5 | copies of the Software, and to permit persons to whom the Software is | ||
| 6 | furnished to do so, subject to the following conditions: | ||
| 7 | |||
| 8 | The above copyright notice and this permission notice shall be included in | ||
| 9 | all copies or substantial portions of the Software. | ||
| 10 | |||
| 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 17 | THE SOFTWARE. | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/README b/scripts/lib/bsp/substrate/target/arch/common/README new file mode 100644 index 0000000000..928659f302 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/README | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | This README file contains information on building the meta-{{=machine}} | ||
| 2 | BSP layer, and booting the images contained in the /binary directory. | ||
| 3 | Please see the corresponding sections below for details. | ||
| 4 | |||
| 5 | |||
| 6 | Dependencies | ||
| 7 | ============ | ||
| 8 | |||
| 9 | This layer depends on: | ||
| 10 | |||
| 11 | URI: git://git.openembedded.org/bitbake | ||
| 12 | branch: master | ||
| 13 | |||
| 14 | URI: git://git.openembedded.org/openembedded-core | ||
| 15 | layers: meta | ||
| 16 | branch: master | ||
| 17 | |||
| 18 | URI: git://git.yoctoproject.org/xxxx | ||
| 19 | layers: xxxx | ||
| 20 | branch: master | ||
| 21 | |||
| 22 | |||
| 23 | Patches | ||
| 24 | ======= | ||
| 25 | |||
| 26 | Please submit any patches against this BSP to the Yocto mailing list | ||
| 27 | (yocto@yoctoproject.org) and cc: the maintainer: | ||
| 28 | |||
| 29 | Maintainer: XXX YYYYYY <xxx.yyyyyy@zzzzz.com> | ||
| 30 | |||
| 31 | Please see the meta-xxxx/MAINTAINERS file for more details. | ||
| 32 | |||
| 33 | |||
| 34 | Table of Contents | ||
| 35 | ================= | ||
| 36 | |||
| 37 | I. Building the meta-{{=machine}} BSP layer | ||
| 38 | II. Booting the images in /binary | ||
| 39 | |||
| 40 | |||
| 41 | I. Building the meta-{{=machine}} BSP layer | ||
| 42 | ======================================== | ||
| 43 | |||
| 44 | --- replace with specific instructions for your layer --- | ||
| 45 | |||
| 46 | In order to build an image with BSP support for a given release, you | ||
| 47 | need to download the corresponding BSP tarball from the 'Board Support | ||
| 48 | Package (BSP) Downloads' page of the Yocto Project website. | ||
| 49 | |||
| 50 | Having done that, and assuming you extracted the BSP tarball contents | ||
| 51 | at the top-level of your yocto build tree, you can build a | ||
| 52 | {{=machine}} image by adding the location of the meta-{{=machine}} | ||
| 53 | layer to bblayers.conf, along with any other layers needed (to access | ||
| 54 | common metadata shared between BSPs) e.g.: | ||
| 55 | |||
| 56 | yocto/meta-xxxx \ | ||
| 57 | yocto/meta-xxxx/meta-{{=machine}} \ | ||
| 58 | |||
| 59 | To enable the {{=machine}} layer, add the {{=machine}} MACHINE to local.conf: | ||
| 60 | |||
| 61 | MACHINE ?= "{{=machine}}" | ||
| 62 | |||
| 63 | You should then be able to build a {{=machine}} image as such: | ||
| 64 | |||
| 65 | $ source oe-init-build-env | ||
| 66 | $ bitbake core-image-sato | ||
| 67 | |||
| 68 | At the end of a successful build, you should have a live image that | ||
| 69 | you can boot from a USB flash drive (see instructions on how to do | ||
| 70 | that below, in the section 'Booting the images from /binary'). | ||
| 71 | |||
| 72 | As an alternative to downloading the BSP tarball, you can also work | ||
| 73 | directly from the meta-xxxx git repository. For each BSP in the | ||
| 74 | 'meta-xxxx' repository, there are multiple branches, one corresponding | ||
| 75 | to each major release starting with 'laverne' (0.90), in addition to | ||
| 76 | the latest code which tracks the current master (note that not all | ||
| 77 | BSPs are present in every release). Instead of extracting a BSP | ||
| 78 | tarball at the top level of your yocto build tree, you can | ||
| 79 | equivalently check out the appropriate branch from the meta-xxxx | ||
| 80 | repository at the same location. | ||
| 81 | |||
| 82 | |||
| 83 | II. Booting the images in /binary | ||
| 84 | ================================= | ||
| 85 | |||
| 86 | --- replace with specific instructions for your platform --- | ||
| 87 | |||
| 88 | This BSP contains bootable live images, which can be used to directly | ||
| 89 | boot Yocto off of a USB flash drive. | ||
| 90 | |||
| 91 | Under Linux, insert a USB flash drive. Assuming the USB flash drive | ||
| 92 | takes device /dev/sdf, use dd to copy the live image to it. For | ||
| 93 | example: | ||
| 94 | |||
| 95 | # dd if=core-image-sato-{{=machine}}-20101207053738.hddimg of=/dev/sdf | ||
| 96 | # sync | ||
| 97 | # eject /dev/sdf | ||
| 98 | |||
| 99 | This should give you a bootable USB flash device. Insert the device | ||
| 100 | into a bootable USB socket on the target, and power on. This should | ||
| 101 | result in a system booted to the Sato graphical desktop. | ||
| 102 | |||
| 103 | If you want a terminal, use the arrows at the top of the UI to move to | ||
| 104 | different pages of available applications, one of which is named | ||
| 105 | 'Terminal'. Clicking that should give you a root terminal. | ||
| 106 | |||
| 107 | If you want to ssh into the system, you can use the root terminal to | ||
| 108 | ifconfig the IP address and use that to ssh in. The root password is | ||
| 109 | empty, so to log in type 'root' for the user name and hit 'Enter' at | ||
| 110 | the Password prompt: and you should be in. | ||
| 111 | |||
| 112 | ---- | ||
| 113 | |||
| 114 | If you find you're getting corrupt images on the USB (it doesn't show | ||
| 115 | the syslinux boot: prompt, or the boot: prompt contains strange | ||
| 116 | characters), try doing this first: | ||
| 117 | |||
| 118 | # dd if=/dev/zero of=/dev/sdf bs=1M count=512 | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/README.sources b/scripts/lib/bsp/substrate/target/arch/common/README.sources new file mode 100644 index 0000000000..3c4cb7b435 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/README.sources | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | The sources for the packages comprising the images shipped with this | ||
| 2 | BSP can be found at the following location: | ||
| 3 | |||
| 4 | http://downloads.yoctoproject.org/mirror/sources/ | ||
| 5 | |||
| 6 | The metadata used to generate the images shipped with this BSP, in | ||
| 7 | addition to the code contained in this BSP, can be found at the | ||
| 8 | following location: | ||
| 9 | |||
| 10 | http://www.yoctoproject.org/downloads/yocto-1.1/poky-edison-6.0.tar.bz2 | ||
| 11 | |||
| 12 | The metadata used to generate the images shipped with this BSP, in | ||
| 13 | addition to the code contained in this BSP, can also be found at the | ||
| 14 | following locations: | ||
| 15 | |||
| 16 | git://git.yoctoproject.org/poky.git | ||
| 17 | git://git.yoctoproject.org/meta-xxxx | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/binary/.gitignore b/scripts/lib/bsp/substrate/target/arch/common/binary/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/binary/.gitignore | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/conf/layer.conf b/scripts/lib/bsp/substrate/target/arch/common/conf/layer.conf new file mode 100644 index 0000000000..5529f45954 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/conf/layer.conf | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # We have a conf and classes directory, add to BBPATH | ||
| 2 | BBPATH .= ":${LAYERDIR}" | ||
| 3 | |||
| 4 | # We have a recipes-* directories, add to BBFILES | ||
| 5 | BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ | ||
| 6 | ${LAYERDIR}/recipes-*/*/*.bbappend" | ||
| 7 | |||
| 8 | BBFILE_COLLECTIONS += "{{=machine}}" | ||
| 9 | BBFILE_PATTERN_{{=machine}} = "^${LAYERDIR}/" | ||
| 10 | BBFILE_PRIORITY_{{=machine}} = "6" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/recipes-bsp/formfactor/formfactor/machine.noinstall b/scripts/lib/bsp/substrate/target/arch/common/recipes-bsp/formfactor/formfactor/machine.noinstall new file mode 100644 index 0000000000..b442d02d57 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/recipes-bsp/formfactor/formfactor/machine.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{=machine}} | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/recipes-bsp/formfactor/formfactor/machine/machconfig b/scripts/lib/bsp/substrate/target/arch/common/recipes-bsp/formfactor/formfactor/machine/machconfig new file mode 100644 index 0000000000..3b85d3821f --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/recipes-bsp/formfactor/formfactor/machine/machconfig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | # Assume a USB mouse and keyboard are connected | ||
| 2 | {{ input type:"boolean" name:"touchscreen" msg:"Does your BSP have a touchscreen? (y/n)" default:"n" }} | ||
| 3 | HAVE_TOUCHSCREEN={{=touchscreen}} | ||
| 4 | {{ input type:"boolean" name:"keyboard" msg:"Does your BSP have a keyboard? (y/n)" default:"y" }} | ||
| 5 | HAVE_KEYBOARD={{=keyboard}} | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/recipes-bsp/formfactor/formfactor_0.0.bbappend b/scripts/lib/bsp/substrate/target/arch/common/recipes-bsp/formfactor/formfactor_0.0.bbappend new file mode 100644 index 0000000000..6d4804d127 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/recipes-bsp/formfactor/formfactor_0.0.bbappend | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" | ||
| 2 | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/kernel-list.noinstall b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/kernel-list.noinstall new file mode 100644 index 0000000000..03b7d84ec2 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/kernel-list.noinstall | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | {{ if kernel_choice == "custom": }} | ||
| 2 | {{ input type:"boolean" name:"custom_kernel_remote" prio:"20" msg:"Is the custom kernel you'd like to use in a remote git repo? (y/n)" default:"y"}} | ||
| 3 | |||
| 4 | {{ if kernel_choice == "custom" and custom_kernel_remote == "y": }} | ||
| 5 | {{ input type:"edit-git-repo" name:"custom_kernel_remote_path" prio:"20" msg:"Please enter the full URI to the remote git repo (the default corresponds to linux-stable v3.13.9)" default:"git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git"}} | ||
| 6 | |||
| 7 | {{ if kernel_choice == "custom" and custom_kernel_remote == "n": }} | ||
| 8 | {{ input type:"edit-git-repo" name:"custom_kernel_local_path" prio:"20" msg:"You've indicated that you're not using a remote git repo. Please enter the full path to the local git repo you want to use (the default assumes a local linux-stable v3.13.9)" default:"/home/trz/yocto/kernels/linux-stable.git"}} | ||
| 9 | |||
| 10 | {{ if kernel_choice == "custom": }} | ||
| 11 | {{ input type:"boolean" name:"custom_kernel_need_kbranch" prio:"20" msg:"Do you need to use a specific (non-master) branch? (y/n)" default:"n"}} | ||
| 12 | |||
| 13 | {{ if kernel_choice == "custom" and custom_kernel_need_kbranch == "y": }} | ||
| 14 | {{ input type:"edit" name:"custom_kernel_kbranch" prio:"20" msg:"Please enter the branch you want to use (the default branch corresponds to the linux-stable 'linux-3.13.y' branch):" default:"linux-3.13.y"}} | ||
| 15 | |||
| 16 | {{ if kernel_choice == "custom": }} | ||
| 17 | {{ input type:"edit" name:"custom_kernel_srcrev" prio:"20" msg:"Please enter the SRCREV (commit id) you'd like to use (use '${AUTOREV}' to track the current HEAD):" default:"${AUTOREV}"}} | ||
| 18 | |||
| 19 | {{ if kernel_choice == "custom": }} | ||
| 20 | {{ input type:"edit" name:"custom_kernel_linux_version" prio:"20" msg:"Please enter the Linux version of the kernel you've specified:" default:"3.13.9"}} | ||
| 21 | |||
| 22 | {{ if kernel_choice == "custom": }} | ||
| 23 | {{ input type:"edit" name:"custom_kernel_linux_version_extension" prio:"20" msg:"Please enter a Linux version extension if you want (it will show up at the end of the kernel name shown by uname):" default:"-custom"}} | ||
| 24 | |||
| 25 | {{ if kernel_choice == "custom": }} | ||
| 26 | {{ input type:"edit-file" name:"custom_kernel_defconfig" prio:"20" msg:"It's recommended (but not required) that custom kernels be built using a defconfig. Please enter the full path to the defconfig for your kernel (NOTE: if you don't specify a defconfig the kernel probably won't build or boot):" default:""}} | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom.bb b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom.bb new file mode 100644 index 0000000000..80a52e7cae --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom.bb | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "custom": }} this | ||
| 2 | # This file was derived from the linux-yocto-custom.bb recipe in | ||
| 3 | # oe-core. | ||
| 4 | # | ||
| 5 | # linux-yocto-custom.bb: | ||
| 6 | # | ||
| 7 | # A yocto-bsp-generated kernel recipe that uses the linux-yocto and | ||
| 8 | # oe-core kernel classes to apply a subset of yocto kernel | ||
| 9 | # management to git managed kernel repositories. | ||
| 10 | # | ||
| 11 | # Warning: | ||
| 12 | # | ||
| 13 | # Building this kernel without providing a defconfig or BSP | ||
| 14 | # configuration will result in build or boot errors. This is not a | ||
| 15 | # bug. | ||
| 16 | # | ||
| 17 | # Notes: | ||
| 18 | # | ||
| 19 | # patches: patches can be merged into to the source git tree itself, | ||
| 20 | # added via the SRC_URI, or controlled via a BSP | ||
| 21 | # configuration. | ||
| 22 | # | ||
| 23 | # example configuration addition: | ||
| 24 | # SRC_URI += "file://smp.cfg" | ||
| 25 | # example patch addition: | ||
| 26 | # SRC_URI += "file://0001-linux-version-tweak.patch | ||
| 27 | # example feature addition: | ||
| 28 | # SRC_URI += "file://feature.scc" | ||
| 29 | # | ||
| 30 | |||
| 31 | inherit kernel | ||
| 32 | require recipes-kernel/linux/linux-yocto.inc | ||
| 33 | |||
| 34 | {{ if kernel_choice == "custom" and custom_kernel_remote == "y": }} | ||
| 35 | SRC_URI = "{{=custom_kernel_remote_path}};protocol=git;bareclone=1;branch=${KBRANCH}" | ||
| 36 | {{ if kernel_choice == "custom" and custom_kernel_remote == "n": }} | ||
| 37 | SRC_URI = "git://{{=custom_kernel_local_path}};protocol=file;bareclone=1;branch=${KBRANCH}" | ||
| 38 | |||
| 39 | SRC_URI += "file://defconfig" | ||
| 40 | |||
| 41 | SRC_URI += "file://{{=machine}}.scc \ | ||
| 42 | file://{{=machine}}.cfg \ | ||
| 43 | file://{{=machine}}-user-config.cfg \ | ||
| 44 | file://{{=machine}}-user-patches.scc \ | ||
| 45 | " | ||
| 46 | |||
| 47 | {{ if kernel_choice == "custom" and custom_kernel_need_kbranch == "y" and custom_kernel_kbranch and custom_kernel_kbranch != "master": }} | ||
| 48 | KBRANCH = "{{=custom_kernel_kbranch}}" | ||
| 49 | |||
| 50 | LINUX_VERSION ?= "{{=custom_kernel_linux_version}}" | ||
| 51 | LINUX_VERSION_EXTENSION ?= "{{=custom_kernel_linux_version_extension}}" | ||
| 52 | |||
| 53 | SRCREV="{{=custom_kernel_srcrev}}" | ||
| 54 | |||
| 55 | PR = "r0" | ||
| 56 | PV = "${LINUX_VERSION}+git${SRCPV}" | ||
| 57 | |||
| 58 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom.noinstall b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom.noinstall new file mode 100644 index 0000000000..017d206c24 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{ if kernel_choice == "custom": }} linux-yocto-custom | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/defconfig b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/defconfig new file mode 100644 index 0000000000..ceb0ffa30c --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/defconfig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | # | ||
| 2 | # Placeholder for custom default kernel configuration. yocto-bsp will | ||
| 3 | # replace this file with a user-specified defconfig. | ||
| 4 | # | ||
| 5 | {{ if custom_kernel_defconfig: replace_file(of, custom_kernel_defconfig) }} | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/machine-user-config.cfg b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/machine-user-config.cfg new file mode 100644 index 0000000000..922309d5ab --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/machine-user-config.cfg | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-user-config.cfg | ||
| 2 | # | ||
| 3 | # Used by yocto-kernel to manage config options. | ||
| 4 | # | ||
| 5 | # yocto-kernel may change the contents of this file in any | ||
| 6 | # way it sees fit, including removing comments like this, | ||
| 7 | # so don't manually make any modifications you don't want | ||
| 8 | # to lose. | ||
| 9 | # | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/machine-user-patches.scc b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/machine-user-patches.scc new file mode 100644 index 0000000000..6d1138f42a --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/machine-user-patches.scc | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-user-patches.scc | ||
| 2 | # | ||
| 3 | # Used by yocto-kernel to manage patches. | ||
| 4 | # | ||
| 5 | # yocto-kernel may change the contents of this file in any | ||
| 6 | # way it sees fit, including removing comments like this, | ||
| 7 | # so don't manually make any modifications you don't want | ||
| 8 | # to lose. | ||
| 9 | # | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/machine.cfg b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/machine.cfg new file mode 100644 index 0000000000..1ba8201f16 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/machine.cfg | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.cfg | ||
| 2 | # | ||
| 3 | # A convenient place to add config options, nothing more. | ||
| 4 | # | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/machine.scc b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/machine.scc new file mode 100644 index 0000000000..0b6b413377 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/common/recipes-kernel/linux/linux-yocto-custom/machine.scc | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.scc | ||
| 2 | # | ||
| 3 | # The top-level 'feature' for the {{=machine}} custom kernel. | ||
| 4 | # | ||
| 5 | # Essentially this is a convenient top-level container or starting | ||
| 6 | # point for adding lower-level config fragements and features. | ||
| 7 | # | ||
| 8 | |||
| 9 | # {{=machine}}.cfg in the linux-yocto-custom subdir is just a | ||
| 10 | # convenient place for adding random config fragments. | ||
| 11 | |||
| 12 | kconf hardware {{=machine}}.cfg | ||
| 13 | |||
| 14 | # These are used by yocto-kernel to add config fragments and features. | ||
| 15 | # Don't remove if you plan on using yocto-kernel with this BSP. | ||
| 16 | |||
| 17 | kconf hardware {{=machine}}-user-config.cfg | ||
| 18 | include {{=machine}}-user-patches.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/conf/machine/machine.conf b/scripts/lib/bsp/substrate/target/arch/i386/conf/machine/machine.conf new file mode 100644 index 0000000000..43e38d06d0 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/conf/machine/machine.conf | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.conf | ||
| 2 | #@TYPE: Machine | ||
| 3 | #@NAME: {{=machine}} | ||
| 4 | |||
| 5 | #@DESCRIPTION: Machine configuration for {{=machine}} systems | ||
| 6 | |||
| 7 | {{ if kernel_choice == "custom": preferred_kernel = "linux-yocto-custom" }} | ||
| 8 | {{ if kernel_choice == "linux-yocto-dev": preferred_kernel = "linux-yocto-dev" }} | ||
| 9 | {{ if kernel_choice == "custom" or kernel_choice == "linux-yocto-dev" : }} | ||
| 10 | PREFERRED_PROVIDER_virtual/kernel ?= "{{=preferred_kernel}}" | ||
| 11 | |||
| 12 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": preferred_kernel = kernel_choice.split('_')[0] }} | ||
| 13 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": preferred_kernel_version = kernel_choice.split('_')[1] }} | ||
| 14 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": }} | ||
| 15 | PREFERRED_PROVIDER_virtual/kernel ?= "{{=preferred_kernel}}" | ||
| 16 | PREFERRED_VERSION_{{=preferred_kernel}} ?= "{{=preferred_kernel_version}}%" | ||
| 17 | |||
| 18 | {{ input type:"choicelist" name:"tunefile" prio:"40" msg:"Which machine tuning would you like to use?" default:"tune_core2" }} | ||
| 19 | {{ input type:"choice" val:"tune_i586" msg:"i586 tuning optimizations" }} | ||
| 20 | {{ input type:"choice" val:"tune_atom" msg:"Atom tuning optimizations" }} | ||
| 21 | {{ input type:"choice" val:"tune_core2" msg:"Core2 tuning optimizations" }} | ||
| 22 | {{ if tunefile == "tune_i586": }} | ||
| 23 | require conf/machine/include/tune-i586.inc | ||
| 24 | {{ if tunefile == "tune_atom": }} | ||
| 25 | require conf/machine/include/tune-atom.inc | ||
| 26 | {{ if tunefile == "tune_core2": }} | ||
| 27 | DEFAULTTUNE="core2-32" | ||
| 28 | require conf/machine/include/tune-core2.inc | ||
| 29 | |||
| 30 | require conf/machine/include/x86-base.inc | ||
| 31 | |||
| 32 | MACHINE_FEATURES += "wifi efi pcbios" | ||
| 33 | |||
| 34 | {{ input type:"boolean" name:"xserver" prio:"50" msg:"Do you need support for X? (y/n)" default:"y" }} | ||
| 35 | |||
| 36 | {{ if xserver == "y" and (kernel_choice == "linux-yocto_3.14" or kernel_choice == "linux-yocto_3.10"): }} | ||
| 37 | {{ input type:"choicelist" name:"xserver_choice" prio:"50" msg:"Please select an xserver for this machine:" default:"xserver_i915" }} | ||
| 38 | {{ input type:"choice" val:"xserver_vesa" msg:"VESA xserver support" }} | ||
| 39 | {{ input type:"choice" val:"xserver_i915" msg:"i915 xserver support" }} | ||
| 40 | {{ input type:"choice" val:"xserver_i965" msg:"i965 xserver support" }} | ||
| 41 | |||
| 42 | {{ if xserver == "y" and kernel_choice == "custom": }} | ||
| 43 | {{ input type:"choicelist" name:"xserver_choice" prio:"50" msg:"Please select an xserver for this machine:" default:"xserver_i915" }} | ||
| 44 | {{ input type:"choice" val:"xserver_vesa" msg:"VESA xserver support" }} | ||
| 45 | {{ input type:"choice" val:"xserver_i915" msg:"i915 xserver support" }} | ||
| 46 | {{ input type:"choice" val:"xserver_i965" msg:"i965 xserver support" }} | ||
| 47 | |||
| 48 | {{ if xserver == "y" and kernel_choice != "linux-yocto_3.14" and kernel_choice != "linux-yocto_3.10" and kernel_choice != "custom": xserver_choice = "xserver_i915" }} | ||
| 49 | |||
| 50 | {{ if xserver == "y": }} | ||
| 51 | XSERVER ?= "${XSERVER_X86_BASE} \ | ||
| 52 | ${XSERVER_X86_EXT} \ | ||
| 53 | {{ if xserver == "y" and xserver_choice == "xserver_vesa": }} | ||
| 54 | ${XSERVER_X86_VESA} \ | ||
| 55 | {{ if xserver == "y" and xserver_choice == "xserver_i915": }} | ||
| 56 | ${XSERVER_X86_I915} \ | ||
| 57 | {{ if xserver == "y" and xserver_choice == "xserver_i965": }} | ||
| 58 | ${XSERVER_X86_I965} \ | ||
| 59 | {{ if xserver == "y": }} | ||
| 60 | " | ||
| 61 | |||
| 62 | MACHINE_EXTRA_RRECOMMENDS += "linux-firmware v86d" | ||
| 63 | |||
| 64 | EXTRA_OECONF_append_pn-matchbox-panel-2 = " --with-battery=acpi" | ||
| 65 | |||
| 66 | {{ if xserver == "y" and xserver_choice == "xserver_vesa": }} | ||
| 67 | APPEND += "video=vesafb vga=0x318" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-graphics/xorg-xserver/xserver-xf86-config/machine.noinstall b/scripts/lib/bsp/substrate/target/arch/i386/recipes-graphics/xorg-xserver/xserver-xf86-config/machine.noinstall new file mode 100644 index 0000000000..b442d02d57 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-graphics/xorg-xserver/xserver-xf86-config/machine.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{=machine}} | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-graphics/xorg-xserver/xserver-xf86-config/machine/xorg.conf b/scripts/lib/bsp/substrate/target/arch/i386/recipes-graphics/xorg-xserver/xserver-xf86-config/machine/xorg.conf new file mode 100644 index 0000000000..ac9a0f1bb0 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-graphics/xorg-xserver/xserver-xf86-config/machine/xorg.conf | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{ if xserver == "y": }} this | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend b/scripts/lib/bsp/substrate/target/arch/i386/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend new file mode 100644 index 0000000000..30830031ed --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | # yocto-bsp-filename {{ if xserver == "y": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files.noinstall b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files.noinstall new file mode 100644 index 0000000000..1e0d92c55c --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{ if kernel_choice != "custom": }} files | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-preempt-rt.scc b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-preempt-rt.scc new file mode 100644 index 0000000000..619ee3f367 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-preempt-rt.scc | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-preempt-rt.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE preempt-rt | ||
| 4 | define KARCH i386 | ||
| 5 | |||
| 6 | include {{=map_preempt_rt_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
| 11 | |||
| 12 | # default policy for preempt-rt kernels | ||
| 13 | include cfg/usb-mass-storage.scc | ||
| 14 | include cfg/boot-live.scc | ||
| 15 | include features/latencytop/latencytop.scc | ||
| 16 | include features/profiling/profiling.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-standard.scc b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-standard.scc new file mode 100644 index 0000000000..682012fafc --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-standard.scc | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-standard.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE standard | ||
| 4 | define KARCH i386 | ||
| 5 | |||
| 6 | include {{=map_standard_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
| 11 | |||
| 12 | # default policy for standard kernels | ||
| 13 | include cfg/usb-mass-storage.scc | ||
| 14 | include cfg/boot-live.scc | ||
| 15 | include features/latencytop/latencytop.scc | ||
| 16 | include features/profiling/profiling.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-tiny.scc b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-tiny.scc new file mode 100644 index 0000000000..cc7519699a --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-tiny.scc | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-tiny.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE tiny | ||
| 4 | define KARCH i386 | ||
| 5 | |||
| 6 | include {{=map_tiny_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-user-config.cfg b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-user-config.cfg new file mode 100644 index 0000000000..69efdcc759 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-user-config.cfg | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-config.cfg \ No newline at end of file | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-user-features.scc b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-user-features.scc new file mode 100644 index 0000000000..85be26de97 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-user-features.scc | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-features.scc \ No newline at end of file | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-user-patches.scc b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-user-patches.scc new file mode 100644 index 0000000000..4c59daac46 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine-user-patches.scc | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-patches.scc \ No newline at end of file | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine.cfg b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine.cfg new file mode 100644 index 0000000000..3b168b7e36 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine.cfg | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.cfg | ||
| 2 | CONFIG_X86_32=y | ||
| 3 | CONFIG_MATOM=y | ||
| 4 | CONFIG_PRINTK=y | ||
| 5 | |||
| 6 | # Basic hardware support for the box - network, USB, PCI, sound | ||
| 7 | CONFIG_NETDEVICES=y | ||
| 8 | CONFIG_ATA=y | ||
| 9 | CONFIG_ATA_GENERIC=y | ||
| 10 | CONFIG_ATA_SFF=y | ||
| 11 | CONFIG_PCI=y | ||
| 12 | CONFIG_MMC=y | ||
| 13 | CONFIG_MMC_SDHCI=y | ||
| 14 | CONFIG_USB_SUPPORT=y | ||
| 15 | CONFIG_USB=y | ||
| 16 | CONFIG_USB_ARCH_HAS_EHCI=y | ||
| 17 | CONFIG_R8169=y | ||
| 18 | CONFIG_PATA_SCH=y | ||
| 19 | CONFIG_MMC_SDHCI_PCI=y | ||
| 20 | CONFIG_USB_EHCI_HCD=y | ||
| 21 | CONFIG_PCIEPORTBUS=y | ||
| 22 | CONFIG_NET=y | ||
| 23 | CONFIG_USB_UHCI_HCD=y | ||
| 24 | CONFIG_USB_OHCI_HCD=y | ||
| 25 | CONFIG_BLK_DEV_SD=y | ||
| 26 | CONFIG_CHR_DEV_SG=y | ||
| 27 | CONFIG_SOUND=y | ||
| 28 | CONFIG_SND=y | ||
| 29 | CONFIG_SND_HDA_INTEL=y | ||
| 30 | CONFIG_SATA_AHCI=y | ||
| 31 | CONFIG_AGP=y | ||
| 32 | CONFIG_PM=y | ||
| 33 | CONFIG_ACPI=y | ||
| 34 | CONFIG_BACKLIGHT_LCD_SUPPORT=y | ||
| 35 | CONFIG_BACKLIGHT_CLASS_DEVICE=y | ||
| 36 | CONFIG_INPUT=y | ||
| 37 | |||
| 38 | # Make sure these are on, otherwise the bootup won't be fun | ||
| 39 | CONFIG_EXT3_FS=y | ||
| 40 | CONFIG_UNIX=y | ||
| 41 | CONFIG_INET=y | ||
| 42 | CONFIG_MODULES=y | ||
| 43 | CONFIG_SHMEM=y | ||
| 44 | CONFIG_TMPFS=y | ||
| 45 | CONFIG_PACKET=y | ||
| 46 | |||
| 47 | # Needed for booting (and using) USB memory sticks | ||
| 48 | CONFIG_BLK_DEV_LOOP=y | ||
| 49 | CONFIG_NLS_CODEPAGE_437=y | ||
| 50 | CONFIG_NLS_ISO8859_1=y | ||
| 51 | |||
| 52 | CONFIG_RD_GZIP=y | ||
| 53 | |||
| 54 | # Needed for booting (and using) CD images | ||
| 55 | CONFIG_BLK_DEV_SR=y | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine.scc b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine.scc new file mode 100644 index 0000000000..3d32f111b0 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/files/machine.scc | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.scc | ||
| 2 | kconf hardware {{=machine}}.cfg | ||
| 3 | |||
| 4 | include features/intel-e1xxxx/intel-e100.scc | ||
| 5 | include features/intel-e1xxxx/intel-e1xxxx.scc | ||
| 6 | |||
| 7 | {{ if xserver == "y" and xserver_choice == "xserver_i915" or xserver_choice == "xserver_i965": }} | ||
| 8 | include features/i915/i915.scc | ||
| 9 | |||
| 10 | include features/serial/8250.scc | ||
| 11 | include features/ericsson-3g/f5521gw.scc | ||
| 12 | |||
| 13 | {{ if xserver == "y" and xserver_choice == "xserver_vesa": }} | ||
| 14 | include cfg/vesafb.scc | ||
| 15 | |||
| 16 | include cfg/usb-mass-storage.scc | ||
| 17 | include cfg/boot-live.scc | ||
| 18 | include features/power/intel.scc | ||
| 19 | |||
| 20 | kconf hardware {{=machine}}-user-config.cfg | ||
| 21 | include {{=machine}}-user-patches.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/kernel-list.noinstall b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/kernel-list.noinstall new file mode 100644 index 0000000000..a04e6c7852 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/kernel-list.noinstall | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | {{ if kernel_choice != "custom": }} | ||
| 2 | {{ input type:"boolean" name:"use_default_kernel" prio:"10" msg:"Would you like to use the default (3.14) kernel? (y/n)" default:"y"}} | ||
| 3 | |||
| 4 | {{ if kernel_choice != "custom" and use_default_kernel == "n": }} | ||
| 5 | {{ input type:"choicelist" name:"kernel_choice" gen:"bsp.kernel.kernels" prio:"10" msg:"Please choose the kernel to use in this BSP:" default:"linux-yocto_3.14"}} | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto-dev.bbappend b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto-dev.bbappend new file mode 100644 index 0000000000..2fa6231cbf --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto-dev.bbappend | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-dev": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 8 | |||
| 9 | {{ if need_new_kbranch == "y": }} | ||
| 10 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 11 | |||
| 12 | {{ if need_new_kbranch == "n": }} | ||
| 13 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 14 | |||
| 15 | {{ if need_new_kbranch == "n": }} | ||
| 16 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 17 | |||
| 18 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Would you like SMP support? (y/n)" default:"y"}} | ||
| 19 | {{ if smp == "y": }} | ||
| 20 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 21 | |||
| 22 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 23 | file://{{=machine}}-user-config.cfg \ | ||
| 24 | file://{{=machine}}-user-patches.scc \ | ||
| 25 | file://{{=machine}}-user-features.scc \ | ||
| 26 | " | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend new file mode 100644 index 0000000000..35b0958582 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-rt_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-preempt-rt.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-rt_{{=machine}} ?= "f35992f80c81dc5fa1a97165dfd5cbb84661f7cb" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-rt_{{=machine}} ?= "1b534b2f8bbe9b8a773268cfa30a4850346f6f5f" | ||
| 33 | #LINUX_VERSION = "3.10.9" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend new file mode 100644 index 0000000000..f04dd0cce4 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-tiny_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-tiny.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-tiny_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-tiny_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.10.9" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend new file mode 100644 index 0000000000..471ccbcc3e --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-tiny_3.14": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-tiny.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-tiny_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-tiny_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.14" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto_3.10.bbappend new file mode 100644 index 0000000000..1cfc611949 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto_{{=machine}} ?= "19f7e43b54aef08d58135ed2a897d77b624b320a" | ||
| 32 | #SRCREV_meta_pn-linux-yocto_{{=machine}} ?= "459165c1dd61c4e843c36e6a1abeb30949a20ba7" | ||
| 33 | #LINUX_VERSION = "3.10.9" \ No newline at end of file | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto_3.14.bbappend b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto_3.14.bbappend new file mode 100644 index 0000000000..fbb49edb26 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/i386/recipes-kernel/linux/linux-yocto_3.14.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto_3.14": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.14" \ No newline at end of file | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/layer/COPYING.MIT b/scripts/lib/bsp/substrate/target/arch/layer/COPYING.MIT new file mode 100644 index 0000000000..89de354795 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/layer/COPYING.MIT | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 2 | of this software and associated documentation files (the "Software"), to deal | ||
| 3 | in the Software without restriction, including without limitation the rights | ||
| 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 5 | copies of the Software, and to permit persons to whom the Software is | ||
| 6 | furnished to do so, subject to the following conditions: | ||
| 7 | |||
| 8 | The above copyright notice and this permission notice shall be included in | ||
| 9 | all copies or substantial portions of the Software. | ||
| 10 | |||
| 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| 17 | THE SOFTWARE. | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/layer/README b/scripts/lib/bsp/substrate/target/arch/layer/README new file mode 100644 index 0000000000..943dfc4412 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/layer/README | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | This README file contains information on the contents of the | ||
| 2 | {{=layer_name}} layer. | ||
| 3 | |||
| 4 | Please see the corresponding sections below for details. | ||
| 5 | |||
| 6 | |||
| 7 | Dependencies | ||
| 8 | ============ | ||
| 9 | |||
| 10 | This layer depends on: | ||
| 11 | |||
| 12 | URI: git://git.openembedded.org/bitbake | ||
| 13 | branch: master | ||
| 14 | |||
| 15 | URI: git://git.openembedded.org/openembedded-core | ||
| 16 | layers: meta | ||
| 17 | branch: master | ||
| 18 | |||
| 19 | URI: git://git.yoctoproject.org/xxxx | ||
| 20 | layers: xxxx | ||
| 21 | branch: master | ||
| 22 | |||
| 23 | |||
| 24 | Patches | ||
| 25 | ======= | ||
| 26 | |||
| 27 | Please submit any patches against the {{=layer_name}} layer to the | ||
| 28 | xxxx mailing list (xxxx@zzzz.org) and cc: the maintainer: | ||
| 29 | |||
| 30 | Maintainer: XXX YYYYYY <xxx.yyyyyy@zzzzz.com> | ||
| 31 | |||
| 32 | |||
| 33 | Table of Contents | ||
| 34 | ================= | ||
| 35 | |||
| 36 | I. Adding the {{=layer_name}} layer to your build | ||
| 37 | II. Misc | ||
| 38 | |||
| 39 | |||
| 40 | I. Adding the {{=layer_name}} layer to your build | ||
| 41 | ================================================= | ||
| 42 | |||
| 43 | --- replace with specific instructions for the {{=layer_name}} layer --- | ||
| 44 | |||
| 45 | In order to use this layer, you need to make the build system aware of | ||
| 46 | it. | ||
| 47 | |||
| 48 | Assuming the {{=layer_name}} layer exists at the top-level of your | ||
| 49 | yocto build tree, you can add it to the build system by adding the | ||
| 50 | location of the {{=layer_name}} layer to bblayers.conf, along with any | ||
| 51 | other layers needed. e.g.: | ||
| 52 | |||
| 53 | BBLAYERS ?= " \ | ||
| 54 | /path/to/yocto/meta \ | ||
| 55 | /path/to/yocto/meta-yocto \ | ||
| 56 | /path/to/yocto/meta-yocto-bsp \ | ||
| 57 | /path/to/yocto/meta-{{=layer_name}} \ | ||
| 58 | " | ||
| 59 | |||
| 60 | |||
| 61 | II. Misc | ||
| 62 | ======== | ||
| 63 | |||
| 64 | --- replace with specific information about the {{=layer_name}} layer --- | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/layer/conf/layer.conf b/scripts/lib/bsp/substrate/target/arch/layer/conf/layer.conf new file mode 100644 index 0000000000..bdffe17195 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/layer/conf/layer.conf | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # We have a conf and classes directory, add to BBPATH | ||
| 2 | BBPATH .= ":${LAYERDIR}" | ||
| 3 | |||
| 4 | # We have recipes-* directories, add to BBFILES | ||
| 5 | BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ | ||
| 6 | ${LAYERDIR}/recipes-*/*/*.bbappend" | ||
| 7 | |||
| 8 | BBFILE_COLLECTIONS += "{{=layer_name}}" | ||
| 9 | BBFILE_PATTERN_{{=layer_name}} = "^${LAYERDIR}/" | ||
| 10 | BBFILE_PRIORITY_{{=layer_name}} = "{{=layer_priority}}" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/layer/layer-questions.noinstall b/scripts/lib/bsp/substrate/target/arch/layer/layer-questions.noinstall new file mode 100644 index 0000000000..e2a89c3b5d --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/layer/layer-questions.noinstall | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | {{ input type:"edit" name:"layer_priority" prio:"20" msg:"Please enter the layer priority you'd like to use for the layer:" default:"6"}} | ||
| 2 | |||
| 3 | {{ input type:"boolean" name:"create_example_recipe" prio:"20" msg:"Would you like to have an example recipe created? (y/n)" default:"n"}} | ||
| 4 | |||
| 5 | {{ if create_example_recipe == "y": }} | ||
| 6 | {{ input type:"edit" name:"example_recipe_name" prio:"20" msg:"Please enter the name you'd like to use for your example recipe:" default:"example"}} | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"create_example_bbappend" prio:"20" msg:"Would you like to have an example bbappend file created? (y/n)" default:"n"}} | ||
| 9 | |||
| 10 | {{ if create_example_bbappend == "y": }} | ||
| 11 | {{ input type:"edit" name:"example_bbappend_name" prio:"20" msg:"Please enter the name you'd like to use for your bbappend file:" default:"example"}} | ||
| 12 | |||
| 13 | {{ if create_example_bbappend == "y": }} | ||
| 14 | {{ input type:"edit" name:"example_bbappend_version" prio:"20" msg:"Please enter the version number you'd like to use for your bbappend file (this should match the recipe you're appending to):" default:"0.1"}} | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/layer/recipes-example-bbappend.noinstall b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example-bbappend.noinstall new file mode 100644 index 0000000000..3594e6583c --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example-bbappend.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{ if create_example_bbappend == "y": }} recipes-example-bbappend | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/layer/recipes-example-bbappend/example-bbappend/example-bbappend-version.bbappend b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example-bbappend/example-bbappend/example-bbappend-version.bbappend new file mode 100644 index 0000000000..353133080a --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example-bbappend/example-bbappend/example-bbappend-version.bbappend | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | # yocto-bsp-filename {{=example_bbappend_name}}_{{=example_bbappend_version}}.bbappend | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}-${PV}:" | ||
| 3 | |||
| 4 | # | ||
| 5 | # This .bbappend doesn't yet do anything - replace this text with | ||
| 6 | # modifications to the example_0.1.bb recipe, or whatever recipe it is | ||
| 7 | # that you want to modify with this .bbappend (make sure you change | ||
| 8 | # the recipe name (PN) and version (PV) to match). | ||
| 9 | # | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/layer/recipes-example-bbappend/example-bbappend/example-bbappend-version.noinstall b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example-bbappend/example-bbappend/example-bbappend-version.noinstall new file mode 100644 index 0000000000..46df8a8e04 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example-bbappend/example-bbappend/example-bbappend-version.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{=example_bbappend_name}}-{{=example_bbappend_version}} | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/layer/recipes-example-bbappend/example-bbappend/example-bbappend-version/example.patch b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example-bbappend/example-bbappend/example-bbappend-version/example.patch new file mode 100644 index 0000000000..2000a34da5 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example-bbappend/example-bbappend/example-bbappend-version/example.patch | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | # | ||
| 2 | # This is a non-functional placeholder file, here for example purposes | ||
| 3 | # only. | ||
| 4 | # | ||
| 5 | # If you had a patch for your recipe, you'd put it in this directory | ||
| 6 | # and reference it from your recipe's SRC_URI: | ||
| 7 | # | ||
| 8 | # SRC_URI += "file://example.patch" | ||
| 9 | # | ||
| 10 | # Note that you could also rename the directory containing this patch | ||
| 11 | # to remove the version number or simply rename it 'files'. Doing so | ||
| 12 | # allows you to use the same directory for multiple recipes. | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/layer/recipes-example.noinstall b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example.noinstall new file mode 100644 index 0000000000..b0069b1a5a --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{ if create_example_recipe == "y": }} recipes-example | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/layer/recipes-example/example/example-recipe-0.1.bb b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example/example/example-recipe-0.1.bb new file mode 100644 index 0000000000..ba1ccb16c6 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example/example/example-recipe-0.1.bb | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | # yocto-bsp-filename {{=example_recipe_name}}_0.1.bb | ||
| 2 | # | ||
| 3 | # This file was derived from the 'Hello World!' example recipe in the | ||
| 4 | # Yocto Project Development Manual. | ||
| 5 | # | ||
| 6 | |||
| 7 | DESCRIPTION = "Simple helloworld application" | ||
| 8 | SECTION = "examples" | ||
| 9 | LICENSE = "MIT" | ||
| 10 | LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302" | ||
| 11 | PR = "r0" | ||
| 12 | |||
| 13 | SRC_URI = "file://helloworld.c" | ||
| 14 | |||
| 15 | S = "${WORKDIR}" | ||
| 16 | |||
| 17 | do_compile() { | ||
| 18 | ${CC} helloworld.c -o helloworld | ||
| 19 | } | ||
| 20 | |||
| 21 | do_install() { | ||
| 22 | install -d ${D}${bindir} | ||
| 23 | install -m 0755 helloworld ${D}${bindir} | ||
| 24 | } | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/layer/recipes-example/example/example-recipe-0.1.noinstall b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example/example/example-recipe-0.1.noinstall new file mode 100644 index 0000000000..c319c19c57 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example/example/example-recipe-0.1.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{=example_recipe_name}}-0.1 | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/layer/recipes-example/example/example-recipe-0.1/example.patch b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example/example/example-recipe-0.1/example.patch new file mode 100644 index 0000000000..2000a34da5 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example/example/example-recipe-0.1/example.patch | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | # | ||
| 2 | # This is a non-functional placeholder file, here for example purposes | ||
| 3 | # only. | ||
| 4 | # | ||
| 5 | # If you had a patch for your recipe, you'd put it in this directory | ||
| 6 | # and reference it from your recipe's SRC_URI: | ||
| 7 | # | ||
| 8 | # SRC_URI += "file://example.patch" | ||
| 9 | # | ||
| 10 | # Note that you could also rename the directory containing this patch | ||
| 11 | # to remove the version number or simply rename it 'files'. Doing so | ||
| 12 | # allows you to use the same directory for multiple recipes. | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/layer/recipes-example/example/example-recipe-0.1/helloworld.c b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example/example/example-recipe-0.1/helloworld.c new file mode 100644 index 0000000000..71f2e46b4e --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/layer/recipes-example/example/example-recipe-0.1/helloworld.c | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | |||
| 3 | int main(int argc, char **argv) | ||
| 4 | { | ||
| 5 | printf("Hello World!\n"); | ||
| 6 | |||
| 7 | return 0; | ||
| 8 | } | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/.gitignore b/scripts/lib/bsp/substrate/target/arch/mips/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/.gitignore | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/conf/machine/machine.conf b/scripts/lib/bsp/substrate/target/arch/mips/conf/machine/machine.conf new file mode 100644 index 0000000000..b319d626f4 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/conf/machine/machine.conf | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.conf | ||
| 2 | #@TYPE: Machine | ||
| 3 | #@NAME: {{=machine}} | ||
| 4 | |||
| 5 | #@DESCRIPTION: Machine configuration for {{=machine}} systems | ||
| 6 | |||
| 7 | require conf/machine/include/tune-mips32.inc | ||
| 8 | |||
| 9 | MACHINE_FEATURES = "screen keyboard pci usbhost ext2 ext3 serial" | ||
| 10 | |||
| 11 | KERNEL_IMAGETYPE = "vmlinux" | ||
| 12 | KERNEL_ALT_IMAGETYPE = "vmlinux.bin" | ||
| 13 | KERNEL_IMAGE_STRIP_EXTRA_SECTIONS = ".comment" | ||
| 14 | |||
| 15 | {{ if kernel_choice == "custom": preferred_kernel = "linux-yocto-custom" }} | ||
| 16 | {{ if kernel_choice == "linux-yocto-dev": preferred_kernel = "linux-yocto-dev" }} | ||
| 17 | {{ if kernel_choice == "custom" or kernel_choice == "linux-yocto-dev" : }} | ||
| 18 | PREFERRED_PROVIDER_virtual/kernel ?= "{{=preferred_kernel}}" | ||
| 19 | |||
| 20 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": preferred_kernel = kernel_choice.split('_')[0] }} | ||
| 21 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": preferred_kernel_version = kernel_choice.split('_')[1] }} | ||
| 22 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": }} | ||
| 23 | PREFERRED_PROVIDER_virtual/kernel ?= "{{=preferred_kernel}}" | ||
| 24 | PREFERRED_VERSION_{{=preferred_kernel}} ?= "{{=preferred_kernel_version}}%" | ||
| 25 | |||
| 26 | {{ input type:"boolean" name:"xserver" prio:"50" msg:"Do you need support for X? (y/n)" default:"y" }} | ||
| 27 | {{ if xserver == "y": }} | ||
| 28 | PREFERRED_PROVIDER_virtual/xserver ?= "xserver-xorg" | ||
| 29 | XSERVER ?= "xserver-xorg \ | ||
| 30 | xf86-input-evdev \ | ||
| 31 | xf86-video-fbdev" | ||
| 32 | |||
| 33 | SERIAL_CONSOLE = "115200 ttyS0" | ||
| 34 | USE_VT ?= "0" | ||
| 35 | |||
| 36 | MACHINE_EXTRA_RRECOMMENDS = " kernel-modules" | ||
| 37 | |||
| 38 | IMAGE_FSTYPES ?= "jffs2 tar.bz2" | ||
| 39 | JFFS2_ERASEBLOCK = "0x10000" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files.noinstall b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files.noinstall new file mode 100644 index 0000000000..1e0d92c55c --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{ if kernel_choice != "custom": }} files | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-preempt-rt.scc b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-preempt-rt.scc new file mode 100644 index 0000000000..176190cd2e --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-preempt-rt.scc | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-preempt-rt.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE preempt-rt | ||
| 4 | define KARCH mips | ||
| 5 | |||
| 6 | include {{=map_preempt_rt_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-standard.scc b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-standard.scc new file mode 100644 index 0000000000..f05dd851d2 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-standard.scc | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-standard.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE standard | ||
| 4 | define KARCH mips | ||
| 5 | |||
| 6 | include {{=map_standard_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-tiny.scc b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-tiny.scc new file mode 100644 index 0000000000..f71c775397 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-tiny.scc | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-tiny.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE tiny | ||
| 4 | define KARCH mips | ||
| 5 | |||
| 6 | include {{=map_tiny_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-user-config.cfg b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-user-config.cfg new file mode 100644 index 0000000000..47489e44e9 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-user-config.cfg | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-config.cfg | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-user-features.scc b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-user-features.scc new file mode 100644 index 0000000000..85be26de97 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-user-features.scc | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-features.scc \ No newline at end of file | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-user-patches.scc b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-user-patches.scc new file mode 100644 index 0000000000..97f747fa07 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine-user-patches.scc | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-patches.scc | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine.cfg b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine.cfg new file mode 100644 index 0000000000..2fe476691c --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine.cfg | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.cfg | ||
| 2 | CONFIG_MIPS=y | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine.scc b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine.scc new file mode 100644 index 0000000000..f39dc3edf1 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/files/machine.scc | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.scc | ||
| 2 | kconf hardware {{=machine}}.cfg | ||
| 3 | |||
| 4 | include cfg/usb-mass-storage.scc | ||
| 5 | include cfg/fs/vfat.scc | ||
| 6 | |||
| 7 | kconf hardware {{=machine}}-user-config.cfg | ||
| 8 | include {{=machine}}-user-patches.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/kernel-list.noinstall b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/kernel-list.noinstall new file mode 100644 index 0000000000..a04e6c7852 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/kernel-list.noinstall | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | {{ if kernel_choice != "custom": }} | ||
| 2 | {{ input type:"boolean" name:"use_default_kernel" prio:"10" msg:"Would you like to use the default (3.14) kernel? (y/n)" default:"y"}} | ||
| 3 | |||
| 4 | {{ if kernel_choice != "custom" and use_default_kernel == "n": }} | ||
| 5 | {{ input type:"choicelist" name:"kernel_choice" gen:"bsp.kernel.kernels" prio:"10" msg:"Please choose the kernel to use in this BSP:" default:"linux-yocto_3.14"}} | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto-dev.bbappend b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto-dev.bbappend new file mode 100644 index 0000000000..2fa6231cbf --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto-dev.bbappend | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-dev": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 8 | |||
| 9 | {{ if need_new_kbranch == "y": }} | ||
| 10 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 11 | |||
| 12 | {{ if need_new_kbranch == "n": }} | ||
| 13 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 14 | |||
| 15 | {{ if need_new_kbranch == "n": }} | ||
| 16 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 17 | |||
| 18 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Would you like SMP support? (y/n)" default:"y"}} | ||
| 19 | {{ if smp == "y": }} | ||
| 20 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 21 | |||
| 22 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 23 | file://{{=machine}}-user-config.cfg \ | ||
| 24 | file://{{=machine}}-user-patches.scc \ | ||
| 25 | file://{{=machine}}-user-features.scc \ | ||
| 26 | " | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend new file mode 100644 index 0000000000..35b0958582 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-rt_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-preempt-rt.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-rt_{{=machine}} ?= "f35992f80c81dc5fa1a97165dfd5cbb84661f7cb" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-rt_{{=machine}} ?= "1b534b2f8bbe9b8a773268cfa30a4850346f6f5f" | ||
| 33 | #LINUX_VERSION = "3.10.9" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend new file mode 100644 index 0000000000..f04dd0cce4 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-tiny_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-tiny.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-tiny_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-tiny_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.10.9" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend new file mode 100644 index 0000000000..c7e7989821 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-tiny_3.14": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-tiny.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-tiny_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-tiny_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.14" \ No newline at end of file | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto_3.10.bbappend new file mode 100644 index 0000000000..badb3aa239 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto_{{=machine}} ?= "19f7e43b54aef08d58135ed2a897d77b624b320a" | ||
| 32 | #SRCREV_meta_pn-linux-yocto_{{=machine}} ?= "459165c1dd61c4e843c36e6a1abeb30949a20ba7" | ||
| 33 | #LINUX_VERSION = "3.10.9" \ No newline at end of file | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto_3.14.bbappend b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto_3.14.bbappend new file mode 100644 index 0000000000..1e1cc51315 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/mips/recipes-kernel/linux/linux-yocto_3.14.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto_3.14": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.14" \ No newline at end of file | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/.gitignore b/scripts/lib/bsp/substrate/target/arch/powerpc/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/.gitignore | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/conf/machine/machine.conf b/scripts/lib/bsp/substrate/target/arch/powerpc/conf/machine/machine.conf new file mode 100644 index 0000000000..bee0ec3772 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/conf/machine/machine.conf | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.conf | ||
| 2 | #@TYPE: Machine | ||
| 3 | #@NAME: {{=machine}} | ||
| 4 | |||
| 5 | #@DESCRIPTION: Machine configuration for {{=machine}} systems | ||
| 6 | |||
| 7 | TARGET_FPU = "" | ||
| 8 | |||
| 9 | {{ input type:"choicelist" name:"tunefile" prio:"40" msg:"Which machine tuning would you like to use?" default:"tune_ppce300c3" }} | ||
| 10 | {{ input type:"choice" val:"tune_ppc476" msg:"ppc476 tuning optimizations" }} | ||
| 11 | {{ input type:"choice" val:"tune_ppc603e" msg:"ppc603e tuning optimizations" }} | ||
| 12 | {{ input type:"choice" val:"tune_ppc7400" msg:"ppc7400 tuning optimizations" }} | ||
| 13 | {{ input type:"choice" val:"tune_ppce300c2" msg:"ppce300c2 tuning optimizations" }} | ||
| 14 | {{ input type:"choice" val:"tune_ppce300c3" msg:"ppce300c3 tuning optimizations" }} | ||
| 15 | {{ input type:"choice" val:"tune_ppce500" msg:"ppce500 tuning optimizations" }} | ||
| 16 | {{ input type:"choice" val:"tune_ppce500mc" msg:"ppce500mc tuning optimizations" }} | ||
| 17 | {{ input type:"choice" val:"tune_ppce500v2" msg:"ppce500v2 tuning optimizations" }} | ||
| 18 | {{ input type:"choice" val:"tune_ppce5500" msg:"ppce5500 tuning optimizations" }} | ||
| 19 | {{ input type:"choice" val:"tune_ppce6500" msg:"ppce6500 tuning optimizations" }} | ||
| 20 | {{ if tunefile == "tune_ppc476": }} | ||
| 21 | include conf/machine/include/tune-ppc476.inc | ||
| 22 | {{ if tunefile == "tune_ppc603e": }} | ||
| 23 | include conf/machine/include/tune-ppc603e.inc | ||
| 24 | {{ if tunefile == "tune_ppc7400": }} | ||
| 25 | include conf/machine/include/tune-ppc7400.inc | ||
| 26 | {{ if tunefile == "tune_ppce300c2": }} | ||
| 27 | include conf/machine/include/tune-ppce300c2.inc | ||
| 28 | {{ if tunefile == "tune_ppce300c3": }} | ||
| 29 | include conf/machine/include/tune-ppce300c3.inc | ||
| 30 | {{ if tunefile == "tune_ppce500": }} | ||
| 31 | include conf/machine/include/tune-ppce500.inc | ||
| 32 | {{ if tunefile == "tune_ppce500mc": }} | ||
| 33 | include conf/machine/include/tune-ppce500mc.inc | ||
| 34 | {{ if tunefile == "tune_ppce500v2": }} | ||
| 35 | include conf/machine/include/tune-ppce500v2.inc | ||
| 36 | {{ if tunefile == "tune_ppce5500": }} | ||
| 37 | include conf/machine/include/tune-ppce5500.inc | ||
| 38 | {{ if tunefile == "tune_ppce6500": }} | ||
| 39 | include conf/machine/include/tune-ppce6500.inc | ||
| 40 | |||
| 41 | KERNEL_IMAGETYPE = "uImage" | ||
| 42 | |||
| 43 | EXTRA_IMAGEDEPENDS += "u-boot" | ||
| 44 | UBOOT_MACHINE_{{=machine}} = "MPC8315ERDB_config" | ||
| 45 | |||
| 46 | SERIAL_CONSOLE = "115200 ttyS0" | ||
| 47 | |||
| 48 | MACHINE_FEATURES = "keyboard pci ext2 ext3 serial" | ||
| 49 | |||
| 50 | {{ if kernel_choice == "custom": preferred_kernel = "linux-yocto-custom" }} | ||
| 51 | {{ if kernel_choice == "linux-yocto-dev": preferred_kernel = "linux-yocto-dev" }} | ||
| 52 | {{ if kernel_choice == "custom" or kernel_choice == "linux-yocto-dev" : }} | ||
| 53 | PREFERRED_PROVIDER_virtual/kernel ?= "{{=preferred_kernel}}" | ||
| 54 | |||
| 55 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": preferred_kernel = kernel_choice.split('_')[0] }} | ||
| 56 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": preferred_kernel_version = kernel_choice.split('_')[1] }} | ||
| 57 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": }} | ||
| 58 | PREFERRED_PROVIDER_virtual/kernel ?= "{{=preferred_kernel}}" | ||
| 59 | PREFERRED_VERSION_{{=preferred_kernel}} ?= "{{=preferred_kernel_version}}%" | ||
| 60 | |||
| 61 | {{ input type:"boolean" name:"xserver" prio:"50" msg:"Do you need support for X? (y/n)" default:"y" }} | ||
| 62 | {{ if xserver == "y": }} | ||
| 63 | PREFERRED_PROVIDER_virtual/xserver ?= "xserver-xorg" | ||
| 64 | XSERVER ?= "xserver-xorg \ | ||
| 65 | xf86-input-evdev \ | ||
| 66 | xf86-video-fbdev" | ||
| 67 | |||
| 68 | PREFERRED_VERSION_u-boot ?= "v2013.07%" | ||
| 69 | {{ input type:"edit" name:"uboot_entrypoint" prio:"40" msg:"Please specify a value for UBOOT_ENTRYPOINT:" default:"0x00000000" }} | ||
| 70 | UBOOT_ENTRYPOINT = "{{=uboot_entrypoint}}" | ||
| 71 | |||
| 72 | {{ input type:"edit" name:"kernel_devicetree" prio:"40" msg:"Please specify a [arch/powerpc/boot/dts/xxx] value for KERNEL_DEVICETREE:" default:"mpc8315erdb.dts" }} | ||
| 73 | KERNEL_DEVICETREE = "${S}/arch/powerpc/boot/dts/{{=kernel_devicetree}}" | ||
| 74 | |||
| 75 | MACHINE_EXTRA_RRECOMMENDS = " kernel-modules" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files.noinstall b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files.noinstall new file mode 100644 index 0000000000..1e0d92c55c --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{ if kernel_choice != "custom": }} files | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-preempt-rt.scc b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-preempt-rt.scc new file mode 100644 index 0000000000..40c9267831 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-preempt-rt.scc | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-preempt-rt.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE preempt-rt | ||
| 4 | define KARCH powerpc | ||
| 5 | |||
| 6 | include {{=map_preempt_rt_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-standard.scc b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-standard.scc new file mode 100644 index 0000000000..7a1d35be1e --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-standard.scc | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-standard.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE standard | ||
| 4 | define KARCH powerpc | ||
| 5 | |||
| 6 | include {{=map_standard_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-tiny.scc b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-tiny.scc new file mode 100644 index 0000000000..1bf94b2d05 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-tiny.scc | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-tiny.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE tiny | ||
| 4 | define KARCH powerpc | ||
| 5 | |||
| 6 | include {{=map_tiny_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-user-config.cfg b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-user-config.cfg new file mode 100644 index 0000000000..47489e44e9 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-user-config.cfg | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-config.cfg | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-user-features.scc b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-user-features.scc new file mode 100644 index 0000000000..582759e612 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-user-features.scc | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-features.scc | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-user-patches.scc b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-user-patches.scc new file mode 100644 index 0000000000..97f747fa07 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine-user-patches.scc | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-patches.scc | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine.cfg b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine.cfg new file mode 100644 index 0000000000..5bfe1fe4b0 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine.cfg | |||
| @@ -0,0 +1,164 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.cfg | ||
| 2 | .......................................................................... | ||
| 3 | . WARNING | ||
| 4 | . | ||
| 5 | . This file is a kernel configuration fragment, and not a full kernel | ||
| 6 | . configuration file. The final kernel configuration is made up of | ||
| 7 | . an assembly of processed fragments, each of which is designed to | ||
| 8 | . capture a specific part of the final configuration (e.g. platform | ||
| 9 | . configuration, feature configuration, and board specific hardware | ||
| 10 | . configuration). For more information on kernel configuration, please | ||
| 11 | . consult the product documentation. | ||
| 12 | . | ||
| 13 | .......................................................................... | ||
| 14 | CONFIG_PPC32=y | ||
| 15 | CONFIG_PPC_OF=y | ||
| 16 | CONFIG_PPC_UDBG_16550=y | ||
| 17 | |||
| 18 | # | ||
| 19 | # Processor support | ||
| 20 | # | ||
| 21 | CONFIG_PPC_83xx=y | ||
| 22 | |||
| 23 | # | ||
| 24 | # Platform support | ||
| 25 | # | ||
| 26 | CONFIG_MPC831x_RDB=y | ||
| 27 | # CONFIG_PPC_CHRP is not set | ||
| 28 | # CONFIG_PPC_PMAC is not set | ||
| 29 | |||
| 30 | # | ||
| 31 | # Bus options | ||
| 32 | # | ||
| 33 | CONFIG_PCI=y | ||
| 34 | |||
| 35 | # | ||
| 36 | # Memory Technology Devices (MTD) | ||
| 37 | # | ||
| 38 | CONFIG_MTD=y | ||
| 39 | CONFIG_MTD_PARTITIONS=y | ||
| 40 | CONFIG_MTD_CMDLINE_PARTS=y | ||
| 41 | CONFIG_MTD_OF_PARTS=y | ||
| 42 | |||
| 43 | # | ||
| 44 | # User Modules And Translation Layers | ||
| 45 | # | ||
| 46 | CONFIG_MTD_CHAR=y | ||
| 47 | CONFIG_MTD_BLOCK=y | ||
| 48 | |||
| 49 | # | ||
| 50 | # RAM/ROM/Flash chip drivers | ||
| 51 | # | ||
| 52 | CONFIG_MTD_CFI=y | ||
| 53 | CONFIG_MTD_CFI_AMDSTD=y | ||
| 54 | |||
| 55 | # | ||
| 56 | # Mapping drivers for chip access | ||
| 57 | # | ||
| 58 | CONFIG_MTD_PHYSMAP_OF=y | ||
| 59 | |||
| 60 | # | ||
| 61 | # NAND Flash Device Drivers | ||
| 62 | # | ||
| 63 | CONFIG_MTD_NAND=y | ||
| 64 | |||
| 65 | # | ||
| 66 | # Ethernet (1000 Mbit) | ||
| 67 | # | ||
| 68 | CONFIG_GIANFAR=y | ||
| 69 | |||
| 70 | # | ||
| 71 | # Serial drivers | ||
| 72 | # | ||
| 73 | CONFIG_SERIAL_8250=y | ||
| 74 | CONFIG_SERIAL_8250_CONSOLE=y | ||
| 75 | CONFIG_SERIAL_8250_NR_UARTS=2 | ||
| 76 | |||
| 77 | # | ||
| 78 | # Watchdog Device Drivers | ||
| 79 | # | ||
| 80 | CONFIG_8xxx_WDT=y | ||
| 81 | |||
| 82 | # | ||
| 83 | # I2C support | ||
| 84 | # | ||
| 85 | CONFIG_I2C=y | ||
| 86 | CONFIG_I2C_CHARDEV=y | ||
| 87 | |||
| 88 | # | ||
| 89 | # I2C Hardware Bus support | ||
| 90 | # | ||
| 91 | CONFIG_I2C_MPC=y | ||
| 92 | |||
| 93 | CONFIG_SENSORS_LM75=y | ||
| 94 | |||
| 95 | CONFIG_MISC_DEVICES=y | ||
| 96 | |||
| 97 | # | ||
| 98 | # Miscellaneous I2C Chip support | ||
| 99 | # | ||
| 100 | CONFIG_EEPROM_AT24=y | ||
| 101 | |||
| 102 | # | ||
| 103 | # SPI support | ||
| 104 | # | ||
| 105 | CONFIG_SPI=y | ||
| 106 | # CONFIG_SPI_DEBUG is not set | ||
| 107 | CONFIG_SPI_MASTER=y | ||
| 108 | |||
| 109 | # | ||
| 110 | # SPI Master Controller Drivers | ||
| 111 | # | ||
| 112 | CONFIG_SPI_MPC8xxx=y | ||
| 113 | |||
| 114 | # | ||
| 115 | # SPI Protocol Masters | ||
| 116 | # | ||
| 117 | CONFIG_HWMON=y | ||
| 118 | |||
| 119 | # | ||
| 120 | # SCSI device support | ||
| 121 | # | ||
| 122 | CONFIG_SCSI=y | ||
| 123 | CONFIG_BLK_DEV_SD=y | ||
| 124 | CONFIG_CHR_DEV_SG=y | ||
| 125 | CONFIG_SCSI_LOGGING=y | ||
| 126 | |||
| 127 | CONFIG_ATA=y | ||
| 128 | CONFIG_ATA_VERBOSE_ERROR=y | ||
| 129 | CONFIG_SATA_FSL=y | ||
| 130 | CONFIG_ATA_SFF=y | ||
| 131 | |||
| 132 | # | ||
| 133 | # USB support | ||
| 134 | # | ||
| 135 | CONFIG_USB=m | ||
| 136 | CONFIG_USB_DEVICEFS=y | ||
| 137 | |||
| 138 | # | ||
| 139 | # USB Host Controller Drivers | ||
| 140 | # | ||
| 141 | CONFIG_USB_EHCI_HCD=m | ||
| 142 | CONFIG_USB_EHCI_FSL=y | ||
| 143 | CONFIG_USB_STORAGE=m | ||
| 144 | |||
| 145 | # | ||
| 146 | # Real Time Clock | ||
| 147 | # | ||
| 148 | CONFIG_RTC_CLASS=y | ||
| 149 | |||
| 150 | # | ||
| 151 | # I2C RTC drivers | ||
| 152 | # | ||
| 153 | CONFIG_RTC_DRV_DS1307=y | ||
| 154 | |||
| 155 | CONFIG_KGDB_8250=m | ||
| 156 | |||
| 157 | CONFIG_CRYPTO_DEV_TALITOS=m | ||
| 158 | |||
| 159 | CONFIG_FSL_DMA=y | ||
| 160 | |||
| 161 | CONFIG_MMC=y | ||
| 162 | CONFIG_MMC_SPI=m | ||
| 163 | |||
| 164 | CONFIG_USB_FSL_MPH_DR_OF=y | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine.scc b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine.scc new file mode 100644 index 0000000000..7aac8b0801 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/files/machine.scc | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.scc | ||
| 2 | kconf hardware {{=machine}}.cfg | ||
| 3 | |||
| 4 | include cfg/usb-mass-storage.scc | ||
| 5 | include cfg/fs/vfat.scc | ||
| 6 | |||
| 7 | include cfg/dmaengine.scc | ||
| 8 | |||
| 9 | kconf hardware {{=machine}}-user-config.cfg | ||
| 10 | include {{=machine}}-user-patches.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/kernel-list.noinstall b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/kernel-list.noinstall new file mode 100644 index 0000000000..a04e6c7852 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/kernel-list.noinstall | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | {{ if kernel_choice != "custom": }} | ||
| 2 | {{ input type:"boolean" name:"use_default_kernel" prio:"10" msg:"Would you like to use the default (3.14) kernel? (y/n)" default:"y"}} | ||
| 3 | |||
| 4 | {{ if kernel_choice != "custom" and use_default_kernel == "n": }} | ||
| 5 | {{ input type:"choicelist" name:"kernel_choice" gen:"bsp.kernel.kernels" prio:"10" msg:"Please choose the kernel to use in this BSP:" default:"linux-yocto_3.14"}} | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto-dev.bbappend b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto-dev.bbappend new file mode 100644 index 0000000000..2fa6231cbf --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto-dev.bbappend | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-dev": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 8 | |||
| 9 | {{ if need_new_kbranch == "y": }} | ||
| 10 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 11 | |||
| 12 | {{ if need_new_kbranch == "n": }} | ||
| 13 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 14 | |||
| 15 | {{ if need_new_kbranch == "n": }} | ||
| 16 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 17 | |||
| 18 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Would you like SMP support? (y/n)" default:"y"}} | ||
| 19 | {{ if smp == "y": }} | ||
| 20 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 21 | |||
| 22 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 23 | file://{{=machine}}-user-config.cfg \ | ||
| 24 | file://{{=machine}}-user-patches.scc \ | ||
| 25 | file://{{=machine}}-user-features.scc \ | ||
| 26 | " | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto-rt_3.14.bbappend b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto-rt_3.14.bbappend new file mode 100644 index 0000000000..7a2544617f --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto-rt_3.14.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-rt_3.14": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-preempt-rt.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-rt_{{=machine}} ?= "f35992f80c81dc5fa1a97165dfd5cbb84661f7cb" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-rt_{{=machine}} ?= "1b534b2f8bbe9b8a773268cfa30a4850346f6f5f" | ||
| 33 | #LINUX_VERSION = "3.14" \ No newline at end of file | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend new file mode 100644 index 0000000000..f04dd0cce4 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-tiny_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-tiny.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-tiny_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-tiny_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.10.9" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend new file mode 100644 index 0000000000..471ccbcc3e --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-tiny_3.14": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-tiny.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-tiny_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-tiny_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.14" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto_3.10.bbappend new file mode 100644 index 0000000000..15b4b973c9 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto_{{=machine}} ?= "19f7e43b54aef08d58135ed2a897d77b624b320a" | ||
| 32 | #SRCREV_meta_pn-linux-yocto_{{=machine}} ?= "459165c1dd61c4e843c36e6a1abeb30949a20ba7" | ||
| 33 | #LINUX_VERSION = "3.10.9" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto_3.14.bbappend b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto_3.14.bbappend new file mode 100644 index 0000000000..e688384020 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/powerpc/recipes-kernel/linux/linux-yocto_3.14.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto_3.14": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.14" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/conf/machine/machine.conf b/scripts/lib/bsp/substrate/target/arch/qemu/conf/machine/machine.conf new file mode 100644 index 0000000000..52f1866b5b --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/conf/machine/machine.conf | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.conf | ||
| 2 | #@TYPE: Machine | ||
| 3 | #@NAME: {{=machine}} | ||
| 4 | |||
| 5 | #@DESCRIPTION: Machine configuration for {{=machine}} systems | ||
| 6 | |||
| 7 | {{ if kernel_choice == "custom": preferred_kernel = "linux-yocto-custom" }} | ||
| 8 | {{ if kernel_choice == "linux-yocto-dev": preferred_kernel = "linux-yocto-dev" }} | ||
| 9 | {{ if kernel_choice == "custom" or kernel_choice == "linux-yocto-dev" : }} | ||
| 10 | PREFERRED_PROVIDER_virtual/kernel ?= "{{=preferred_kernel}}" | ||
| 11 | |||
| 12 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": preferred_kernel = kernel_choice.split('_')[0] }} | ||
| 13 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": preferred_kernel_version = kernel_choice.split('_')[1] }} | ||
| 14 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": }} | ||
| 15 | PREFERRED_PROVIDER_virtual/kernel ?= "{{=preferred_kernel}}" | ||
| 16 | PREFERRED_VERSION_{{=preferred_kernel}} ?= "{{=preferred_kernel_version}}%" | ||
| 17 | |||
| 18 | {{ if qemuarch == "i386" or qemuarch == "x86_64": }} | ||
| 19 | PREFERRED_PROVIDER_virtual/xserver ?= "xserver-xorg" | ||
| 20 | PREFERRED_PROVIDER_virtual/libgl ?= "mesa" | ||
| 21 | PREFERRED_PROVIDER_virtual/libgles1 ?= "mesa" | ||
| 22 | PREFERRED_PROVIDER_virtual/libgles2 ?= "mesa" | ||
| 23 | |||
| 24 | {{ input type:"choicelist" name:"qemuarch" prio:"5" msg:"Which qemu architecture would you like to use?" default:"i386" }} | ||
| 25 | {{ input type:"choice" val:"i386" msg:"i386 (32-bit)" }} | ||
| 26 | {{ input type:"choice" val:"x86_64" msg:"x86_64 (64-bit)" }} | ||
| 27 | {{ input type:"choice" val:"arm" msg:"ARM (32-bit)" }} | ||
| 28 | {{ input type:"choice" val:"powerpc" msg:"PowerPC (32-bit)" }} | ||
| 29 | {{ input type:"choice" val:"mips" msg:"MIPS (32-bit)" }} | ||
| 30 | {{ if qemuarch == "i386": }} | ||
| 31 | require conf/machine/include/qemu.inc | ||
| 32 | require conf/machine/include/tune-i586.inc | ||
| 33 | {{ if qemuarch == "x86_64": }} | ||
| 34 | require conf/machine/include/qemu.inc | ||
| 35 | DEFAULTTUNE ?= "core2-64" | ||
| 36 | require conf/machine/include/tune-core2.inc | ||
| 37 | {{ if qemuarch == "arm": }} | ||
| 38 | require conf/machine/include/qemu.inc | ||
| 39 | require conf/machine/include/tune-arm926ejs.inc | ||
| 40 | {{ if qemuarch == "powerpc": }} | ||
| 41 | require conf/machine/include/qemu.inc | ||
| 42 | require conf/machine/include/tune-ppc7400.inc | ||
| 43 | {{ if qemuarch == "mips": }} | ||
| 44 | require conf/machine/include/qemu.inc | ||
| 45 | require conf/machine/include/tune-mips32.inc | ||
| 46 | |||
| 47 | {{ if qemuarch == "i386" or qemuarch == "x86_64": }} | ||
| 48 | MACHINE_FEATURES += "x86" | ||
| 49 | KERNEL_IMAGETYPE = "bzImage" | ||
| 50 | SERIAL_CONSOLE = "115200 ttyS0" | ||
| 51 | XSERVER = "xserver-xorg \ | ||
| 52 | ${@bb.utils.contains('DISTRO_FEATURES', 'opengl', 'mesa-driver-swrast', '', d)} \ | ||
| 53 | xf86-input-vmmouse \ | ||
| 54 | xf86-input-keyboard \ | ||
| 55 | xf86-input-evdev \ | ||
| 56 | xf86-video-vmware" | ||
| 57 | |||
| 58 | {{ if qemuarch == "arm": }} | ||
| 59 | KERNEL_IMAGETYPE = "zImage" | ||
| 60 | SERIAL_CONSOLE = "115200 ttyAMA0" | ||
| 61 | |||
| 62 | {{ if qemuarch == "powerpc": }} | ||
| 63 | KERNEL_IMAGETYPE = "vmlinux" | ||
| 64 | SERIAL_CONSOLE = "115200 ttyS0" | ||
| 65 | |||
| 66 | {{ if qemuarch == "mips": }} | ||
| 67 | KERNEL_IMAGETYPE = "vmlinux" | ||
| 68 | KERNEL_ALT_IMAGETYPE = "vmlinux.bin" | ||
| 69 | SERIAL_CONSOLE = "115200 ttyS0" | ||
| 70 | MACHINE_EXTRA_RRECOMMENDS = " kernel-modules" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-core/init-ifupdown/init-ifupdown/machine.noinstall b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-core/init-ifupdown/init-ifupdown/machine.noinstall new file mode 100644 index 0000000000..b442d02d57 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-core/init-ifupdown/init-ifupdown/machine.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{=machine}} | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-core/init-ifupdown/init-ifupdown/machine/interfaces b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-core/init-ifupdown/init-ifupdown/machine/interfaces new file mode 100644 index 0000000000..16967763e5 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-core/init-ifupdown/init-ifupdown/machine/interfaces | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | # /etc/network/interfaces -- configuration file for ifup(8), ifdown(8) | ||
| 2 | |||
| 3 | # The loopback interface | ||
| 4 | auto lo | ||
| 5 | iface lo inet loopback | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-core/init-ifupdown/init-ifupdown_1.0.bbappend b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-core/init-ifupdown/init-ifupdown_1.0.bbappend new file mode 100644 index 0000000000..72d991c7e5 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-core/init-ifupdown/init-ifupdown_1.0.bbappend | |||
| @@ -0,0 +1 @@ | |||
| FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-graphics/xorg-xserver/xserver-xf86-config/machine.noinstall b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-graphics/xorg-xserver/xserver-xf86-config/machine.noinstall new file mode 100644 index 0000000000..b442d02d57 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-graphics/xorg-xserver/xserver-xf86-config/machine.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{=machine}} | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-graphics/xorg-xserver/xserver-xf86-config/machine/xorg.conf b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-graphics/xorg-xserver/xserver-xf86-config/machine/xorg.conf new file mode 100644 index 0000000000..13519804bc --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-graphics/xorg-xserver/xserver-xf86-config/machine/xorg.conf | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | |||
| 2 | Section "Files" | ||
| 3 | EndSection | ||
| 4 | |||
| 5 | Section "InputDevice" | ||
| 6 | Identifier "Generic Keyboard" | ||
| 7 | Driver "evdev" | ||
| 8 | Option "CoreKeyboard" | ||
| 9 | Option "Device" "/dev/input/by-path/platform-i8042-serio-0-event-kbd" | ||
| 10 | Option "XkbRules" "xorg" | ||
| 11 | Option "XkbModel" "evdev" | ||
| 12 | Option "XkbLayout" "us" | ||
| 13 | EndSection | ||
| 14 | |||
| 15 | Section "InputDevice" | ||
| 16 | Identifier "Configured Mouse" | ||
| 17 | {{ if qemuarch == "arm" or qemuarch == "powerpc" or qemuarch == "mips": }} | ||
| 18 | Driver "mouse" | ||
| 19 | {{ if qemuarch == "i386" or qemuarch == "x86_64": }} | ||
| 20 | Driver "vmmouse" | ||
| 21 | |||
| 22 | Option "CorePointer" | ||
| 23 | Option "Device" "/dev/input/mice" | ||
| 24 | Option "Protocol" "ImPS/2" | ||
| 25 | Option "ZAxisMapping" "4 5" | ||
| 26 | Option "Emulate3Buttons" "true" | ||
| 27 | EndSection | ||
| 28 | |||
| 29 | Section "InputDevice" | ||
| 30 | Identifier "Qemu Tablet" | ||
| 31 | Driver "evdev" | ||
| 32 | Option "CorePointer" | ||
| 33 | Option "Device" "/dev/input/touchscreen0" | ||
| 34 | Option "USB" "on" | ||
| 35 | EndSection | ||
| 36 | |||
| 37 | Section "Device" | ||
| 38 | Identifier "Graphics Controller" | ||
| 39 | {{ if qemuarch == "arm" or qemuarch == "powerpc" or qemuarch == "mips": }} | ||
| 40 | Driver "fbdev" | ||
| 41 | {{ if qemuarch == "i386" or qemuarch == "x86_64": }} | ||
| 42 | Driver "vmware" | ||
| 43 | |||
| 44 | EndSection | ||
| 45 | |||
| 46 | Section "Monitor" | ||
| 47 | Identifier "Generic Monitor" | ||
| 48 | Option "DPMS" | ||
| 49 | # 1024x600 59.85 Hz (CVT) hsync: 37.35 kHz; pclk: 49.00 MHz | ||
| 50 | Modeline "1024x600_60.00" 49.00 1024 1072 1168 1312 600 603 613 624 -hsync +vsync | ||
| 51 | # 640x480 @ 60Hz (Industry standard) hsync: 31.5kHz | ||
| 52 | ModeLine "640x480" 25.2 640 656 752 800 480 490 492 525 -hsync -vsync | ||
| 53 | # 640x480 @ 72Hz (VESA) hsync: 37.9kHz | ||
| 54 | ModeLine "640x480" 31.5 640 664 704 832 480 489 491 520 -hsync -vsync | ||
| 55 | # 640x480 @ 75Hz (VESA) hsync: 37.5kHz | ||
| 56 | ModeLine "640x480" 31.5 640 656 720 840 480 481 484 500 -hsync -vsync | ||
| 57 | # 640x480 @ 85Hz (VESA) hsync: 43.3kHz | ||
| 58 | ModeLine "640x480" 36.0 640 696 752 832 480 481 484 509 -hsync -vsync | ||
| 59 | EndSection | ||
| 60 | |||
| 61 | Section "Screen" | ||
| 62 | Identifier "Default Screen" | ||
| 63 | Device "Graphics Controller" | ||
| 64 | Monitor "Generic Monitor" | ||
| 65 | SubSection "Display" | ||
| 66 | Modes "640x480" | ||
| 67 | EndSubSection | ||
| 68 | EndSection | ||
| 69 | |||
| 70 | Section "ServerLayout" | ||
| 71 | Identifier "Default Layout" | ||
| 72 | Screen "Default Screen" | ||
| 73 | InputDevice "Generic Keyboard" | ||
| 74 | # InputDevice "Configured Mouse" | ||
| 75 | InputDevice "QEMU Tablet" | ||
| 76 | Option "AllowEmptyInput" "no" | ||
| 77 | EndSection | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend new file mode 100644 index 0000000000..72d991c7e5 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend | |||
| @@ -0,0 +1 @@ | |||
| FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files.noinstall b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files.noinstall new file mode 100644 index 0000000000..0fb5283a8d --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{ if kernel_choice != "custom": }} files \ No newline at end of file | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-preempt-rt.scc b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-preempt-rt.scc new file mode 100644 index 0000000000..6aaffb8184 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-preempt-rt.scc | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-preempt-rt.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE preempt-rt | ||
| 4 | define KARCH {{=qemuarch}} | ||
| 5 | |||
| 6 | include {{=map_preempt_rt_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-standard.scc b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-standard.scc new file mode 100644 index 0000000000..695f488064 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-standard.scc | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-standard.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE standard | ||
| 4 | define KARCH {{=qemuarch}} | ||
| 5 | |||
| 6 | {{ if qemuarch == "i386" or qemuarch == "x86_64": }} | ||
| 7 | include {{=map_standard_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 8 | {{ if qemuarch == "arm": }} | ||
| 9 | include bsp/arm-versatile-926ejs/arm-versatile-926ejs-standard | ||
| 10 | {{ if qemuarch == "powerpc": }} | ||
| 11 | include bsp/qemu-ppc32/qemu-ppc32-standard | ||
| 12 | {{ if qemuarch == "mips": }} | ||
| 13 | include bsp/mti-malta32/mti-malta32-be-standard | ||
| 14 | {{ if need_new_kbranch == "y": }} | ||
| 15 | branch {{=machine}} | ||
| 16 | |||
| 17 | include {{=machine}}.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-tiny.scc b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-tiny.scc new file mode 100644 index 0000000000..6c098fed21 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-tiny.scc | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-tiny.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE tiny | ||
| 4 | define KARCH {{=qemuarch}} | ||
| 5 | |||
| 6 | include {{=map_tiny_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-user-config.cfg b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-user-config.cfg new file mode 100644 index 0000000000..69efdcc759 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-user-config.cfg | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-config.cfg \ No newline at end of file | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-user-features.scc b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-user-features.scc new file mode 100644 index 0000000000..582759e612 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-user-features.scc | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-features.scc | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-user-patches.scc b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-user-patches.scc new file mode 100644 index 0000000000..4c59daac46 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine-user-patches.scc | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-patches.scc \ No newline at end of file | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine.cfg b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine.cfg new file mode 100644 index 0000000000..d560784b56 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine.cfg | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}.cfg \ No newline at end of file | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine.scc b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine.scc new file mode 100644 index 0000000000..8301e05f7d --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/files/machine.scc | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.scc | ||
| 2 | kconf hardware {{=machine}}.cfg | ||
| 3 | |||
| 4 | kconf hardware {{=machine}}-user-config.cfg | ||
| 5 | include {{=machine}}-user-patches.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/kernel-list.noinstall b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/kernel-list.noinstall new file mode 100644 index 0000000000..a04e6c7852 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/kernel-list.noinstall | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | {{ if kernel_choice != "custom": }} | ||
| 2 | {{ input type:"boolean" name:"use_default_kernel" prio:"10" msg:"Would you like to use the default (3.14) kernel? (y/n)" default:"y"}} | ||
| 3 | |||
| 4 | {{ if kernel_choice != "custom" and use_default_kernel == "n": }} | ||
| 5 | {{ input type:"choicelist" name:"kernel_choice" gen:"bsp.kernel.kernels" prio:"10" msg:"Please choose the kernel to use in this BSP:" default:"linux-yocto_3.14"}} | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto-dev.bbappend b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto-dev.bbappend new file mode 100644 index 0000000000..a2b86d2568 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto-dev.bbappend | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-dev": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 8 | |||
| 9 | {{ if need_new_kbranch == "y" and qemuarch == "arm": }} | ||
| 10 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base your new BSP branch on:" default:"standard/base" }} | ||
| 11 | |||
| 12 | {{ if need_new_kbranch == "n" and qemuarch == "arm": }} | ||
| 13 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose an existing machine branch to use for this BSP:" default:"standard/arm-versatile-926ejs" }} | ||
| 14 | |||
| 15 | {{ if need_new_kbranch == "y" and qemuarch == "powerpc": }} | ||
| 16 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"powerpc" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 17 | |||
| 18 | {{ if need_new_kbranch == "n" and qemuarch == "powerpc": }} | ||
| 19 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"powerpc" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/qemuppc" }} | ||
| 20 | |||
| 21 | {{ if need_new_kbranch == "y" and qemuarch == "i386": }} | ||
| 22 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc/base" }} | ||
| 23 | |||
| 24 | {{ if need_new_kbranch == "n" and qemuarch == "i386": }} | ||
| 25 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc/base" }} | ||
| 26 | |||
| 27 | {{ if need_new_kbranch == "y" and qemuarch == "x86_64": }} | ||
| 28 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"x86_64" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc-64" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc-64/base" }} | ||
| 29 | |||
| 30 | {{ if need_new_kbranch == "n" and qemuarch == "x86_64": }} | ||
| 31 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"x86_64" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc-64" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc-64/base" }} | ||
| 32 | |||
| 33 | {{ if need_new_kbranch == "y" and qemuarch == "mips": }} | ||
| 34 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"mips" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 35 | |||
| 36 | {{ if need_new_kbranch == "n" and qemuarch == "mips": }} | ||
| 37 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"mips" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/mti-malta32" }} | ||
| 38 | |||
| 39 | {{ if need_new_kbranch == "n": }} | ||
| 40 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 41 | |||
| 42 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Would you like SMP support? (y/n)" default:"y"}} | ||
| 43 | {{ if smp == "y": }} | ||
| 44 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 45 | |||
| 46 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 47 | file://{{=machine}}-user-config.cfg \ | ||
| 48 | file://{{=machine}}-user-patches.scc \ | ||
| 49 | file://{{=machine}}-user-features.scc \ | ||
| 50 | " | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend new file mode 100644 index 0000000000..aa87c28ff8 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-rt_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 8 | |||
| 9 | {{ if need_new_kbranch == "y" and qemuarch == "arm": }} | ||
| 10 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"arm" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 11 | |||
| 12 | {{ if need_new_kbranch == "n" and qemuarch == "arm": }} | ||
| 13 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"arm" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 14 | |||
| 15 | {{ if need_new_kbranch == "y" and qemuarch == "powerpc": }} | ||
| 16 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"powerpc" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 17 | |||
| 18 | {{ if need_new_kbranch == "n" and qemuarch == "powerpc": }} | ||
| 19 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"powerpc" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/qemuppc" }} | ||
| 20 | |||
| 21 | {{ if need_new_kbranch == "y" and qemuarch == "i386": }} | ||
| 22 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 23 | |||
| 24 | {{ if need_new_kbranch == "n" and qemuarch == "i386": }} | ||
| 25 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 26 | |||
| 27 | {{ if need_new_kbranch == "y" and qemuarch == "x86_64": }} | ||
| 28 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"x86_64" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 29 | |||
| 30 | {{ if need_new_kbranch == "n" and qemuarch == "x86_64": }} | ||
| 31 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"x86_64" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 32 | |||
| 33 | {{ if need_new_kbranch == "y" and qemuarch == "mips": }} | ||
| 34 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"mips" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 35 | |||
| 36 | {{ if need_new_kbranch == "n" and qemuarch == "mips": }} | ||
| 37 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"mips" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 38 | |||
| 39 | {{ if need_new_kbranch == "n": }} | ||
| 40 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 41 | |||
| 42 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 43 | {{ if smp == "y": }} | ||
| 44 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 45 | |||
| 46 | SRC_URI += "file://{{=machine}}-preempt-rt.scc \ | ||
| 47 | file://{{=machine}}-user-config.cfg \ | ||
| 48 | file://{{=machine}}-user-patches.scc \ | ||
| 49 | file://{{=machine}}-user-features.scc \ | ||
| 50 | " | ||
| 51 | |||
| 52 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 53 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 54 | #SRCREV_machine_pn-linux-yocto-rt_{{=machine}} ?= "f35992f80c81dc5fa1a97165dfd5cbb84661f7cb" | ||
| 55 | #SRCREV_meta_pn-linux-yocto-rt_{{=machine}} ?= "1b534b2f8bbe9b8a773268cfa30a4850346f6f5f" | ||
| 56 | #LINUX_VERSION = "3.10.35" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend new file mode 100644 index 0000000000..001317ac92 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-tiny_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 8 | |||
| 9 | {{ if need_new_kbranch == "y" and qemuarch == "arm": }} | ||
| 10 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"arm" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 11 | |||
| 12 | {{ if need_new_kbranch == "n" and qemuarch == "arm": }} | ||
| 13 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"arm" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 14 | |||
| 15 | {{ if need_new_kbranch == "y" and qemuarch == "powerpc": }} | ||
| 16 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"powerpc" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 17 | |||
| 18 | {{ if need_new_kbranch == "n" and qemuarch == "powerpc": }} | ||
| 19 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"powerpc" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 20 | |||
| 21 | {{ if need_new_kbranch == "y" and qemuarch == "i386": }} | ||
| 22 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 23 | |||
| 24 | {{ if need_new_kbranch == "n" and qemuarch == "i386": }} | ||
| 25 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/common-pc" }} | ||
| 26 | |||
| 27 | {{ if need_new_kbranch == "y" and qemuarch == "x86_64": }} | ||
| 28 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"x86_64" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 29 | |||
| 30 | {{ if need_new_kbranch == "n" and qemuarch == "x86_64": }} | ||
| 31 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"x86_64" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 32 | |||
| 33 | {{ if need_new_kbranch == "y" and qemuarch == "mips": }} | ||
| 34 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"mips" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 35 | |||
| 36 | {{ if need_new_kbranch == "n" and qemuarch == "mips": }} | ||
| 37 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"mips" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 38 | |||
| 39 | {{ if need_new_kbranch == "n": }} | ||
| 40 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 41 | |||
| 42 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 43 | {{ if smp == "y": }} | ||
| 44 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 45 | |||
| 46 | SRC_URI += "file://{{=machine}}-tiny.scc \ | ||
| 47 | file://{{=machine}}-user-config.cfg \ | ||
| 48 | file://{{=machine}}-user-patches.scc \ | ||
| 49 | file://{{=machine}}-user-features.scc \ | ||
| 50 | " | ||
| 51 | |||
| 52 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 53 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 54 | #SRCREV_machine_pn-linux-yocto-tiny_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 55 | #SRCREV_meta_pn-linux-yocto-tiny_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 56 | #LINUX_VERSION = "3.10.35" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto-tiny_3.4.bbappend b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto-tiny_3.4.bbappend new file mode 100644 index 0000000000..32c96c9df8 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto-tiny_3.4.bbappend | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-tiny_3.4": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 8 | |||
| 9 | {{ if need_new_kbranch == "y" and qemuarch == "arm": }} | ||
| 10 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"arm" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 11 | |||
| 12 | {{ if need_new_kbranch == "n" and qemuarch == "arm": }} | ||
| 13 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"arm" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 14 | |||
| 15 | {{ if need_new_kbranch == "y" and qemuarch == "powerpc": }} | ||
| 16 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"powerpc" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 17 | |||
| 18 | {{ if need_new_kbranch == "n" and qemuarch == "powerpc": }} | ||
| 19 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"powerpc" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 20 | |||
| 21 | {{ if need_new_kbranch == "y" and qemuarch == "i386": }} | ||
| 22 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 23 | |||
| 24 | {{ if need_new_kbranch == "n" and qemuarch == "i386": }} | ||
| 25 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/common-pc" }} | ||
| 26 | |||
| 27 | {{ if need_new_kbranch == "y" and qemuarch == "x86_64": }} | ||
| 28 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"x86_64" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 29 | |||
| 30 | {{ if need_new_kbranch == "n" and qemuarch == "x86_64": }} | ||
| 31 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"x86_64" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 32 | |||
| 33 | {{ if need_new_kbranch == "y" and qemuarch == "mips": }} | ||
| 34 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"mips" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 35 | |||
| 36 | {{ if need_new_kbranch == "n" and qemuarch == "mips": }} | ||
| 37 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"mips" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 38 | |||
| 39 | {{ if need_new_kbranch == "n": }} | ||
| 40 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 41 | |||
| 42 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 43 | {{ if smp == "y": }} | ||
| 44 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 45 | |||
| 46 | SRC_URI += "file://{{=machine}}-tiny.scc \ | ||
| 47 | file://{{=machine}}-user-config.cfg \ | ||
| 48 | file://{{=machine}}-user-patches.scc \ | ||
| 49 | file://{{=machine}}-user-features.scc \ | ||
| 50 | " | ||
| 51 | |||
| 52 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 53 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 54 | #SRCREV_machine_pn-linux-yocto-tiny_{{=machine}} ?= "0143c6ebb4a2d63b241df5f608b19f483f7eb9e0" | ||
| 55 | #SRCREV_meta_pn-linux-yocto-tiny_{{=machine}} ?= "8f55bee2403176a50cc0dd41811aa60fcf07243c" | ||
| 56 | #LINUX_VERSION = "3.14" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto_3.10.bbappend new file mode 100644 index 0000000000..9e3b7fb683 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto_3.10.bbappend | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 8 | |||
| 9 | {{ if need_new_kbranch == "y" and qemuarch == "arm": }} | ||
| 10 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base your new BSP branch on:" default:"standard/base" }} | ||
| 11 | |||
| 12 | {{ if need_new_kbranch == "n" and qemuarch == "arm": }} | ||
| 13 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose an existing machine branch to use for this BSP:" default:"standard/arm-versatile-926ejs" }} | ||
| 14 | |||
| 15 | {{ if need_new_kbranch == "y" and qemuarch == "powerpc": }} | ||
| 16 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"powerpc" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 17 | |||
| 18 | {{ if need_new_kbranch == "n" and qemuarch == "powerpc": }} | ||
| 19 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"powerpc" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/qemuppc" }} | ||
| 20 | |||
| 21 | {{ if need_new_kbranch == "y" and qemuarch == "i386": }} | ||
| 22 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc/base" }} | ||
| 23 | |||
| 24 | {{ if need_new_kbranch == "n" and qemuarch == "i386": }} | ||
| 25 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc/base" }} | ||
| 26 | |||
| 27 | {{ if need_new_kbranch == "y" and qemuarch == "x86_64": }} | ||
| 28 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"x86_64" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc-64" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc-64/base" }} | ||
| 29 | |||
| 30 | {{ if need_new_kbranch == "n" and qemuarch == "x86_64": }} | ||
| 31 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"x86_64" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc-64" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc-64/base" }} | ||
| 32 | |||
| 33 | {{ if need_new_kbranch == "y" and qemuarch == "mips": }} | ||
| 34 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"mips" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 35 | |||
| 36 | {{ if need_new_kbranch == "n" and qemuarch == "mips": }} | ||
| 37 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"mips" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/mti-malta32" }} | ||
| 38 | |||
| 39 | {{ if need_new_kbranch == "n": }} | ||
| 40 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 41 | |||
| 42 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Would you like SMP support? (y/n)" default:"y"}} | ||
| 43 | {{ if smp == "y": }} | ||
| 44 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 45 | |||
| 46 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 47 | file://{{=machine}}-user-config.cfg \ | ||
| 48 | file://{{=machine}}-user-patches.scc \ | ||
| 49 | file://{{=machine}}-user-features.scc \ | ||
| 50 | " | ||
| 51 | |||
| 52 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 53 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 54 | #SRCREV_machine_pn-linux-yocto_{{=machine}} ?= "b170394a475b96ecc92cbc9e4b002bed0a9f69c5" | ||
| 55 | #SRCREV_meta_pn-linux-yocto_{{=machine}} ?= "c2ed0f16fdec628242a682897d5d86df4547cf24" | ||
| 56 | #LINUX_VERSION = "3.10.35" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto_3.14.bbappend b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto_3.14.bbappend new file mode 100644 index 0000000000..e63c897f60 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/qemu/recipes-kernel/linux/linux-yocto_3.14.bbappend | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto_3.14": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 8 | |||
| 9 | {{ if need_new_kbranch == "y" and qemuarch == "arm": }} | ||
| 10 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base your new BSP branch on:" default:"standard/base" }} | ||
| 11 | |||
| 12 | {{ if need_new_kbranch == "n" and qemuarch == "arm": }} | ||
| 13 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose an existing machine branch to use for this BSP:" default:"standard/arm-versatile-926ejs" }} | ||
| 14 | |||
| 15 | {{ if need_new_kbranch == "y" and qemuarch == "powerpc": }} | ||
| 16 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"powerpc" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 17 | |||
| 18 | {{ if need_new_kbranch == "n" and qemuarch == "powerpc": }} | ||
| 19 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"powerpc" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/qemuppc" }} | ||
| 20 | |||
| 21 | {{ if need_new_kbranch == "y" and qemuarch == "i386": }} | ||
| 22 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc/base" }} | ||
| 23 | |||
| 24 | {{ if need_new_kbranch == "n" and qemuarch == "i386": }} | ||
| 25 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc/base" }} | ||
| 26 | |||
| 27 | {{ if need_new_kbranch == "y" and qemuarch == "x86_64": }} | ||
| 28 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"x86_64" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc-64" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc-64/base" }} | ||
| 29 | |||
| 30 | {{ if need_new_kbranch == "n" and qemuarch == "x86_64": }} | ||
| 31 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"x86_64" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc-64" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc-64/base" }} | ||
| 32 | |||
| 33 | {{ if need_new_kbranch == "y" and qemuarch == "mips": }} | ||
| 34 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"mips" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 35 | |||
| 36 | {{ if need_new_kbranch == "n" and qemuarch == "mips": }} | ||
| 37 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"mips" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/mti-malta32" }} | ||
| 38 | |||
| 39 | {{ if need_new_kbranch == "n": }} | ||
| 40 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 41 | |||
| 42 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Would you like SMP support? (y/n)" default:"y"}} | ||
| 43 | {{ if smp == "y": }} | ||
| 44 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 45 | |||
| 46 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 47 | file://{{=machine}}-user-config.cfg \ | ||
| 48 | file://{{=machine}}-user-patches.scc \ | ||
| 49 | file://{{=machine}}-user-features.scc \ | ||
| 50 | " | ||
| 51 | |||
| 52 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 53 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 54 | #SRCREV_machine_pn-linux-yocto_{{=machine}} ?= "0143c6ebb4a2d63b241df5f608b19f483f7eb9e0" | ||
| 55 | #SRCREV_meta_pn-linux-yocto_{{=machine}} ?= "8f55bee2403176a50cc0dd41811aa60fcf07243c" | ||
| 56 | #LINUX_VERSION = "3.14" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/.gitignore b/scripts/lib/bsp/substrate/target/arch/x86_64/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/.gitignore | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/conf/machine/machine.conf b/scripts/lib/bsp/substrate/target/arch/x86_64/conf/machine/machine.conf new file mode 100644 index 0000000000..79b38e6b35 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/conf/machine/machine.conf | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.conf | ||
| 2 | #@TYPE: Machine | ||
| 3 | #@NAME: {{=machine}} | ||
| 4 | |||
| 5 | #@DESCRIPTION: Machine configuration for {{=machine}} systems | ||
| 6 | |||
| 7 | {{ if kernel_choice == "custom": preferred_kernel = "linux-yocto-custom" }} | ||
| 8 | {{ if kernel_choice == "linux-yocto-dev": preferred_kernel = "linux-yocto-dev" }} | ||
| 9 | {{ if kernel_choice == "custom" or kernel_choice == "linux-yocto-dev" : }} | ||
| 10 | PREFERRED_PROVIDER_virtual/kernel ?= "{{=preferred_kernel}}" | ||
| 11 | |||
| 12 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": preferred_kernel = kernel_choice.split('_')[0] }} | ||
| 13 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": preferred_kernel_version = kernel_choice.split('_')[1] }} | ||
| 14 | {{ if kernel_choice != "custom" and kernel_choice != "linux-yocto-dev": }} | ||
| 15 | PREFERRED_PROVIDER_virtual/kernel ?= "{{=preferred_kernel}}" | ||
| 16 | PREFERRED_VERSION_{{=preferred_kernel}} ?= "{{=preferred_kernel_version}}%" | ||
| 17 | |||
| 18 | {{ input type:"choicelist" name:"tunefile" prio:"40" msg:"Which machine tuning would you like to use?" default:"tune_core2" }} | ||
| 19 | {{ input type:"choice" val:"tune_core2" msg:"Core2 tuning optimizations" }} | ||
| 20 | {{ input type:"choice" val:"tune_corei7" msg:"Corei7 tuning optimizations" }} | ||
| 21 | {{ if tunefile == "tune_core2": }} | ||
| 22 | DEFAULTTUNE ?= "core2-64" | ||
| 23 | require conf/machine/include/tune-core2.inc | ||
| 24 | {{ if tunefile == "tune_corei7": }} | ||
| 25 | DEFAULTTUNE ?= "corei7-64" | ||
| 26 | require conf/machine/include/tune-corei7.inc | ||
| 27 | |||
| 28 | require conf/machine/include/x86-base.inc | ||
| 29 | |||
| 30 | MACHINE_FEATURES += "wifi efi pcbios" | ||
| 31 | |||
| 32 | {{ input type:"boolean" name:"xserver" prio:"50" msg:"Do you need support for X? (y/n)" default:"y" }} | ||
| 33 | |||
| 34 | {{ if xserver == "y": }} | ||
| 35 | {{ input type:"choicelist" name:"xserver_choice" prio:"50" msg:"Please select an xserver for this machine:" default:"xserver_i915" }} | ||
| 36 | |||
| 37 | {{ input type:"choice" val:"xserver_vesa" msg:"VESA xserver support" }} | ||
| 38 | {{ input type:"choice" val:"xserver_i915" msg:"i915 xserver support" }} | ||
| 39 | {{ input type:"choice" val:"xserver_i965" msg:"i965 xserver support" }} | ||
| 40 | {{ if xserver == "y": }} | ||
| 41 | XSERVER ?= "${XSERVER_X86_BASE} \ | ||
| 42 | ${XSERVER_X86_EXT} \ | ||
| 43 | {{ if xserver == "y" and xserver_choice == "xserver_vesa": }} | ||
| 44 | ${XSERVER_X86_VESA} \ | ||
| 45 | {{ if xserver == "y" and xserver_choice == "xserver_i915": }} | ||
| 46 | ${XSERVER_X86_I915} \ | ||
| 47 | {{ if xserver == "y" and xserver_choice == "xserver_i965": }} | ||
| 48 | ${XSERVER_X86_I965} \ | ||
| 49 | {{ if xserver == "y": }} | ||
| 50 | " | ||
| 51 | |||
| 52 | MACHINE_EXTRA_RRECOMMENDS += "linux-firmware v86d" | ||
| 53 | |||
| 54 | EXTRA_OECONF_append_pn-matchbox-panel-2 = " --with-battery=acpi" | ||
| 55 | |||
| 56 | {{ if xserver == "y" and xserver_choice == "xserver_vesa": }} | ||
| 57 | APPEND += "video=vesafb vga=0x318" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-graphics/xorg-xserver/xserver-xf86-config/machine.noinstall b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-graphics/xorg-xserver/xserver-xf86-config/machine.noinstall new file mode 100644 index 0000000000..b442d02d57 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-graphics/xorg-xserver/xserver-xf86-config/machine.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{=machine}} | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-graphics/xorg-xserver/xserver-xf86-config/machine/xorg.conf b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-graphics/xorg-xserver/xserver-xf86-config/machine/xorg.conf new file mode 100644 index 0000000000..ac9a0f1bb0 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-graphics/xorg-xserver/xserver-xf86-config/machine/xorg.conf | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{ if xserver == "y": }} this | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend new file mode 100644 index 0000000000..30830031ed --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-graphics/xorg-xserver/xserver-xf86-config_0.1.bbappend | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | # yocto-bsp-filename {{ if xserver == "y": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files.noinstall b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files.noinstall new file mode 100644 index 0000000000..1e0d92c55c --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files.noinstall | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-dirname {{ if kernel_choice != "custom": }} files | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-preempt-rt.scc b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-preempt-rt.scc new file mode 100644 index 0000000000..fd5320ba1e --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-preempt-rt.scc | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-preempt-rt.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE preempt-rt | ||
| 4 | define KARCH x86_64 | ||
| 5 | |||
| 6 | include {{=map_preempt_rt_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
| 11 | |||
| 12 | # default policy for preempt-rt kernels | ||
| 13 | include cfg/usb-mass-storage.scc | ||
| 14 | include cfg/boot-live.scc | ||
| 15 | include features/latencytop/latencytop.scc | ||
| 16 | include features/profiling/profiling.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-standard.scc b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-standard.scc new file mode 100644 index 0000000000..569f967c6a --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-standard.scc | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-standard.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE standard | ||
| 4 | define KARCH x86_64 | ||
| 5 | |||
| 6 | include {{=map_standard_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
| 11 | |||
| 12 | # default policy for standard kernels | ||
| 13 | include cfg/usb-mass-storage.scc | ||
| 14 | include cfg/boot-live.scc | ||
| 15 | include features/latencytop/latencytop.scc | ||
| 16 | include features/profiling/profiling.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-tiny.scc b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-tiny.scc new file mode 100644 index 0000000000..fb21432a4f --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-tiny.scc | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}-tiny.scc | ||
| 2 | define KMACHINE {{=machine}} | ||
| 3 | define KTYPE tiny | ||
| 4 | define KARCH x86_64 | ||
| 5 | |||
| 6 | include {{=map_tiny_kbranch(need_new_kbranch, new_kbranch, existing_kbranch)}} | ||
| 7 | {{ if need_new_kbranch == "y": }} | ||
| 8 | branch {{=machine}} | ||
| 9 | |||
| 10 | include {{=machine}}.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-user-config.cfg b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-user-config.cfg new file mode 100644 index 0000000000..47489e44e9 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-user-config.cfg | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-config.cfg | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-user-features.scc b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-user-features.scc new file mode 100644 index 0000000000..582759e612 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-user-features.scc | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-features.scc | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-user-patches.scc b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-user-patches.scc new file mode 100644 index 0000000000..97f747fa07 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine-user-patches.scc | |||
| @@ -0,0 +1 @@ | |||
| # yocto-bsp-filename {{=machine}}-user-patches.scc | |||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine.cfg b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine.cfg new file mode 100644 index 0000000000..3290ddefe7 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine.cfg | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.cfg | ||
| 2 | CONFIG_PRINTK=y | ||
| 3 | |||
| 4 | # Basic hardware support for the box - network, USB, PCI, sound | ||
| 5 | CONFIG_NETDEVICES=y | ||
| 6 | CONFIG_ATA=y | ||
| 7 | CONFIG_ATA_GENERIC=y | ||
| 8 | CONFIG_ATA_SFF=y | ||
| 9 | CONFIG_PCI=y | ||
| 10 | CONFIG_MMC=y | ||
| 11 | CONFIG_MMC_SDHCI=y | ||
| 12 | CONFIG_USB_SUPPORT=y | ||
| 13 | CONFIG_USB=y | ||
| 14 | CONFIG_USB_ARCH_HAS_EHCI=y | ||
| 15 | CONFIG_R8169=y | ||
| 16 | CONFIG_PATA_SCH=y | ||
| 17 | CONFIG_MMC_SDHCI_PCI=y | ||
| 18 | CONFIG_USB_EHCI_HCD=y | ||
| 19 | CONFIG_PCIEPORTBUS=y | ||
| 20 | CONFIG_NET=y | ||
| 21 | CONFIG_USB_UHCI_HCD=y | ||
| 22 | CONFIG_BLK_DEV_SD=y | ||
| 23 | CONFIG_CHR_DEV_SG=y | ||
| 24 | CONFIG_SOUND=y | ||
| 25 | CONFIG_SND=y | ||
| 26 | CONFIG_SND_HDA_INTEL=y | ||
| 27 | |||
| 28 | # Make sure these are on, otherwise the bootup won't be fun | ||
| 29 | CONFIG_EXT3_FS=y | ||
| 30 | CONFIG_UNIX=y | ||
| 31 | CONFIG_INET=y | ||
| 32 | CONFIG_MODULES=y | ||
| 33 | CONFIG_SHMEM=y | ||
| 34 | CONFIG_TMPFS=y | ||
| 35 | CONFIG_PACKET=y | ||
| 36 | |||
| 37 | CONFIG_I2C=y | ||
| 38 | CONFIG_AGP=y | ||
| 39 | CONFIG_PM=y | ||
| 40 | CONFIG_ACPI=y | ||
| 41 | CONFIG_INPUT=y | ||
| 42 | |||
| 43 | # Needed for booting (and using) USB memory sticks | ||
| 44 | CONFIG_BLK_DEV_LOOP=y | ||
| 45 | CONFIG_NLS_CODEPAGE_437=y | ||
| 46 | CONFIG_NLS_ISO8859_1=y | ||
| 47 | |||
| 48 | CONFIG_RD_GZIP=y | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine.scc b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine.scc new file mode 100644 index 0000000000..9b7c291a8f --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/files/machine.scc | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | # yocto-bsp-filename {{=machine}}.scc | ||
| 2 | kconf hardware {{=machine}}.cfg | ||
| 3 | |||
| 4 | include features/serial/8250.scc | ||
| 5 | {{ if xserver == "y" and xserver_choice == "xserver_vesa": }} | ||
| 6 | include cfg/vesafb.scc | ||
| 7 | {{ if xserver == "y" and xserver_choice == "xserver_i915" or xserver_choice == "xserver_i965": }} | ||
| 8 | include features/i915/i915.scc | ||
| 9 | |||
| 10 | include cfg/usb-mass-storage.scc | ||
| 11 | include features/power/intel.scc | ||
| 12 | |||
| 13 | kconf hardware {{=machine}}-user-config.cfg | ||
| 14 | include {{=machine}}-user-patches.scc | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/kernel-list.noinstall b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/kernel-list.noinstall new file mode 100644 index 0000000000..a04e6c7852 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/kernel-list.noinstall | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | {{ if kernel_choice != "custom": }} | ||
| 2 | {{ input type:"boolean" name:"use_default_kernel" prio:"10" msg:"Would you like to use the default (3.14) kernel? (y/n)" default:"y"}} | ||
| 3 | |||
| 4 | {{ if kernel_choice != "custom" and use_default_kernel == "n": }} | ||
| 5 | {{ input type:"choicelist" name:"kernel_choice" gen:"bsp.kernel.kernels" prio:"10" msg:"Please choose the kernel to use in this BSP:" default:"linux-yocto_3.14"}} | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto-dev.bbappend b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto-dev.bbappend new file mode 100644 index 0000000000..2fa6231cbf --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto-dev.bbappend | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-dev": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 8 | |||
| 9 | {{ if need_new_kbranch == "y": }} | ||
| 10 | {{ input type:"choicelist" name:"new_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 11 | |||
| 12 | {{ if need_new_kbranch == "n": }} | ||
| 13 | {{ input type:"choicelist" name:"existing_kbranch" nameappend:"i386" gen:"bsp.kernel.all_branches" branches_base:"standard" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/base" }} | ||
| 14 | |||
| 15 | {{ if need_new_kbranch == "n": }} | ||
| 16 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 17 | |||
| 18 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Would you like SMP support? (y/n)" default:"y"}} | ||
| 19 | {{ if smp == "y": }} | ||
| 20 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 21 | |||
| 22 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 23 | file://{{=machine}}-user-config.cfg \ | ||
| 24 | file://{{=machine}}-user-patches.scc \ | ||
| 25 | file://{{=machine}}-user-features.scc \ | ||
| 26 | " | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend new file mode 100644 index 0000000000..39bc72d9c4 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto-rt_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-rt_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/preempt-rt" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/preempt-rt/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-preempt-rt.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-rt_{{=machine}} ?= "f35992f80c81dc5fa1a97165dfd5cbb84661f7cb" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-rt_{{=machine}} ?= "1b534b2f8bbe9b8a773268cfa30a4850346f6f5f" | ||
| 33 | #LINUX_VERSION = "3.10.9" \ No newline at end of file | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend new file mode 100644 index 0000000000..f04dd0cce4 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto-tiny_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-tiny_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-tiny.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-tiny_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-tiny_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.10.9" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend new file mode 100644 index 0000000000..471ccbcc3e --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto-tiny_3.14.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto-tiny_3.14": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard/tiny" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/tiny/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-tiny.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto-tiny_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto-tiny_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.14" | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto_3.10.bbappend b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto_3.10.bbappend new file mode 100644 index 0000000000..e21a333fa4 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto_3.10.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto_3.10": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc-64" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc-64/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc-64" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc-64/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto_{{=machine}} ?= "b170394a475b96ecc92cbc9e4b002bed0a9f69c5" | ||
| 32 | #SRCREV_meta_pn-linux-yocto_{{=machine}} ?= "c2ed0f16fdec628242a682897d5d86df4547cf24" | ||
| 33 | #LINUX_VERSION = "3.10.9" \ No newline at end of file | ||
diff --git a/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto_3.14.bbappend b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto_3.14.bbappend new file mode 100644 index 0000000000..ca0b497ff4 --- /dev/null +++ b/scripts/lib/bsp/substrate/target/arch/x86_64/recipes-kernel/linux/linux-yocto_3.14.bbappend | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | # yocto-bsp-filename {{ if kernel_choice == "linux-yocto_3.14": }} this | ||
| 2 | FILESEXTRAPATHS_prepend := "${THISDIR}/files:" | ||
| 3 | |||
| 4 | PR := "${PR}.1" | ||
| 5 | |||
| 6 | COMPATIBLE_MACHINE_{{=machine}} = "{{=machine}}" | ||
| 7 | |||
| 8 | {{ input type:"boolean" name:"need_new_kbranch" prio:"20" msg:"Do you need a new machine branch for this BSP (the alternative is to re-use an existing branch)? [y/n]" default:"y" }} | ||
| 9 | |||
| 10 | {{ if need_new_kbranch == "y": }} | ||
| 11 | {{ input type:"choicelist" name:"new_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc-64" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc-64/base" }} | ||
| 12 | |||
| 13 | {{ if need_new_kbranch == "n": }} | ||
| 14 | {{ input type:"choicelist" name:"existing_kbranch" gen:"bsp.kernel.all_branches" branches_base:"standard:standard/common-pc-64" prio:"20" msg:"Please choose a machine branch to base this BSP on:" default:"standard/common-pc-64/base" }} | ||
| 15 | |||
| 16 | {{ if need_new_kbranch == "n": }} | ||
| 17 | KBRANCH_{{=machine}} = "{{=existing_kbranch}}" | ||
| 18 | |||
| 19 | {{ input type:"boolean" name:"smp" prio:"30" msg:"Do you need SMP support? (y/n)" default:"y"}} | ||
| 20 | {{ if smp == "y": }} | ||
| 21 | KERNEL_FEATURES_append_{{=machine}} += " cfg/smp.scc" | ||
| 22 | |||
| 23 | SRC_URI += "file://{{=machine}}-standard.scc \ | ||
| 24 | file://{{=machine}}-user-config.cfg \ | ||
| 25 | file://{{=machine}}-user-patches.scc \ | ||
| 26 | file://{{=machine}}-user-features.scc \ | ||
| 27 | " | ||
| 28 | |||
| 29 | # uncomment and replace these SRCREVs with the real commit ids once you've had | ||
| 30 | # the appropriate changes committed to the upstream linux-yocto repo | ||
| 31 | #SRCREV_machine_pn-linux-yocto_{{=machine}} ?= "840bb8c059418c4753415df56c9aff1c0d5354c8" | ||
| 32 | #SRCREV_meta_pn-linux-yocto_{{=machine}} ?= "4fd76cc4f33e0afd8f906b1e8f231b6d13b6c993" | ||
| 33 | #LINUX_VERSION = "3.14" | ||
diff --git a/scripts/lib/bsp/tags.py b/scripts/lib/bsp/tags.py new file mode 100644 index 0000000000..3719427884 --- /dev/null +++ b/scripts/lib/bsp/tags.py | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2012, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This module provides a place to define common constants for the | ||
| 22 | # Yocto BSP Tools. | ||
| 23 | # | ||
| 24 | # AUTHORS | ||
| 25 | # Tom Zanussi <tom.zanussi (at] intel.com> | ||
| 26 | # | ||
| 27 | |||
| 28 | OPEN_TAG = "{{" | ||
| 29 | CLOSE_TAG = "}}" | ||
| 30 | ASSIGN_TAG = "{{=" | ||
| 31 | INPUT_TAG = "input" | ||
| 32 | IF_TAG = "if" | ||
| 33 | FILENAME_TAG = "yocto-bsp-filename" | ||
| 34 | DIRNAME_TAG = "yocto-bsp-dirname" | ||
| 35 | |||
| 36 | INDENT_STR = " " | ||
| 37 | |||
| 38 | BLANKLINE_STR = "of.write(\"\\n\")" | ||
| 39 | NORMAL_START = "of.write" | ||
| 40 | OPEN_START = "current_file =" | ||
| 41 | |||
| 42 | INPUT_TYPE_PROPERTY = "type" | ||
| 43 | |||
| 44 | SRC_URI_FILE = "file://" | ||
| 45 | |||
| 46 | GIT_CHECK_URI = "git://git.yoctoproject.org/linux-yocto-dev.git" | ||
| 47 | |||
| 48 | |||
| 49 | |||
diff --git a/scripts/lib/image/__init__.py b/scripts/lib/image/__init__.py new file mode 100644 index 0000000000..1ff814e761 --- /dev/null +++ b/scripts/lib/image/__init__.py | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | # | ||
| 2 | # OpenEmbedded Image tools library | ||
| 3 | # | ||
| 4 | # Copyright (c) 2013, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # AUTHORS | ||
| 21 | # Tom Zanussi <tom.zanussi (at] linux.intel.com> | ||
| 22 | # | ||
diff --git a/scripts/lib/image/canned-wks/directdisk.wks b/scripts/lib/image/canned-wks/directdisk.wks new file mode 100644 index 0000000000..62dcab15ce --- /dev/null +++ b/scripts/lib/image/canned-wks/directdisk.wks | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # short-description: Create a 'pcbios' direct disk image | ||
| 2 | # long-description: Creates a partitioned legacy BIOS disk image that the user | ||
| 3 | # can directly dd to boot media. | ||
| 4 | |||
| 5 | |||
| 6 | part /boot --source bootimg-pcbios --ondisk sda --label boot --active --align 1024 | ||
| 7 | part / --source rootfs --ondisk sda --fstype=ext3 --label platform --align 1024 | ||
| 8 | |||
| 9 | bootloader --timeout=0 --append="rootwait rootfstype=ext3 video=vesafb vga=0x318 console=tty0" | ||
| 10 | |||
diff --git a/scripts/lib/image/canned-wks/mkefidisk.wks b/scripts/lib/image/canned-wks/mkefidisk.wks new file mode 100644 index 0000000000..58d42e61eb --- /dev/null +++ b/scripts/lib/image/canned-wks/mkefidisk.wks | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | # short-description: Create an EFI disk image | ||
| 2 | # long-description: Creates a partitioned EFI disk image that the user | ||
| 3 | # can directly dd to boot media. | ||
| 4 | |||
| 5 | part /boot --source bootimg-efi --sourceparams="loader=grub-efi" --ondisk sda --label msdos --active --align 1024 | ||
| 6 | |||
| 7 | part / --source rootfs --ondisk sda --fstype=ext3 --label platform --align 1024 | ||
| 8 | |||
| 9 | part swap --ondisk sda --size 44 --label swap1 --fstype=swap | ||
| 10 | |||
| 11 | bootloader --timeout=10 --append="rootwait rootfstype=ext3 console=ttyPCH0,115200 console=tty0 vmalloc=256MB snd-hda-intel.enable_msi=0" | ||
diff --git a/scripts/lib/image/canned-wks/mkgummidisk.wks b/scripts/lib/image/canned-wks/mkgummidisk.wks new file mode 100644 index 0000000000..f81cbdfb84 --- /dev/null +++ b/scripts/lib/image/canned-wks/mkgummidisk.wks | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | # short-description: Create an EFI disk image | ||
| 2 | # long-description: Creates a partitioned EFI disk image that the user | ||
| 3 | # can directly dd to boot media. | ||
| 4 | |||
| 5 | part /boot --source bootimg-efi --sourceparams="loader=gummiboot" --ondisk sda --label msdos --active --align 1024 | ||
| 6 | |||
| 7 | part / --source rootfs --ondisk sda --fstype=ext3 --label platform --align 1024 | ||
| 8 | |||
| 9 | part swap --ondisk sda --size 44 --label swap1 --fstype=swap | ||
| 10 | |||
| 11 | bootloader --timeout=10 --append="rootwait rootfstype=ext3 console=ttyPCH0,115200 console=tty0 vmalloc=256MB snd-hda-intel.enable_msi=0" | ||
diff --git a/scripts/lib/image/canned-wks/sdimage-bootpart.wks b/scripts/lib/image/canned-wks/sdimage-bootpart.wks new file mode 100644 index 0000000000..7ffd632f4a --- /dev/null +++ b/scripts/lib/image/canned-wks/sdimage-bootpart.wks | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | # short-description: Create SD card image with a boot partition | ||
| 2 | # long-description: Creates a partitioned SD card image. Boot files | ||
| 3 | # are located in the first vfat partition. | ||
| 4 | |||
| 5 | part /boot --source bootimg-partition --ondisk mmcblk --fstype=vfat --label boot --active --align 4 --size 16 | ||
| 6 | part / --source rootfs --ondisk mmcblk --fstype=ext4 --label root --align 4 | ||
diff --git a/scripts/lib/image/canned-wks/uboot.wks b/scripts/lib/image/canned-wks/uboot.wks new file mode 100644 index 0000000000..7de0572d0f --- /dev/null +++ b/scripts/lib/image/canned-wks/uboot.wks | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | # short-description: . Create a ramdisk image for U-Boot | ||
| 2 | # long-description: Creates a ramdisk image for U-Boot that user | ||
| 3 | # can directly load it into ram through tftp | ||
| 4 | # | ||
| 5 | # part - is a wic command that drive the process of generating a valid file system | ||
| 6 | # - --source=uboot : wic plugin that generates a ramdisk image for U-Boot | ||
| 7 | # - --fstype=ext2 : file system type( ext2 / ext3 / ext 4) | ||
| 8 | # | ||
| 9 | # %packages %end - option to provide a list of packages that will be installed | ||
| 10 | # into rootfs. All packages dependencies will be installed by | ||
| 11 | # package manager(default opkg). | ||
| 12 | |||
| 13 | |||
| 14 | part / --source=uboot --fstype=ext2 --label imageName --align 1024 | ||
| 15 | |||
| 16 | %packages | ||
| 17 | %end | ||
diff --git a/scripts/lib/image/config/wic.conf b/scripts/lib/image/config/wic.conf new file mode 100644 index 0000000000..2de8fa91f7 --- /dev/null +++ b/scripts/lib/image/config/wic.conf | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | [common] | ||
| 2 | ; general settings | ||
| 3 | distro_name = OpenEmbedded | ||
| 4 | |||
| 5 | [create] | ||
| 6 | ; settings for create subcommand | ||
| 7 | ; repourl=http://linux.com/ipk/all http://linux.com/ipk/target http://linux.com/ipk/arch | ||
| 8 | arch=powerpc | ||
| 9 | pkgmgr=opkg | ||
| 10 | install_pkgs=source | ||
diff --git a/scripts/lib/image/engine.py b/scripts/lib/image/engine.py new file mode 100644 index 0000000000..e794545e94 --- /dev/null +++ b/scripts/lib/image/engine.py | |||
| @@ -0,0 +1,279 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2013, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | |||
| 22 | # This module implements the image creation engine used by 'wic' to | ||
| 23 | # create images. The engine parses through the OpenEmbedded kickstart | ||
| 24 | # (wks) file specified and generates images that can then be directly | ||
| 25 | # written onto media. | ||
| 26 | # | ||
| 27 | # AUTHORS | ||
| 28 | # Tom Zanussi <tom.zanussi (at] linux.intel.com> | ||
| 29 | # | ||
| 30 | |||
| 31 | import os | ||
| 32 | import sys | ||
| 33 | from abc import ABCMeta, abstractmethod | ||
| 34 | import shlex | ||
| 35 | import json | ||
| 36 | import subprocess | ||
| 37 | import shutil | ||
| 38 | |||
| 39 | import os, sys, errno | ||
| 40 | from wic import msger, creator | ||
| 41 | from wic.utils import cmdln, misc, errors | ||
| 42 | from wic.conf import configmgr | ||
| 43 | from wic.plugin import pluginmgr | ||
| 44 | from wic.__version__ import VERSION | ||
| 45 | from wic.utils.oe.misc import * | ||
| 46 | |||
| 47 | |||
| 48 | def verify_build_env(): | ||
| 49 | """ | ||
| 50 | Verify that the build environment is sane. | ||
| 51 | |||
| 52 | Returns True if it is, false otherwise | ||
| 53 | """ | ||
| 54 | try: | ||
| 55 | builddir = os.environ["BUILDDIR"] | ||
| 56 | except KeyError: | ||
| 57 | print "BUILDDIR not found, exiting. (Did you forget to source oe-init-build-env?)" | ||
| 58 | sys.exit(1) | ||
| 59 | |||
| 60 | return True | ||
| 61 | |||
| 62 | |||
| 63 | def find_artifacts(image_name): | ||
| 64 | """ | ||
| 65 | Gather the build artifacts for the current image (the image_name | ||
| 66 | e.g. core-image-minimal) for the current MACHINE set in local.conf | ||
| 67 | """ | ||
| 68 | bitbake_env_lines = get_bitbake_env_lines() | ||
| 69 | |||
| 70 | rootfs_dir = kernel_dir = bootimg_dir = native_sysroot = "" | ||
| 71 | |||
| 72 | for line in bitbake_env_lines.split('\n'): | ||
| 73 | if (get_line_val(line, "IMAGE_ROOTFS")): | ||
| 74 | rootfs_dir = get_line_val(line, "IMAGE_ROOTFS") | ||
| 75 | continue | ||
| 76 | if (get_line_val(line, "STAGING_KERNEL_DIR")): | ||
| 77 | kernel_dir = get_line_val(line, "STAGING_KERNEL_DIR") | ||
| 78 | continue | ||
| 79 | if (get_line_val(line, "STAGING_DIR_NATIVE")): | ||
| 80 | native_sysroot = get_line_val(line, "STAGING_DIR_NATIVE") | ||
| 81 | continue | ||
| 82 | |||
| 83 | return (rootfs_dir, kernel_dir, bootimg_dir, native_sysroot) | ||
| 84 | |||
| 85 | |||
| 86 | CANNED_IMAGE_DIR = "lib/image/canned-wks" # relative to scripts | ||
| 87 | SCRIPTS_CANNED_IMAGE_DIR = "scripts/" + CANNED_IMAGE_DIR | ||
| 88 | |||
| 89 | def build_canned_image_list(dl): | ||
| 90 | layers_path = get_bitbake_var("BBLAYERS") | ||
| 91 | canned_wks_layer_dirs = [] | ||
| 92 | |||
| 93 | if layers_path is not None: | ||
| 94 | for layer_path in layers_path.split(): | ||
| 95 | path = os.path.join(layer_path, SCRIPTS_CANNED_IMAGE_DIR) | ||
| 96 | canned_wks_layer_dirs.append(path) | ||
| 97 | |||
| 98 | path = os.path.join(dl, CANNED_IMAGE_DIR) | ||
| 99 | canned_wks_layer_dirs.append(path) | ||
| 100 | |||
| 101 | return canned_wks_layer_dirs | ||
| 102 | |||
| 103 | def find_canned_image(scripts_path, wks_file): | ||
| 104 | """ | ||
| 105 | Find a .wks file with the given name in the canned files dir. | ||
| 106 | |||
| 107 | Return False if not found | ||
| 108 | """ | ||
| 109 | layers_canned_wks_dir = build_canned_image_list(scripts_path) | ||
| 110 | |||
| 111 | for canned_wks_dir in layers_canned_wks_dir: | ||
| 112 | for root, dirs, files in os.walk(canned_wks_dir): | ||
| 113 | for file in files: | ||
| 114 | if file.endswith("~") or file.endswith("#"): | ||
| 115 | continue | ||
| 116 | if file.endswith(".wks") and wks_file + ".wks" == file: | ||
| 117 | fullpath = os.path.join(canned_wks_dir, file) | ||
| 118 | return fullpath | ||
| 119 | return None | ||
| 120 | |||
| 121 | |||
| 122 | def list_canned_images(scripts_path): | ||
| 123 | """ | ||
| 124 | List the .wks files in the canned image dir, minus the extension. | ||
| 125 | """ | ||
| 126 | layers_canned_wks_dir = build_canned_image_list(scripts_path) | ||
| 127 | |||
| 128 | for canned_wks_dir in layers_canned_wks_dir: | ||
| 129 | for root, dirs, files in os.walk(canned_wks_dir): | ||
| 130 | for file in files: | ||
| 131 | if file.endswith("~") or file.endswith("#"): | ||
| 132 | continue | ||
| 133 | if file.endswith(".wks"): | ||
| 134 | fullpath = os.path.join(canned_wks_dir, file) | ||
| 135 | f = open(fullpath, "r") | ||
| 136 | lines = f.readlines() | ||
| 137 | for line in lines: | ||
| 138 | desc = "" | ||
| 139 | idx = line.find("short-description:") | ||
| 140 | if idx != -1: | ||
| 141 | desc = line[idx + len("short-description:"):].strip() | ||
| 142 | break | ||
| 143 | basename = os.path.splitext(file)[0] | ||
| 144 | print " %s\t\t%s" % (basename.ljust(30), desc) | ||
| 145 | |||
| 146 | |||
| 147 | def list_canned_image_help(scripts_path, fullpath): | ||
| 148 | """ | ||
| 149 | List the help and params in the specified canned image. | ||
| 150 | """ | ||
| 151 | f = open(fullpath, "r") | ||
| 152 | lines = f.readlines() | ||
| 153 | found = False | ||
| 154 | for line in lines: | ||
| 155 | if not found: | ||
| 156 | idx = line.find("long-description:") | ||
| 157 | if idx != -1: | ||
| 158 | |||
| 159 | print line[idx + len("long-description:"):].strip() | ||
| 160 | found = True | ||
| 161 | continue | ||
| 162 | if not line.strip(): | ||
| 163 | break | ||
| 164 | idx = line.find("#") | ||
| 165 | if idx != -1: | ||
| 166 | print line[idx + len("#:"):].rstrip() | ||
| 167 | else: | ||
| 168 | break | ||
| 169 | |||
| 170 | |||
| 171 | def list_source_plugins(): | ||
| 172 | """ | ||
| 173 | List the available source plugins i.e. plugins available for --source. | ||
| 174 | """ | ||
| 175 | plugins = pluginmgr.get_source_plugins() | ||
| 176 | |||
| 177 | for plugin in plugins: | ||
| 178 | print " %s" % plugin | ||
| 179 | |||
| 180 | |||
| 181 | def wic_create(args, wks_file, rootfs_dir, bootimg_dir, kernel_dir, | ||
| 182 | native_sysroot, scripts_path, image_output_dir, debug, | ||
| 183 | properties_file, properties=None): | ||
| 184 | """Create image | ||
| 185 | |||
| 186 | wks_file - user-defined OE kickstart file | ||
| 187 | rootfs_dir - absolute path to the build's /rootfs dir | ||
| 188 | bootimg_dir - absolute path to the build's boot artifacts directory | ||
| 189 | kernel_dir - absolute path to the build's kernel directory | ||
| 190 | native_sysroot - absolute path to the build's native sysroots dir | ||
| 191 | scripts_path - absolute path to /scripts dir | ||
| 192 | image_output_dir - dirname to create for image | ||
| 193 | properties_file - use values from this file if nonempty i.e no prompting | ||
| 194 | properties - use values from this string if nonempty i.e no prompting | ||
| 195 | |||
| 196 | Normally, the values for the build artifacts values are determined | ||
| 197 | by 'wic -e' from the output of the 'bitbake -e' command given an | ||
| 198 | image name e.g. 'core-image-minimal' and a given machine set in | ||
| 199 | local.conf. If that's the case, the variables get the following | ||
| 200 | values from the output of 'bitbake -e': | ||
| 201 | |||
| 202 | rootfs_dir: IMAGE_ROOTFS | ||
| 203 | kernel_dir: STAGING_KERNEL_DIR | ||
| 204 | native_sysroot: STAGING_DIR_NATIVE | ||
| 205 | |||
| 206 | In the above case, bootimg_dir remains unset and the | ||
| 207 | plugin-specific image creation code is responsible for finding the | ||
| 208 | bootimg artifacts. | ||
| 209 | |||
| 210 | In the case where the values are passed in explicitly i.e 'wic -e' | ||
| 211 | is not used but rather the individual 'wic' options are used to | ||
| 212 | explicitly specify these values. | ||
| 213 | """ | ||
| 214 | try: | ||
| 215 | oe_builddir = os.environ["BUILDDIR"] | ||
| 216 | except KeyError: | ||
| 217 | print "BUILDDIR not found, exiting. (Did you forget to source oe-init-build-env?)" | ||
| 218 | sys.exit(1) | ||
| 219 | |||
| 220 | direct_args = list() | ||
| 221 | direct_args.insert(0, oe_builddir) | ||
| 222 | direct_args.insert(0, image_output_dir) | ||
| 223 | direct_args.insert(0, wks_file) | ||
| 224 | direct_args.insert(0, rootfs_dir) | ||
| 225 | direct_args.insert(0, bootimg_dir) | ||
| 226 | direct_args.insert(0, kernel_dir) | ||
| 227 | direct_args.insert(0, native_sysroot) | ||
| 228 | direct_args.insert(0, "direct") | ||
| 229 | |||
| 230 | if debug: | ||
| 231 | msger.set_loglevel('debug') | ||
| 232 | |||
| 233 | cr = creator.Creator() | ||
| 234 | |||
| 235 | cr.main(direct_args) | ||
| 236 | |||
| 237 | print "\nThe image(s) were created using OE kickstart file:\n %s" % wks_file | ||
| 238 | |||
| 239 | |||
| 240 | def wic_list(args, scripts_path, properties_file): | ||
| 241 | """ | ||
| 242 | Print the complete list of properties defined by the image, or the | ||
| 243 | possible values for a particular image property. | ||
| 244 | """ | ||
| 245 | if len(args) < 1: | ||
| 246 | return False | ||
| 247 | |||
| 248 | if len(args) == 1: | ||
| 249 | if args[0] == "images": | ||
| 250 | list_canned_images(scripts_path) | ||
| 251 | return True | ||
| 252 | elif args[0] == "source-plugins": | ||
| 253 | list_source_plugins() | ||
| 254 | return True | ||
| 255 | elif args[0] == "properties": | ||
| 256 | return True | ||
| 257 | else: | ||
| 258 | return False | ||
| 259 | |||
| 260 | if len(args) == 2: | ||
| 261 | if args[0] == "properties": | ||
| 262 | wks_file = args[1] | ||
| 263 | print "print properties contained in wks file: %s" % wks_file | ||
| 264 | return True | ||
| 265 | elif args[0] == "property": | ||
| 266 | print "print property values for property: %s" % args[1] | ||
| 267 | return True | ||
| 268 | elif args[1] == "help": | ||
| 269 | wks_file = args[0] | ||
| 270 | fullpath = find_canned_image(scripts_path, wks_file) | ||
| 271 | if not fullpath: | ||
| 272 | print "No image named %s found, exiting. (Use 'wic list images' to list available images, or specify a fully-qualified OE kickstart (.wks) filename)\n" % wks_file | ||
| 273 | sys.exit(1) | ||
| 274 | list_canned_image_help(scripts_path, fullpath) | ||
| 275 | return True | ||
| 276 | else: | ||
| 277 | return False | ||
| 278 | |||
| 279 | return False | ||
diff --git a/scripts/lib/image/help.py b/scripts/lib/image/help.py new file mode 100644 index 0000000000..6b74f57662 --- /dev/null +++ b/scripts/lib/image/help.py | |||
| @@ -0,0 +1,756 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2013, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This module implements some basic help invocation functions along | ||
| 22 | # with the bulk of the help topic text for the OE Core Image Tools. | ||
| 23 | # | ||
| 24 | # AUTHORS | ||
| 25 | # Tom Zanussi <tom.zanussi (at] linux.intel.com> | ||
| 26 | # | ||
| 27 | |||
| 28 | import subprocess | ||
| 29 | import logging | ||
| 30 | |||
| 31 | |||
| 32 | def subcommand_error(args): | ||
| 33 | logging.info("invalid subcommand %s" % args[0]) | ||
| 34 | |||
| 35 | |||
| 36 | def display_help(subcommand, subcommands): | ||
| 37 | """ | ||
| 38 | Display help for subcommand. | ||
| 39 | """ | ||
| 40 | if subcommand not in subcommands: | ||
| 41 | return False | ||
| 42 | |||
| 43 | help = subcommands.get(subcommand, subcommand_error)[2] | ||
| 44 | pager = subprocess.Popen('less', stdin=subprocess.PIPE) | ||
| 45 | pager.communicate(help) | ||
| 46 | |||
| 47 | return True | ||
| 48 | |||
| 49 | |||
| 50 | def wic_help(args, usage_str, subcommands): | ||
| 51 | """ | ||
| 52 | Subcommand help dispatcher. | ||
| 53 | """ | ||
| 54 | if len(args) == 1 or not display_help(args[1], subcommands): | ||
| 55 | print(usage_str) | ||
| 56 | |||
| 57 | |||
| 58 | def invoke_subcommand(args, parser, main_command_usage, subcommands): | ||
| 59 | """ | ||
| 60 | Dispatch to subcommand handler borrowed from combo-layer. | ||
| 61 | Should use argparse, but has to work in 2.6. | ||
| 62 | """ | ||
| 63 | if not args: | ||
| 64 | logging.error("No subcommand specified, exiting") | ||
| 65 | parser.print_help() | ||
| 66 | elif args[0] == "help": | ||
| 67 | wic_help(args, main_command_usage, subcommands) | ||
| 68 | elif args[0] not in subcommands: | ||
| 69 | logging.error("Unsupported subcommand %s, exiting\n" % (args[0])) | ||
| 70 | parser.print_help() | ||
| 71 | else: | ||
| 72 | usage = subcommands.get(args[0], subcommand_error)[1] | ||
| 73 | subcommands.get(args[0], subcommand_error)[0](args[1:], usage) | ||
| 74 | |||
| 75 | |||
| 76 | ## | ||
| 77 | # wic help and usage strings | ||
| 78 | ## | ||
| 79 | |||
| 80 | wic_usage = """ | ||
| 81 | |||
| 82 | Create a customized OpenEmbedded image | ||
| 83 | |||
| 84 | usage: wic [--version] [--help] COMMAND [ARGS] | ||
| 85 | |||
| 86 | Current 'wic' commands are: | ||
| 87 | create Create a new OpenEmbedded image | ||
| 88 | list List available values for options and image properties | ||
| 89 | |||
| 90 | Help topics: | ||
| 91 | overview wic overview - General overview of wic | ||
| 92 | plugins wic plugins - Overview and API | ||
| 93 | kickstart wic kickstart - wic kickstart reference | ||
| 94 | |||
| 95 | See 'wic help <COMMAND or HELP TOPIC>' for more information on a specific | ||
| 96 | command or help topic. | ||
| 97 | """ | ||
| 98 | |||
| 99 | wic_help_usage = """ | ||
| 100 | |||
| 101 | usage: wic help <subcommand> | ||
| 102 | |||
| 103 | This command displays detailed help for the specified subcommand. | ||
| 104 | """ | ||
| 105 | |||
| 106 | wic_create_usage = """ | ||
| 107 | |||
| 108 | Create a new OpenEmbedded image | ||
| 109 | |||
| 110 | usage: wic create <wks file or image name> [-o <DIRNAME> | --outdir <DIRNAME>] | ||
| 111 | [-i <JSON PROPERTY FILE> | --infile <JSON PROPERTY_FILE>] | ||
| 112 | [-e | --image-name] [-s, --skip-build-check] [-D, --debug] | ||
| 113 | [-r, --rootfs-dir] [-b, --bootimg-dir] | ||
| 114 | [-k, --kernel-dir] [-n, --native-sysroot] | ||
| 115 | |||
| 116 | This command creates an OpenEmbedded image based on the 'OE kickstart | ||
| 117 | commands' found in the <wks file>. | ||
| 118 | |||
| 119 | The -o option can be used to place the image in a directory with a | ||
| 120 | different name and location. | ||
| 121 | |||
| 122 | See 'wic help create' for more detailed instructions. | ||
| 123 | """ | ||
| 124 | |||
| 125 | wic_create_help = """ | ||
| 126 | |||
| 127 | NAME | ||
| 128 | wic create - Create a new OpenEmbedded image | ||
| 129 | |||
| 130 | SYNOPSIS | ||
| 131 | wic create <wks file or image name> [-o <DIRNAME> | --outdir <DIRNAME>] | ||
| 132 | [-i <JSON PROPERTY FILE> | --infile <JSON PROPERTY_FILE>] | ||
| 133 | [-e | --image-name] [-s, --skip-build-check] [-D, --debug] | ||
| 134 | [-r, --rootfs-dir] [-b, --bootimg-dir] | ||
| 135 | [-k, --kernel-dir] [-n, --native-sysroot] | ||
| 136 | |||
| 137 | DESCRIPTION | ||
| 138 | This command creates an OpenEmbedded image based on the 'OE | ||
| 139 | kickstart commands' found in the <wks file>. | ||
| 140 | |||
| 141 | In order to do this, wic needs to know the locations of the | ||
| 142 | various build artifacts required to build the image. | ||
| 143 | |||
| 144 | Users can explicitly specify the build artifact locations using | ||
| 145 | the -r, -b, -k, and -n options. See below for details on where | ||
| 146 | the corresponding artifacts are typically found in a normal | ||
| 147 | OpenEmbedded build. | ||
| 148 | |||
| 149 | Alternatively, users can use the -e option to have 'wic' determine | ||
| 150 | those locations for a given image. If the -e option is used, the | ||
| 151 | user needs to have set the appropriate MACHINE variable in | ||
| 152 | local.conf, and have sourced the build environment. | ||
| 153 | |||
| 154 | The -e option is used to specify the name of the image to use the | ||
| 155 | artifacts from e.g. core-image-sato. | ||
| 156 | |||
| 157 | The -r option is used to specify the path to the /rootfs dir to | ||
| 158 | use as the .wks rootfs source. | ||
| 159 | |||
| 160 | The -b option is used to specify the path to the dir containing | ||
| 161 | the boot artifacts (e.g. /EFI or /syslinux dirs) to use as the | ||
| 162 | .wks bootimg source. | ||
| 163 | |||
| 164 | The -k option is used to specify the path to the dir containing | ||
| 165 | the kernel to use in the .wks bootimg. | ||
| 166 | |||
| 167 | The -n option is used to specify the path to the native sysroot | ||
| 168 | containing the tools to use to build the image. | ||
| 169 | |||
| 170 | The -s option is used to skip the build check. The build check is | ||
| 171 | a simple sanity check used to determine whether the user has | ||
| 172 | sourced the build environment so that the -e option can operate | ||
| 173 | correctly. If the user has specified the build artifact locations | ||
| 174 | explicitly, 'wic' assumes the user knows what he or she is doing | ||
| 175 | and skips the build check. | ||
| 176 | |||
| 177 | The -D option is used to display debug information detailing | ||
| 178 | exactly what happens behind the scenes when a create request is | ||
| 179 | fulfilled (or not, as the case may be). It enumerates and | ||
| 180 | displays the command sequence used, and should be included in any | ||
| 181 | bug report describing unexpected results. | ||
| 182 | |||
| 183 | When 'wic -e' is used, the locations for the build artifacts | ||
| 184 | values are determined by 'wic -e' from the output of the 'bitbake | ||
| 185 | -e' command given an image name e.g. 'core-image-minimal' and a | ||
| 186 | given machine set in local.conf. In that case, the image is | ||
| 187 | created as if the following 'bitbake -e' variables were used: | ||
| 188 | |||
| 189 | -r: IMAGE_ROOTFS | ||
| 190 | -k: STAGING_KERNEL_DIR | ||
| 191 | -n: STAGING_DIR_NATIVE | ||
| 192 | -b: empty (plugin-specific handlers must determine this) | ||
| 193 | |||
| 194 | If 'wic -e' is not used, the user needs to select the appropriate | ||
| 195 | value for -b (as well as -r, -k, and -n). | ||
| 196 | |||
| 197 | The -o option can be used to place the image in a directory with a | ||
| 198 | different name and location. | ||
| 199 | |||
| 200 | As an alternative to the wks file, the image-specific properties | ||
| 201 | that define the values that will be used to generate a particular | ||
| 202 | image can be specified on the command-line using the -i option and | ||
| 203 | supplying a JSON object consisting of the set of name:value pairs | ||
| 204 | needed by image creation. | ||
| 205 | |||
| 206 | The set of properties available for a given image type can be | ||
| 207 | listed using the 'wic list' command. | ||
| 208 | """ | ||
| 209 | |||
| 210 | wic_list_usage = """ | ||
| 211 | |||
| 212 | List available OpenEmbedded image properties and values | ||
| 213 | |||
| 214 | usage: wic list images | ||
| 215 | wic list <image> help | ||
| 216 | wic list source-plugins | ||
| 217 | wic list properties | ||
| 218 | wic list properties <wks file> | ||
| 219 | wic list property <property> | ||
| 220 | [-o <JSON PROPERTY FILE> | --outfile <JSON PROPERTY_FILE>] | ||
| 221 | |||
| 222 | This command enumerates the set of available canned images as well as | ||
| 223 | help for those images. It also can be used to enumerate the complete | ||
| 224 | set of possible values for a specified option or property needed by | ||
| 225 | the image creation process. | ||
| 226 | |||
| 227 | The first form enumerates all the available 'canned' images. | ||
| 228 | |||
| 229 | The second form lists the detailed help information for a specific | ||
| 230 | 'canned' image. | ||
| 231 | |||
| 232 | The third form enumerates all the available --sources (source | ||
| 233 | plugins). | ||
| 234 | |||
| 235 | The fourth form enumerates all the possible values that exist and can | ||
| 236 | be specified in an OE kickstart (wks) file. | ||
| 237 | |||
| 238 | The fifth form enumerates all the possible options that exist for the | ||
| 239 | set of properties specified in a given OE kickstart (ks) file. | ||
| 240 | |||
| 241 | The final form enumerates all the possible values that exist and can | ||
| 242 | be specified for any given OE kickstart (wks) property. | ||
| 243 | |||
| 244 | See 'wic help list' for more details. | ||
| 245 | """ | ||
| 246 | |||
| 247 | wic_list_help = """ | ||
| 248 | |||
| 249 | NAME | ||
| 250 | wic list - List available OpenEmbedded image properties and values | ||
| 251 | |||
| 252 | SYNOPSIS | ||
| 253 | wic list images | ||
| 254 | wic list <image> help | ||
| 255 | wic list source-plugins | ||
| 256 | wic list properties | ||
| 257 | wic list properties <wks file> | ||
| 258 | wic list property <property> | ||
| 259 | [-o <JSON PROPERTY FILE> | --outfile <JSON PROPERTY_FILE>] | ||
| 260 | |||
| 261 | DESCRIPTION | ||
| 262 | This command enumerates the complete set of possible values for a | ||
| 263 | specified option or property needed by the image creation process. | ||
| 264 | |||
| 265 | This command enumerates the set of available canned images as well | ||
| 266 | as help for those images. It also can be used to enumerate the | ||
| 267 | complete set of possible values for a specified option or property | ||
| 268 | needed by the image creation process. | ||
| 269 | |||
| 270 | The first form enumerates all the available 'canned' images. | ||
| 271 | These are actually just the set of .wks files that have been moved | ||
| 272 | into the /scripts/lib/image/canned-wks directory). | ||
| 273 | |||
| 274 | The second form lists the detailed help information for a specific | ||
| 275 | 'canned' image. | ||
| 276 | |||
| 277 | The third form enumerates all the available --sources (source | ||
| 278 | plugins). The contents of a given partition are driven by code | ||
| 279 | defined in 'source plugins'. Users specify a specific plugin via | ||
| 280 | the --source parameter of the partition .wks command. Normally | ||
| 281 | this is the 'rootfs' plugin but can be any of the more specialized | ||
| 282 | sources listed by the 'list source-plugins' command. Users can | ||
| 283 | also add their own source plugins - see 'wic help plugins' for | ||
| 284 | details. | ||
| 285 | |||
| 286 | The third form enumerates all the possible values that exist and | ||
| 287 | can be specified in a OE kickstart (wks) file. The output of this | ||
| 288 | can be used by the third form to print the description and | ||
| 289 | possible values of a specific property. | ||
| 290 | |||
| 291 | The fourth form enumerates all the possible options that exist for | ||
| 292 | the set of properties specified in a given OE kickstart (wks) | ||
| 293 | file. If the -o option is specified, the list of properties, in | ||
| 294 | addition to being displayed, will be written to the specified file | ||
| 295 | as a JSON object. In this case, the object will consist of the | ||
| 296 | set of name:value pairs corresponding to the (possibly nested) | ||
| 297 | dictionary of properties defined by the input statements used by | ||
| 298 | the image. Some example output for the 'list <wks file>' command: | ||
| 299 | |||
| 300 | $ wic list test.ks | ||
| 301 | "part" : { | ||
| 302 | "mountpoint" : "/" | ||
| 303 | "fstype" : "ext3" | ||
| 304 | } | ||
| 305 | "part" : { | ||
| 306 | "mountpoint" : "/home" | ||
| 307 | "fstype" : "ext3" | ||
| 308 | "offset" : "10000" | ||
| 309 | } | ||
| 310 | "bootloader" : { | ||
| 311 | "type" : "efi" | ||
| 312 | } | ||
| 313 | . | ||
| 314 | . | ||
| 315 | . | ||
| 316 | |||
| 317 | Each entry in the output consists of the name of the input element | ||
| 318 | e.g. "part", followed by the properties defined for that | ||
| 319 | element enclosed in braces. This information should provide | ||
| 320 | sufficient information to create a complete user interface with. | ||
| 321 | |||
| 322 | The final form enumerates all the possible values that exist and | ||
| 323 | can be specified for any given OE kickstart (wks) property. If | ||
| 324 | the -o option is specified, the list of values for the given | ||
| 325 | property, in addition to being displayed, will be written to the | ||
| 326 | specified file as a JSON object. In this case, the object will | ||
| 327 | consist of the set of name:value pairs corresponding to the array | ||
| 328 | of property values associated with the property. | ||
| 329 | |||
| 330 | $ wic list property part | ||
| 331 | ["mountpoint", "where the partition should be mounted"] | ||
| 332 | ["fstype", "filesytem type of the partition"] | ||
| 333 | ["ext3"] | ||
| 334 | ["ext4"] | ||
| 335 | ["btrfs"] | ||
| 336 | ["swap"] | ||
| 337 | ["offset", "offset of the partition within the image"] | ||
| 338 | |||
| 339 | """ | ||
| 340 | |||
| 341 | wic_plugins_help = """ | ||
| 342 | |||
| 343 | NAME | ||
| 344 | wic plugins - Overview and API | ||
| 345 | |||
| 346 | DESCRIPTION | ||
| 347 | plugins allow wic functionality to be extended and specialized by | ||
| 348 | users. This section documents the plugin interface, which is | ||
| 349 | currently restricted to 'source' plugins. | ||
| 350 | |||
| 351 | 'Source' plugins provide a mechanism to customize various aspects | ||
| 352 | of the image generation process in wic, mainly the contents of | ||
| 353 | partitions. | ||
| 354 | |||
| 355 | Source plugins provide a mechanism for mapping values specified in | ||
| 356 | .wks files using the --source keyword to a particular plugin | ||
| 357 | implementation that populates a corresponding partition. | ||
| 358 | |||
| 359 | A source plugin is created as a subclass of SourcePlugin (see | ||
| 360 | scripts/lib/wic/pluginbase.py) and the plugin file containing it | ||
| 361 | is added to scripts/lib/wic/plugins/source/ to make the plugin | ||
| 362 | implementation available to the wic implementation. | ||
| 363 | |||
| 364 | Source plugins can also be implemented and added by external | ||
| 365 | layers - any plugins found in a scripts/lib/wic/plugins/source/ | ||
| 366 | directory in an external layer will also be made available. | ||
| 367 | |||
| 368 | When the wic implementation needs to invoke a partition-specific | ||
| 369 | implementation, it looks for the plugin that has the same name as | ||
| 370 | the --source param given to that partition. For example, if the | ||
| 371 | partition is set up like this: | ||
| 372 | |||
| 373 | part /boot --source bootimg-pcbios ... | ||
| 374 | |||
| 375 | then the methods defined as class members of the plugin having the | ||
| 376 | matching bootimg-pcbios .name class member would be used. | ||
| 377 | |||
| 378 | To be more concrete, here's the plugin definition that would match | ||
| 379 | a '--source bootimg-pcbios' usage, along with an example method | ||
| 380 | that would be called by the wic implementation when it needed to | ||
| 381 | invoke an implementation-specific partition-preparation function: | ||
| 382 | |||
| 383 | class BootimgPcbiosPlugin(SourcePlugin): | ||
| 384 | name = 'bootimg-pcbios' | ||
| 385 | |||
| 386 | @classmethod | ||
| 387 | def do_prepare_partition(self, part, ...) | ||
| 388 | |||
| 389 | If the subclass itself doesn't implement a function, a 'default' | ||
| 390 | version in a superclass will be located and used, which is why all | ||
| 391 | plugins must be derived from SourcePlugin. | ||
| 392 | |||
| 393 | The SourcePlugin class defines the following methods, which is the | ||
| 394 | current set of methods that can be implemented/overridden by | ||
| 395 | --source plugins. Any methods not implemented by a SourcePlugin | ||
| 396 | subclass inherit the implementations present in the SourcePlugin | ||
| 397 | class (see the SourcePlugin source for details): | ||
| 398 | |||
| 399 | do_prepare_partition() | ||
| 400 | Called to do the actual content population for a | ||
| 401 | partition. In other words, it 'prepares' the final partition | ||
| 402 | image which will be incorporated into the disk image. | ||
| 403 | |||
| 404 | do_configure_partition() | ||
| 405 | Called before do_prepare_partition(), typically used to | ||
| 406 | create custom configuration files for a partition, for | ||
| 407 | example syslinux or grub config files. | ||
| 408 | |||
| 409 | do_install_disk() | ||
| 410 | Called after all partitions have been prepared and assembled | ||
| 411 | into a disk image. This provides a hook to allow | ||
| 412 | finalization of a disk image, for example to write an MBR to | ||
| 413 | it. | ||
| 414 | |||
| 415 | do_stage_partition() | ||
| 416 | Special content-staging hook called before | ||
| 417 | do_prepare_partition(), normally empty. | ||
| 418 | |||
| 419 | Typically, a partition will just use the passed-in | ||
| 420 | parameters, for example the unmodified value of bootimg_dir. | ||
| 421 | In some cases however, things may need to be more tailored. | ||
| 422 | As an example, certain files may additionally need to be | ||
| 423 | take from bootimg_dir + /boot. This hook allows those files | ||
| 424 | to be staged in a customized fashion. Note that | ||
| 425 | get_bitbake_var() allows you to access non-standard | ||
| 426 | variables that you might want to use for these types of | ||
| 427 | situations. | ||
| 428 | |||
| 429 | This scheme is extensible - adding more hooks is a simple matter | ||
| 430 | of adding more plugin methods to SourcePlugin and derived classes. | ||
| 431 | The code that then needs to call the plugin methods uses | ||
| 432 | plugin.get_source_plugin_methods() to find the method(s) needed by | ||
| 433 | the call; this is done by filling up a dict with keys containing | ||
| 434 | the method names of interest - on success, these will be filled in | ||
| 435 | with the actual methods. Please see the implementation for | ||
| 436 | examples and details. | ||
| 437 | """ | ||
| 438 | |||
| 439 | wic_overview_help = """ | ||
| 440 | |||
| 441 | NAME | ||
| 442 | wic overview - General overview of wic | ||
| 443 | |||
| 444 | DESCRIPTION | ||
| 445 | The 'wic' command generates partitioned images from existing | ||
| 446 | OpenEmbedded build artifacts. Image generation is driven by | ||
| 447 | partitioning commands contained in an 'Openembedded kickstart' | ||
| 448 | (.wks) file (see 'wic help kickstart') specified either directly | ||
| 449 | on the command-line or as one of a selection of canned .wks files | ||
| 450 | (see 'wic list images'). When applied to a given set of build | ||
| 451 | artifacts, the result is an image or set of images that can be | ||
| 452 | directly written onto media and used on a particular system. | ||
| 453 | |||
| 454 | The 'wic' command and the infrastructure it's based on is by | ||
| 455 | definition incomplete - its purpose is to allow the generation of | ||
| 456 | customized images, and as such was designed to be completely | ||
| 457 | extensible via a plugin interface (see 'wic help plugins'). | ||
| 458 | |||
| 459 | Background and Motivation | ||
| 460 | |||
| 461 | wic is meant to be a completely independent standalone utility | ||
| 462 | that initially provides easier-to-use and more flexible | ||
| 463 | replacements for a couple bits of existing functionality in | ||
| 464 | oe-core: directdisk.bbclass and mkefidisk.sh. The difference | ||
| 465 | between wic and those examples is that with wic the functionality | ||
| 466 | of those scripts is implemented by a general-purpose partitioning | ||
| 467 | 'language' based on Redhat kickstart syntax). | ||
| 468 | |||
| 469 | The initial motivation and design considerations that lead to the | ||
| 470 | current tool are described exhaustively in Yocto Bug #3847 | ||
| 471 | (https://bugzilla.yoctoproject.org/show_bug.cgi?id=3847). | ||
| 472 | |||
| 473 | Implementation and Examples | ||
| 474 | |||
| 475 | wic can be used in two different modes, depending on how much | ||
| 476 | control the user needs in specifying the Openembedded build | ||
| 477 | artifacts that will be used in creating the image: 'raw' and | ||
| 478 | 'cooked'. | ||
| 479 | |||
| 480 | If used in 'raw' mode, artifacts are explicitly specified via | ||
| 481 | command-line arguments (see example below). | ||
| 482 | |||
| 483 | The more easily usable 'cooked' mode uses the current MACHINE | ||
| 484 | setting and a specified image name to automatically locate the | ||
| 485 | artifacts used to create the image. | ||
| 486 | |||
| 487 | OE kickstart files (.wks) can of course be specified directly on | ||
| 488 | the command-line, but the user can also choose from a set of | ||
| 489 | 'canned' .wks files available via the 'wic list images' command | ||
| 490 | (example below). | ||
| 491 | |||
| 492 | In any case, the prerequisite for generating any image is to have | ||
| 493 | the build artifacts already available. The below examples assume | ||
| 494 | the user has already build a 'core-image-minimal' for a specific | ||
| 495 | machine (future versions won't require this redundant step, but | ||
| 496 | for now that's typically how build artifacts get generated). | ||
| 497 | |||
| 498 | The other prerequisite is to source the build environment: | ||
| 499 | |||
| 500 | $ source oe-init-build-env | ||
| 501 | |||
| 502 | To start out with, we'll generate an image from one of the canned | ||
| 503 | .wks files. The following generates a list of availailable | ||
| 504 | images: | ||
| 505 | |||
| 506 | $ wic list images | ||
| 507 | mkefidisk Create an EFI disk image | ||
| 508 | directdisk Create a 'pcbios' direct disk image | ||
| 509 | |||
| 510 | You can get more information about any of the available images by | ||
| 511 | typing 'wic list xxx help', where 'xxx' is one of the image names: | ||
| 512 | |||
| 513 | $ wic list mkefidisk help | ||
| 514 | |||
| 515 | Creates a partitioned EFI disk image that the user can directly dd | ||
| 516 | to boot media. | ||
| 517 | |||
| 518 | At any time, you can get help on the 'wic' command or any | ||
| 519 | subcommand (currently 'list' and 'create'). For instance, to get | ||
| 520 | the description of 'wic create' command and its parameters: | ||
| 521 | |||
| 522 | $ wic create | ||
| 523 | |||
| 524 | Usage: | ||
| 525 | |||
| 526 | Create a new OpenEmbedded image | ||
| 527 | |||
| 528 | usage: wic create <wks file or image name> [-o <DIRNAME> | ...] | ||
| 529 | [-i <JSON PROPERTY FILE> | --infile <JSON PROPERTY_FILE>] | ||
| 530 | [-e | --image-name] [-s, --skip-build-check] [-D, --debug] | ||
| 531 | [-r, --rootfs-dir] [-b, --bootimg-dir] | ||
| 532 | [-k, --kernel-dir] [-n, --native-sysroot] | ||
| 533 | |||
| 534 | This command creates an OpenEmbedded image based on the 'OE | ||
| 535 | kickstart commands' found in the <wks file>. | ||
| 536 | |||
| 537 | The -o option can be used to place the image in a directory | ||
| 538 | with a different name and location. | ||
| 539 | |||
| 540 | See 'wic help create' for more detailed instructions. | ||
| 541 | ... | ||
| 542 | |||
| 543 | As mentioned in the command, you can get even more detailed | ||
| 544 | information by adding 'help' to the above: | ||
| 545 | |||
| 546 | $ wic help create | ||
| 547 | |||
| 548 | So, the easiest way to create an image is to use the -e option | ||
| 549 | with a canned .wks file. To use the -e option, you need to | ||
| 550 | specify the image used to generate the artifacts and you actually | ||
| 551 | need to have the MACHINE used to build them specified in your | ||
| 552 | local.conf (these requirements aren't necessary if you aren't | ||
| 553 | using the -e options.) Below, we generate a directdisk image, | ||
| 554 | pointing the process at the core-image-minimal artifacts for the | ||
| 555 | current MACHINE: | ||
| 556 | |||
| 557 | $ wic create directdisk -e core-image-minimal | ||
| 558 | |||
| 559 | Checking basic build environment... | ||
| 560 | Done. | ||
| 561 | |||
| 562 | Creating image(s)... | ||
| 563 | |||
| 564 | Info: The new image(s) can be found here: | ||
| 565 | /var/tmp/wic/build/directdisk-201309252350-sda.direct | ||
| 566 | |||
| 567 | The following build artifacts were used to create the image(s): | ||
| 568 | |||
| 569 | ROOTFS_DIR: ... | ||
| 570 | BOOTIMG_DIR: ... | ||
| 571 | KERNEL_DIR: ... | ||
| 572 | NATIVE_SYSROOT: ... | ||
| 573 | |||
| 574 | The image(s) were created using OE kickstart file: | ||
| 575 | .../scripts/lib/image/canned-wks/directdisk.wks | ||
| 576 | |||
| 577 | The output shows the name and location of the image created, and | ||
| 578 | so that you know exactly what was used to generate the image, each | ||
| 579 | of the artifacts and the kickstart file used. | ||
| 580 | |||
| 581 | Similarly, you can create a 'mkefidisk' image in the same way | ||
| 582 | (notice that this example uses a different machine - because it's | ||
| 583 | using the -e option, you need to change the MACHINE in your | ||
| 584 | local.conf): | ||
| 585 | |||
| 586 | $ wic create mkefidisk -e core-image-minimal | ||
| 587 | Checking basic build environment... | ||
| 588 | Done. | ||
| 589 | |||
| 590 | Creating image(s)... | ||
| 591 | |||
| 592 | Info: The new image(s) can be found here: | ||
| 593 | /var/tmp/wic/build/mkefidisk-201309260027-sda.direct | ||
| 594 | |||
| 595 | ... | ||
| 596 | |||
| 597 | Here's an example that doesn't take the easy way out and manually | ||
| 598 | specifies each build artifact, along with a non-canned .wks file, | ||
| 599 | and also uses the -o option to have wic create the output | ||
| 600 | somewhere other than the default /var/tmp/wic: | ||
| 601 | |||
| 602 | $ wic create ~/test.wks -o /home/trz/testwic --rootfs-dir | ||
| 603 | /home/trz/yocto/build/tmp/work/crownbay/core-image-minimal/1.0-r0/rootfs | ||
| 604 | --bootimg-dir /home/trz/yocto/build/tmp/sysroots/crownbay/usr/share | ||
| 605 | --kernel-dir /home/trz/yocto/build/tmp/sysroots/crownbay/usr/src/kernel | ||
| 606 | --native-sysroot /home/trz/yocto/build/tmp/sysroots/x86_64-linux | ||
| 607 | |||
| 608 | Creating image(s)... | ||
| 609 | |||
| 610 | Info: The new image(s) can be found here: | ||
| 611 | /home/trz/testwic/build/test-201309260032-sda.direct | ||
| 612 | |||
| 613 | ... | ||
| 614 | |||
| 615 | Finally, here's an example of the actual partition language | ||
| 616 | commands used to generate the mkefidisk image i.e. these are the | ||
| 617 | contents of the mkefidisk.wks OE kickstart file: | ||
| 618 | |||
| 619 | # short-description: Create an EFI disk image | ||
| 620 | # long-description: Creates a partitioned EFI disk image that the user | ||
| 621 | # can directly dd to boot media. | ||
| 622 | |||
| 623 | part /boot --source bootimg-efi --ondisk sda --fstype=efi --active | ||
| 624 | |||
| 625 | part / --source rootfs --ondisk sda --fstype=ext3 --label platform | ||
| 626 | |||
| 627 | part swap --ondisk sda --size 44 --label swap1 --fstype=swap | ||
| 628 | |||
| 629 | bootloader --timeout=10 --append="rootwait console=ttyPCH0,115200" | ||
| 630 | |||
| 631 | You can get a complete listing and description of all the | ||
| 632 | kickstart commands available for use in .wks files from 'wic help | ||
| 633 | kickstart'. | ||
| 634 | """ | ||
| 635 | |||
| 636 | wic_kickstart_help = """ | ||
| 637 | |||
| 638 | NAME | ||
| 639 | wic kickstart - wic kickstart reference | ||
| 640 | |||
| 641 | DESCRIPTION | ||
| 642 | This section provides the definitive reference to the wic | ||
| 643 | kickstart language. It also provides documentation on the list of | ||
| 644 | --source plugins available for use from the 'part' command (see | ||
| 645 | the 'Platform-specific Plugins' section below). | ||
| 646 | |||
| 647 | The current wic implementation supports only the basic kickstart | ||
| 648 | partitioning commands: partition (or part for short) and | ||
| 649 | bootloader. | ||
| 650 | |||
| 651 | The following is a listing of the commands, their syntax, and | ||
| 652 | meanings. The commands are based on the Fedora kickstart | ||
| 653 | documentation but with modifications to reflect wic capabilities. | ||
| 654 | |||
| 655 | http://fedoraproject.org/wiki/Anaconda/Kickstart#part_or_partition | ||
| 656 | http://fedoraproject.org/wiki/Anaconda/Kickstart#bootloader | ||
| 657 | |||
| 658 | Commands | ||
| 659 | |||
| 660 | * 'part' or 'partition' | ||
| 661 | |||
| 662 | This command creates a partition on the system and uses the | ||
| 663 | following syntax: | ||
| 664 | |||
| 665 | part <mountpoint> | ||
| 666 | |||
| 667 | The <mountpoint> is where the partition will be mounted and | ||
| 668 | must take of one of the following forms: | ||
| 669 | |||
| 670 | /<path>: For example: /, /usr, or /home | ||
| 671 | |||
| 672 | swap: The partition will be used as swap space. | ||
| 673 | |||
| 674 | The following are supported 'part' options: | ||
| 675 | |||
| 676 | --size: The minimum partition size in MBytes. Specify an | ||
| 677 | integer value such as 500. Do not append the number | ||
| 678 | with "MB". You do not need this option if you use | ||
| 679 | --source. | ||
| 680 | |||
| 681 | --source: This option is a wic-specific option that names the | ||
| 682 | source of the data that will populate the | ||
| 683 | partition. The most common value for this option | ||
| 684 | is 'rootfs', but can be any value which maps to a | ||
| 685 | valid 'source plugin' (see 'wic help plugins'). | ||
| 686 | |||
| 687 | If '--source rootfs' is used, it tells the wic | ||
| 688 | command to create a partition as large as needed | ||
| 689 | and to fill it with the contents of the root | ||
| 690 | filesystem pointed to by the '-r' wic command-line | ||
| 691 | option (or the equivalent rootfs derived from the | ||
| 692 | '-e' command-line option). The filesystem type | ||
| 693 | that will be used to create the partition is driven | ||
| 694 | by the value of the --fstype option specified for | ||
| 695 | the partition (see --fstype below). | ||
| 696 | |||
| 697 | If --source <plugin-name>' is used, it tells the | ||
| 698 | wic command to create a partition as large as | ||
| 699 | needed and to fill with the contents of the | ||
| 700 | partition that will be generated by the specified | ||
| 701 | plugin name using the data pointed to by the '-r' | ||
| 702 | wic command-line option (or the equivalent rootfs | ||
| 703 | derived from the '-e' command-line option). | ||
| 704 | Exactly what those contents and filesystem type end | ||
| 705 | up being are dependent on the given plugin | ||
| 706 | implementation. | ||
| 707 | |||
| 708 | --ondisk or --ondrive: Forces the partition to be created on | ||
| 709 | a particular disk. | ||
| 710 | |||
| 711 | --fstype: Sets the file system type for the partition. These | ||
| 712 | apply to partitions created using '--source rootfs' (see | ||
| 713 | --source above). Valid values are: | ||
| 714 | |||
| 715 | ext2 | ||
| 716 | ext3 | ||
| 717 | ext4 | ||
| 718 | btrfs | ||
| 719 | squashfs | ||
| 720 | swap | ||
| 721 | |||
| 722 | --fsoptions: Specifies a free-form string of options to be | ||
| 723 | used when mounting the filesystem. This string | ||
| 724 | will be copied into the /etc/fstab file of the | ||
| 725 | installed system and should be enclosed in | ||
| 726 | quotes. If not specified, the default string is | ||
| 727 | "defaults". | ||
| 728 | |||
| 729 | --label label: Specifies the label to give to the filesystem | ||
| 730 | to be made on the partition. If the given | ||
| 731 | label is already in use by another filesystem, | ||
| 732 | a new label is created for the partition. | ||
| 733 | |||
| 734 | --active: Marks the partition as active. | ||
| 735 | |||
| 736 | --align (in KBytes): This option is specific to wic and says | ||
| 737 | to start a partition on an x KBytes | ||
| 738 | boundary. | ||
| 739 | |||
| 740 | * bootloader | ||
| 741 | |||
| 742 | This command allows the user to specify various bootloader | ||
| 743 | options. The following are supported 'bootloader' options: | ||
| 744 | |||
| 745 | --timeout: Specifies the number of seconds before the | ||
| 746 | bootloader times out and boots the default option. | ||
| 747 | |||
| 748 | --append: Specifies kernel parameters. These will be added to | ||
| 749 | bootloader command-line - for example, the syslinux | ||
| 750 | APPEND or grub kernel command line. | ||
| 751 | |||
| 752 | Note that bootloader functionality and boot partitions are | ||
| 753 | implemented by the various --source plugins that implement | ||
| 754 | bootloader functionality; the bootloader command essentially | ||
| 755 | provides a means of modifying bootloader configuration. | ||
| 756 | """ | ||
diff --git a/scripts/lib/scriptpath.py b/scripts/lib/scriptpath.py new file mode 100644 index 0000000000..d00317e18d --- /dev/null +++ b/scripts/lib/scriptpath.py | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | # Path utility functions for OE python scripts | ||
| 2 | # | ||
| 3 | # Copyright (C) 2012-2014 Intel Corporation | ||
| 4 | # Copyright (C) 2011 Mentor Graphics Corporation | ||
| 5 | # | ||
| 6 | # This program is free software; you can redistribute it and/or modify | ||
| 7 | # it under the terms of the GNU General Public License version 2 as | ||
| 8 | # published by the Free Software Foundation. | ||
| 9 | # | ||
| 10 | # This program is distributed in the hope that it will be useful, | ||
| 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | # GNU General Public License for more details. | ||
| 14 | # | ||
| 15 | # You should have received a copy of the GNU General Public License along | ||
| 16 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 18 | |||
| 19 | import sys | ||
| 20 | import os | ||
| 21 | import os.path | ||
| 22 | |||
| 23 | def add_oe_lib_path(): | ||
| 24 | basepath = os.path.abspath(os.path.dirname(__file__) + '/../..') | ||
| 25 | newpath = basepath + '/meta/lib' | ||
| 26 | sys.path.insert(0, newpath) | ||
| 27 | |||
| 28 | def add_bitbake_lib_path(): | ||
| 29 | basepath = os.path.abspath(os.path.dirname(__file__) + '/../..') | ||
| 30 | bitbakepath = None | ||
| 31 | if os.path.exists(basepath + '/bitbake/lib/bb'): | ||
| 32 | bitbakepath = basepath + '/bitbake' | ||
| 33 | else: | ||
| 34 | # look for bitbake/bin dir in PATH | ||
| 35 | for pth in os.environ['PATH'].split(':'): | ||
| 36 | if os.path.exists(os.path.join(pth, '../lib/bb')): | ||
| 37 | bitbakepath = os.path.abspath(os.path.join(pth, '..')) | ||
| 38 | break | ||
| 39 | |||
| 40 | if bitbakepath: | ||
| 41 | sys.path.insert(0, bitbakepath + '/lib') | ||
| 42 | return bitbakepath | ||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/__init__.py b/scripts/lib/wic/3rdparty/pykickstart/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/__init__.py | |||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/base.py b/scripts/lib/wic/3rdparty/pykickstart/base.py new file mode 100644 index 0000000000..e6c8f56f9d --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/base.py | |||
| @@ -0,0 +1,466 @@ | |||
| 1 | # | ||
| 2 | # Chris Lumens <clumens@redhat.com> | ||
| 3 | # | ||
| 4 | # Copyright 2006, 2007, 2008 Red Hat, Inc. | ||
| 5 | # | ||
| 6 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 7 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 8 | # General Public License v.2. This program is distributed in the hope that it | ||
| 9 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 10 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 11 | # See the GNU General Public License for more details. | ||
| 12 | # | ||
| 13 | # You should have received a copy of the GNU General Public License along with | ||
| 14 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 15 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat | ||
| 16 | # trademarks that are incorporated in the source code or documentation are not | ||
| 17 | # subject to the GNU General Public License and may only be used or replicated | ||
| 18 | # with the express permission of Red Hat, Inc. | ||
| 19 | # | ||
| 20 | """ | ||
| 21 | Base classes for creating commands and syntax version object. | ||
| 22 | |||
| 23 | This module exports several important base classes: | ||
| 24 | |||
| 25 | BaseData - The base abstract class for all data objects. Data objects | ||
| 26 | are contained within a BaseHandler object. | ||
| 27 | |||
| 28 | BaseHandler - The base abstract class from which versioned kickstart | ||
| 29 | handler are derived. Subclasses of BaseHandler hold | ||
| 30 | BaseData and KickstartCommand objects. | ||
| 31 | |||
| 32 | DeprecatedCommand - An abstract subclass of KickstartCommand that should | ||
| 33 | be further subclassed by users of this module. When | ||
| 34 | a subclass is used, a warning message will be | ||
| 35 | printed. | ||
| 36 | |||
| 37 | KickstartCommand - The base abstract class for all kickstart commands. | ||
| 38 | Command objects are contained within a BaseHandler | ||
| 39 | object. | ||
| 40 | """ | ||
| 41 | import gettext | ||
| 42 | gettext.textdomain("pykickstart") | ||
| 43 | _ = lambda x: gettext.ldgettext("pykickstart", x) | ||
| 44 | |||
| 45 | import types | ||
| 46 | import warnings | ||
| 47 | from pykickstart.errors import * | ||
| 48 | from pykickstart.ko import * | ||
| 49 | from pykickstart.parser import Packages | ||
| 50 | from pykickstart.version import versionToString | ||
| 51 | |||
| 52 | ### | ||
| 53 | ### COMMANDS | ||
| 54 | ### | ||
| 55 | class KickstartCommand(KickstartObject): | ||
| 56 | """The base class for all kickstart commands. This is an abstract class.""" | ||
| 57 | removedKeywords = [] | ||
| 58 | removedAttrs = [] | ||
| 59 | |||
| 60 | def __init__(self, writePriority=0, *args, **kwargs): | ||
| 61 | """Create a new KickstartCommand instance. This method must be | ||
| 62 | provided by all subclasses, but subclasses must call | ||
| 63 | KickstartCommand.__init__ first. Instance attributes: | ||
| 64 | |||
| 65 | currentCmd -- The name of the command in the input file that | ||
| 66 | caused this handler to be run. | ||
| 67 | currentLine -- The current unprocessed line from the input file | ||
| 68 | that caused this handler to be run. | ||
| 69 | handler -- A reference to the BaseHandler subclass this | ||
| 70 | command is contained withing. This is needed to | ||
| 71 | allow referencing of Data objects. | ||
| 72 | lineno -- The current line number in the input file. | ||
| 73 | writePriority -- An integer specifying when this command should be | ||
| 74 | printed when iterating over all commands' __str__ | ||
| 75 | methods. The higher the number, the later this | ||
| 76 | command will be written. All commands with the | ||
| 77 | same priority will be written alphabetically. | ||
| 78 | """ | ||
| 79 | |||
| 80 | # We don't want people using this class by itself. | ||
| 81 | if self.__class__ is KickstartCommand: | ||
| 82 | raise TypeError, "KickstartCommand is an abstract class." | ||
| 83 | |||
| 84 | KickstartObject.__init__(self, *args, **kwargs) | ||
| 85 | |||
| 86 | self.writePriority = writePriority | ||
| 87 | |||
| 88 | # These will be set by the dispatcher. | ||
| 89 | self.currentCmd = "" | ||
| 90 | self.currentLine = "" | ||
| 91 | self.handler = None | ||
| 92 | self.lineno = 0 | ||
| 93 | |||
| 94 | # If a subclass provides a removedKeywords list, remove all the | ||
| 95 | # members from the kwargs list before we start processing it. This | ||
| 96 | # ensures that subclasses don't continue to recognize arguments that | ||
| 97 | # were removed. | ||
| 98 | for arg in filter(kwargs.has_key, self.removedKeywords): | ||
| 99 | kwargs.pop(arg) | ||
| 100 | |||
| 101 | def __call__(self, *args, **kwargs): | ||
| 102 | """Set multiple attributes on a subclass of KickstartCommand at once | ||
| 103 | via keyword arguments. Valid attributes are anything specified in | ||
| 104 | a subclass, but unknown attributes will be ignored. | ||
| 105 | """ | ||
| 106 | for (key, val) in kwargs.items(): | ||
| 107 | # Ignore setting attributes that were removed in a subclass, as | ||
| 108 | # if they were unknown attributes. | ||
| 109 | if key in self.removedAttrs: | ||
| 110 | continue | ||
| 111 | |||
| 112 | if hasattr(self, key): | ||
| 113 | setattr(self, key, val) | ||
| 114 | |||
| 115 | def __str__(self): | ||
| 116 | """Return a string formatted for output to a kickstart file. This | ||
| 117 | method must be provided by all subclasses. | ||
| 118 | """ | ||
| 119 | return KickstartObject.__str__(self) | ||
| 120 | |||
| 121 | def parse(self, args): | ||
| 122 | """Parse the list of args and set data on the KickstartCommand object. | ||
| 123 | This method must be provided by all subclasses. | ||
| 124 | """ | ||
| 125 | raise TypeError, "parse() not implemented for KickstartCommand" | ||
| 126 | |||
| 127 | def apply(self, instroot="/"): | ||
| 128 | """Write out the configuration related to the KickstartCommand object. | ||
| 129 | Subclasses which do not provide this method will not have their | ||
| 130 | configuration written out. | ||
| 131 | """ | ||
| 132 | return | ||
| 133 | |||
| 134 | def dataList(self): | ||
| 135 | """For commands that can occur multiple times in a single kickstart | ||
| 136 | file (like network, part, etc.), return the list that we should | ||
| 137 | append more data objects to. | ||
| 138 | """ | ||
| 139 | return None | ||
| 140 | |||
| 141 | def deleteRemovedAttrs(self): | ||
| 142 | """Remove all attributes from self that are given in the removedAttrs | ||
| 143 | list. This method should be called from __init__ in a subclass, | ||
| 144 | but only after the superclass's __init__ method has been called. | ||
| 145 | """ | ||
| 146 | for attr in filter(lambda k: hasattr(self, k), self.removedAttrs): | ||
| 147 | delattr(self, attr) | ||
| 148 | |||
| 149 | # Set the contents of the opts object (an instance of optparse.Values | ||
| 150 | # returned by parse_args) as attributes on the KickstartCommand object. | ||
| 151 | # It's useful to call this from KickstartCommand subclasses after parsing | ||
| 152 | # the arguments. | ||
| 153 | def _setToSelf(self, optParser, opts): | ||
| 154 | self._setToObj(optParser, opts, self) | ||
| 155 | |||
| 156 | # Sets the contents of the opts object (an instance of optparse.Values | ||
| 157 | # returned by parse_args) as attributes on the provided object obj. It's | ||
| 158 | # useful to call this from KickstartCommand subclasses that handle lists | ||
| 159 | # of objects (like partitions, network devices, etc.) and need to populate | ||
| 160 | # a Data object. | ||
| 161 | def _setToObj(self, optParser, opts, obj): | ||
| 162 | for key in filter (lambda k: getattr(opts, k) != None, optParser.keys()): | ||
| 163 | setattr(obj, key, getattr(opts, key)) | ||
| 164 | |||
| 165 | class DeprecatedCommand(KickstartCommand): | ||
| 166 | """Specify that a command is deprecated and no longer has any function. | ||
| 167 | Any command that is deprecated should be subclassed from this class, | ||
| 168 | only specifying an __init__ method that calls the superclass's __init__. | ||
| 169 | This is an abstract class. | ||
| 170 | """ | ||
| 171 | def __init__(self, writePriority=None, *args, **kwargs): | ||
| 172 | # We don't want people using this class by itself. | ||
| 173 | if self.__class__ is KickstartCommand: | ||
| 174 | raise TypeError, "DeprecatedCommand is an abstract class." | ||
| 175 | |||
| 176 | # Create a new DeprecatedCommand instance. | ||
| 177 | KickstartCommand.__init__(self, writePriority, *args, **kwargs) | ||
| 178 | |||
| 179 | def __str__(self): | ||
| 180 | """Placeholder since DeprecatedCommands don't work anymore.""" | ||
| 181 | return "" | ||
| 182 | |||
| 183 | def parse(self, args): | ||
| 184 | """Print a warning message if the command is seen in the input file.""" | ||
| 185 | mapping = {"lineno": self.lineno, "cmd": self.currentCmd} | ||
| 186 | warnings.warn(_("Ignoring deprecated command on line %(lineno)s: The %(cmd)s command has been deprecated and no longer has any effect. It may be removed from future releases, which will result in a fatal error from kickstart. Please modify your kickstart file to remove this command.") % mapping, DeprecationWarning) | ||
| 187 | |||
| 188 | |||
| 189 | ### | ||
| 190 | ### HANDLERS | ||
| 191 | ### | ||
| 192 | class BaseHandler(KickstartObject): | ||
| 193 | """Each version of kickstart syntax is provided by a subclass of this | ||
| 194 | class. These subclasses are what users will interact with for parsing, | ||
| 195 | extracting data, and writing out kickstart files. This is an abstract | ||
| 196 | class. | ||
| 197 | |||
| 198 | version -- The version this syntax handler supports. This is set by | ||
| 199 | a class attribute of a BaseHandler subclass and is used to | ||
| 200 | set up the command dict. It is for read-only use. | ||
| 201 | """ | ||
| 202 | version = None | ||
| 203 | |||
| 204 | def __init__(self, mapping=None, dataMapping=None, commandUpdates=None, | ||
| 205 | dataUpdates=None, *args, **kwargs): | ||
| 206 | """Create a new BaseHandler instance. This method must be provided by | ||
| 207 | all subclasses, but subclasses must call BaseHandler.__init__ first. | ||
| 208 | |||
| 209 | mapping -- A custom map from command strings to classes, | ||
| 210 | useful when creating your own handler with | ||
| 211 | special command objects. It is otherwise unused | ||
| 212 | and rarely needed. If you give this argument, | ||
| 213 | the mapping takes the place of the default one | ||
| 214 | and so must include all commands you want | ||
| 215 | recognized. | ||
| 216 | dataMapping -- This is the same as mapping, but for data | ||
| 217 | objects. All the same comments apply. | ||
| 218 | commandUpdates -- This is similar to mapping, but does not take | ||
| 219 | the place of the defaults entirely. Instead, | ||
| 220 | this mapping is applied after the defaults and | ||
| 221 | updates it with just the commands you want to | ||
| 222 | modify. | ||
| 223 | dataUpdates -- This is the same as commandUpdates, but for | ||
| 224 | data objects. | ||
| 225 | |||
| 226 | |||
| 227 | Instance attributes: | ||
| 228 | |||
| 229 | commands -- A mapping from a string command to a KickstartCommand | ||
| 230 | subclass object that handles it. Multiple strings can | ||
| 231 | map to the same object, but only one instance of the | ||
| 232 | command object should ever exist. Most users should | ||
| 233 | never have to deal with this directly, as it is | ||
| 234 | manipulated internally and called through dispatcher. | ||
| 235 | currentLine -- The current unprocessed line from the input file | ||
| 236 | that caused this handler to be run. | ||
| 237 | packages -- An instance of pykickstart.parser.Packages which | ||
| 238 | describes the packages section of the input file. | ||
| 239 | platform -- A string describing the hardware platform, which is | ||
| 240 | needed only by system-config-kickstart. | ||
| 241 | scripts -- A list of pykickstart.parser.Script instances, which is | ||
| 242 | populated by KickstartParser.addScript and describes the | ||
| 243 | %pre/%post/%traceback script section of the input file. | ||
| 244 | """ | ||
| 245 | |||
| 246 | # We don't want people using this class by itself. | ||
| 247 | if self.__class__ is BaseHandler: | ||
| 248 | raise TypeError, "BaseHandler is an abstract class." | ||
| 249 | |||
| 250 | KickstartObject.__init__(self, *args, **kwargs) | ||
| 251 | |||
| 252 | # This isn't really a good place for these, but it's better than | ||
| 253 | # everything else I can think of. | ||
| 254 | self.scripts = [] | ||
| 255 | self.packages = Packages() | ||
| 256 | self.platform = "" | ||
| 257 | |||
| 258 | # These will be set by the dispatcher. | ||
| 259 | self.commands = {} | ||
| 260 | self.currentLine = 0 | ||
| 261 | |||
| 262 | # A dict keyed by an integer priority number, with each value being a | ||
| 263 | # list of KickstartCommand subclasses. This dict is maintained by | ||
| 264 | # registerCommand and used in __str__. No one else should be touching | ||
| 265 | # it. | ||
| 266 | self._writeOrder = {} | ||
| 267 | |||
| 268 | self._registerCommands(mapping, dataMapping, commandUpdates, dataUpdates) | ||
| 269 | |||
| 270 | def __str__(self): | ||
| 271 | """Return a string formatted for output to a kickstart file.""" | ||
| 272 | retval = "" | ||
| 273 | |||
| 274 | if self.platform != "": | ||
| 275 | retval += "#platform=%s\n" % self.platform | ||
| 276 | |||
| 277 | retval += "#version=%s\n" % versionToString(self.version) | ||
| 278 | |||
| 279 | lst = self._writeOrder.keys() | ||
| 280 | lst.sort() | ||
| 281 | |||
| 282 | for prio in lst: | ||
| 283 | for obj in self._writeOrder[prio]: | ||
| 284 | retval += obj.__str__() | ||
| 285 | |||
| 286 | for script in self.scripts: | ||
| 287 | retval += script.__str__() | ||
| 288 | |||
| 289 | retval += self.packages.__str__() | ||
| 290 | |||
| 291 | return retval | ||
| 292 | |||
| 293 | def _insertSorted(self, lst, obj): | ||
| 294 | length = len(lst) | ||
| 295 | i = 0 | ||
| 296 | |||
| 297 | while i < length: | ||
| 298 | # If the two classes have the same name, it's because we are | ||
| 299 | # overriding an existing class with one from a later kickstart | ||
| 300 | # version, so remove the old one in favor of the new one. | ||
| 301 | if obj.__class__.__name__ > lst[i].__class__.__name__: | ||
| 302 | i += 1 | ||
| 303 | elif obj.__class__.__name__ == lst[i].__class__.__name__: | ||
| 304 | lst[i] = obj | ||
| 305 | return | ||
| 306 | elif obj.__class__.__name__ < lst[i].__class__.__name__: | ||
| 307 | break | ||
| 308 | |||
| 309 | if i >= length: | ||
| 310 | lst.append(obj) | ||
| 311 | else: | ||
| 312 | lst.insert(i, obj) | ||
| 313 | |||
| 314 | def _setCommand(self, cmdObj): | ||
| 315 | # Add an attribute on this version object. We need this to provide a | ||
| 316 | # way for clients to access the command objects. We also need to strip | ||
| 317 | # off the version part from the front of the name. | ||
| 318 | if cmdObj.__class__.__name__.find("_") != -1: | ||
| 319 | name = unicode(cmdObj.__class__.__name__.split("_", 1)[1]) | ||
| 320 | else: | ||
| 321 | name = unicode(cmdObj.__class__.__name__).lower() | ||
| 322 | |||
| 323 | setattr(self, name.lower(), cmdObj) | ||
| 324 | |||
| 325 | # Also, add the object into the _writeOrder dict in the right place. | ||
| 326 | if cmdObj.writePriority is not None: | ||
| 327 | if self._writeOrder.has_key(cmdObj.writePriority): | ||
| 328 | self._insertSorted(self._writeOrder[cmdObj.writePriority], cmdObj) | ||
| 329 | else: | ||
| 330 | self._writeOrder[cmdObj.writePriority] = [cmdObj] | ||
| 331 | |||
| 332 | def _registerCommands(self, mapping=None, dataMapping=None, commandUpdates=None, | ||
| 333 | dataUpdates=None): | ||
| 334 | if mapping == {} or mapping == None: | ||
| 335 | from pykickstart.handlers.control import commandMap | ||
| 336 | cMap = commandMap[self.version] | ||
| 337 | else: | ||
| 338 | cMap = mapping | ||
| 339 | |||
| 340 | if dataMapping == {} or dataMapping == None: | ||
| 341 | from pykickstart.handlers.control import dataMap | ||
| 342 | dMap = dataMap[self.version] | ||
| 343 | else: | ||
| 344 | dMap = dataMapping | ||
| 345 | |||
| 346 | if type(commandUpdates) == types.DictType: | ||
| 347 | cMap.update(commandUpdates) | ||
| 348 | |||
| 349 | if type(dataUpdates) == types.DictType: | ||
| 350 | dMap.update(dataUpdates) | ||
| 351 | |||
| 352 | for (cmdName, cmdClass) in cMap.iteritems(): | ||
| 353 | # First make sure we haven't instantiated this command handler | ||
| 354 | # already. If we have, we just need to make another mapping to | ||
| 355 | # it in self.commands. | ||
| 356 | cmdObj = None | ||
| 357 | |||
| 358 | for (key, val) in self.commands.iteritems(): | ||
| 359 | if val.__class__.__name__ == cmdClass.__name__: | ||
| 360 | cmdObj = val | ||
| 361 | break | ||
| 362 | |||
| 363 | # If we didn't find an instance in self.commands, create one now. | ||
| 364 | if cmdObj == None: | ||
| 365 | cmdObj = cmdClass() | ||
| 366 | self._setCommand(cmdObj) | ||
| 367 | |||
| 368 | # Finally, add the mapping to the commands dict. | ||
| 369 | self.commands[cmdName] = cmdObj | ||
| 370 | self.commands[cmdName].handler = self | ||
| 371 | |||
| 372 | # We also need to create attributes for the various data objects. | ||
| 373 | # No checks here because dMap is a bijection. At least, that's what | ||
| 374 | # the comment says. Hope no one screws that up. | ||
| 375 | for (dataName, dataClass) in dMap.iteritems(): | ||
| 376 | setattr(self, dataName, dataClass) | ||
| 377 | |||
| 378 | def dispatcher(self, args, lineno): | ||
| 379 | """Call the appropriate KickstartCommand handler for the current line | ||
| 380 | in the kickstart file. A handler for the current command should | ||
| 381 | be registered, though a handler of None is not an error. Returns | ||
| 382 | the data object returned by KickstartCommand.parse. | ||
| 383 | |||
| 384 | args -- A list of arguments to the current command | ||
| 385 | lineno -- The line number in the file, for error reporting | ||
| 386 | """ | ||
| 387 | cmd = args[0] | ||
| 388 | |||
| 389 | if not self.commands.has_key(cmd): | ||
| 390 | raise KickstartParseError, formatErrorMsg(lineno, msg=_("Unknown command: %s" % cmd)) | ||
| 391 | elif self.commands[cmd] != None: | ||
| 392 | self.commands[cmd].currentCmd = cmd | ||
| 393 | self.commands[cmd].currentLine = self.currentLine | ||
| 394 | self.commands[cmd].lineno = lineno | ||
| 395 | |||
| 396 | # The parser returns the data object that was modified. This could | ||
| 397 | # be a BaseData subclass that should be put into a list, or it | ||
| 398 | # could be the command handler object itself. | ||
| 399 | obj = self.commands[cmd].parse(args[1:]) | ||
| 400 | lst = self.commands[cmd].dataList() | ||
| 401 | if lst is not None: | ||
| 402 | lst.append(obj) | ||
| 403 | |||
| 404 | return obj | ||
| 405 | |||
| 406 | def maskAllExcept(self, lst): | ||
| 407 | """Set all entries in the commands dict to None, except the ones in | ||
| 408 | the lst. All other commands will not be processed. | ||
| 409 | """ | ||
| 410 | self._writeOrder = {} | ||
| 411 | |||
| 412 | for (key, val) in self.commands.iteritems(): | ||
| 413 | if not key in lst: | ||
| 414 | self.commands[key] = None | ||
| 415 | |||
| 416 | def hasCommand(self, cmd): | ||
| 417 | """Return true if there is a handler for the string cmd.""" | ||
| 418 | return hasattr(self, cmd) | ||
| 419 | |||
| 420 | |||
| 421 | ### | ||
| 422 | ### DATA | ||
| 423 | ### | ||
| 424 | class BaseData(KickstartObject): | ||
| 425 | """The base class for all data objects. This is an abstract class.""" | ||
| 426 | removedKeywords = [] | ||
| 427 | removedAttrs = [] | ||
| 428 | |||
| 429 | def __init__(self, *args, **kwargs): | ||
| 430 | """Create a new BaseData instance. | ||
| 431 | |||
| 432 | lineno -- Line number in the ks-file where this object was defined | ||
| 433 | """ | ||
| 434 | |||
| 435 | # We don't want people using this class by itself. | ||
| 436 | if self.__class__ is BaseData: | ||
| 437 | raise TypeError, "BaseData is an abstract class." | ||
| 438 | |||
| 439 | KickstartObject.__init__(self, *args, **kwargs) | ||
| 440 | self.lineno = 0 | ||
| 441 | |||
| 442 | def __str__(self): | ||
| 443 | """Return a string formatted for output to a kickstart file.""" | ||
| 444 | return "" | ||
| 445 | |||
| 446 | def __call__(self, *args, **kwargs): | ||
| 447 | """Set multiple attributes on a subclass of BaseData at once via | ||
| 448 | keyword arguments. Valid attributes are anything specified in a | ||
| 449 | subclass, but unknown attributes will be ignored. | ||
| 450 | """ | ||
| 451 | for (key, val) in kwargs.items(): | ||
| 452 | # Ignore setting attributes that were removed in a subclass, as | ||
| 453 | # if they were unknown attributes. | ||
| 454 | if key in self.removedAttrs: | ||
| 455 | continue | ||
| 456 | |||
| 457 | if hasattr(self, key): | ||
| 458 | setattr(self, key, val) | ||
| 459 | |||
| 460 | def deleteRemovedAttrs(self): | ||
| 461 | """Remove all attributes from self that are given in the removedAttrs | ||
| 462 | list. This method should be called from __init__ in a subclass, | ||
| 463 | but only after the superclass's __init__ method has been called. | ||
| 464 | """ | ||
| 465 | for attr in filter(lambda k: hasattr(self, k), self.removedAttrs): | ||
| 466 | delattr(self, attr) | ||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/commands/__init__.py b/scripts/lib/wic/3rdparty/pykickstart/commands/__init__.py new file mode 100644 index 0000000000..2d94550935 --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/commands/__init__.py | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | # | ||
| 2 | # Chris Lumens <clumens@redhat.com> | ||
| 3 | # | ||
| 4 | # Copyright 2009 Red Hat, Inc. | ||
| 5 | # | ||
| 6 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 7 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 8 | # General Public License v.2. This program is distributed in the hope that it | ||
| 9 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 10 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 11 | # See the GNU General Public License for more details. | ||
| 12 | # | ||
| 13 | # You should have received a copy of the GNU General Public License along with | ||
| 14 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 15 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat | ||
| 16 | # trademarks that are incorporated in the source code or documentation are not | ||
| 17 | # subject to the GNU General Public License and may only be used or replicated | ||
| 18 | # with the express permission of Red Hat, Inc. | ||
| 19 | # | ||
| 20 | import bootloader, partition | ||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/commands/bootloader.py b/scripts/lib/wic/3rdparty/pykickstart/commands/bootloader.py new file mode 100644 index 0000000000..c2b552f689 --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/commands/bootloader.py | |||
| @@ -0,0 +1,216 @@ | |||
| 1 | # | ||
| 2 | # Chris Lumens <clumens@redhat.com> | ||
| 3 | # | ||
| 4 | # Copyright 2007 Red Hat, Inc. | ||
| 5 | # | ||
| 6 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 7 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 8 | # General Public License v.2. This program is distributed in the hope that it | ||
| 9 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 10 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 11 | # See the GNU General Public License for more details. | ||
| 12 | # | ||
| 13 | # You should have received a copy of the GNU General Public License along with | ||
| 14 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 15 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat | ||
| 16 | # trademarks that are incorporated in the source code or documentation are not | ||
| 17 | # subject to the GNU General Public License and may only be used or replicated | ||
| 18 | # with the express permission of Red Hat, Inc. | ||
| 19 | # | ||
| 20 | from pykickstart.base import * | ||
| 21 | from pykickstart.options import * | ||
| 22 | |||
| 23 | class FC3_Bootloader(KickstartCommand): | ||
| 24 | removedKeywords = KickstartCommand.removedKeywords | ||
| 25 | removedAttrs = KickstartCommand.removedAttrs | ||
| 26 | |||
| 27 | def __init__(self, writePriority=10, *args, **kwargs): | ||
| 28 | KickstartCommand.__init__(self, writePriority, *args, **kwargs) | ||
| 29 | self.op = self._getParser() | ||
| 30 | |||
| 31 | self.driveorder = kwargs.get("driveorder", []) | ||
| 32 | self.appendLine = kwargs.get("appendLine", "") | ||
| 33 | self.forceLBA = kwargs.get("forceLBA", False) | ||
| 34 | self.linear = kwargs.get("linear", True) | ||
| 35 | self.location = kwargs.get("location", "") | ||
| 36 | self.md5pass = kwargs.get("md5pass", "") | ||
| 37 | self.password = kwargs.get("password", "") | ||
| 38 | self.upgrade = kwargs.get("upgrade", False) | ||
| 39 | self.useLilo = kwargs.get("useLilo", False) | ||
| 40 | |||
| 41 | self.deleteRemovedAttrs() | ||
| 42 | |||
| 43 | def _getArgsAsStr(self): | ||
| 44 | retval = "" | ||
| 45 | |||
| 46 | if self.appendLine != "": | ||
| 47 | retval += " --append=\"%s\"" % self.appendLine | ||
| 48 | if self.linear: | ||
| 49 | retval += " --linear" | ||
| 50 | if self.location: | ||
| 51 | retval += " --location=%s" % self.location | ||
| 52 | if hasattr(self, "forceLBA") and self.forceLBA: | ||
| 53 | retval += " --lba32" | ||
| 54 | if self.password != "": | ||
| 55 | retval += " --password=\"%s\"" % self.password | ||
| 56 | if self.md5pass != "": | ||
| 57 | retval += " --md5pass=\"%s\"" % self.md5pass | ||
| 58 | if self.upgrade: | ||
| 59 | retval += " --upgrade" | ||
| 60 | if self.useLilo: | ||
| 61 | retval += " --useLilo" | ||
| 62 | if len(self.driveorder) > 0: | ||
| 63 | retval += " --driveorder=\"%s\"" % ",".join(self.driveorder) | ||
| 64 | |||
| 65 | return retval | ||
| 66 | |||
| 67 | def __str__(self): | ||
| 68 | retval = KickstartCommand.__str__(self) | ||
| 69 | |||
| 70 | if self.location != "": | ||
| 71 | retval += "# System bootloader configuration\nbootloader" | ||
| 72 | retval += self._getArgsAsStr() + "\n" | ||
| 73 | |||
| 74 | return retval | ||
| 75 | |||
| 76 | def _getParser(self): | ||
| 77 | def driveorder_cb (option, opt_str, value, parser): | ||
| 78 | for d in value.split(','): | ||
| 79 | parser.values.ensure_value(option.dest, []).append(d) | ||
| 80 | |||
| 81 | op = KSOptionParser() | ||
| 82 | op.add_option("--append", dest="appendLine") | ||
| 83 | op.add_option("--linear", dest="linear", action="store_true", | ||
| 84 | default=True) | ||
| 85 | op.add_option("--nolinear", dest="linear", action="store_false") | ||
| 86 | op.add_option("--location", dest="location", type="choice", | ||
| 87 | default="mbr", | ||
| 88 | choices=["mbr", "partition", "none", "boot"]) | ||
| 89 | op.add_option("--lba32", dest="forceLBA", action="store_true", | ||
| 90 | default=False) | ||
| 91 | op.add_option("--password", dest="password", default="") | ||
| 92 | op.add_option("--md5pass", dest="md5pass", default="") | ||
| 93 | op.add_option("--upgrade", dest="upgrade", action="store_true", | ||
| 94 | default=False) | ||
| 95 | op.add_option("--useLilo", dest="useLilo", action="store_true", | ||
| 96 | default=False) | ||
| 97 | op.add_option("--driveorder", dest="driveorder", action="callback", | ||
| 98 | callback=driveorder_cb, nargs=1, type="string") | ||
| 99 | return op | ||
| 100 | |||
| 101 | def parse(self, args): | ||
| 102 | (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno) | ||
| 103 | self._setToSelf(self.op, opts) | ||
| 104 | |||
| 105 | if self.currentCmd == "lilo": | ||
| 106 | self.useLilo = True | ||
| 107 | |||
| 108 | return self | ||
| 109 | |||
| 110 | class FC4_Bootloader(FC3_Bootloader): | ||
| 111 | removedKeywords = FC3_Bootloader.removedKeywords + ["linear", "useLilo"] | ||
| 112 | removedAttrs = FC3_Bootloader.removedAttrs + ["linear", "useLilo"] | ||
| 113 | |||
| 114 | def __init__(self, writePriority=10, *args, **kwargs): | ||
| 115 | FC3_Bootloader.__init__(self, writePriority, *args, **kwargs) | ||
| 116 | |||
| 117 | def _getArgsAsStr(self): | ||
| 118 | retval = "" | ||
| 119 | if self.appendLine != "": | ||
| 120 | retval += " --append=\"%s\"" % self.appendLine | ||
| 121 | if self.location: | ||
| 122 | retval += " --location=%s" % self.location | ||
| 123 | if hasattr(self, "forceLBA") and self.forceLBA: | ||
| 124 | retval += " --lba32" | ||
| 125 | if self.password != "": | ||
| 126 | retval += " --password=\"%s\"" % self.password | ||
| 127 | if self.md5pass != "": | ||
| 128 | retval += " --md5pass=\"%s\"" % self.md5pass | ||
| 129 | if self.upgrade: | ||
| 130 | retval += " --upgrade" | ||
| 131 | if len(self.driveorder) > 0: | ||
| 132 | retval += " --driveorder=\"%s\"" % ",".join(self.driveorder) | ||
| 133 | return retval | ||
| 134 | |||
| 135 | def _getParser(self): | ||
| 136 | op = FC3_Bootloader._getParser(self) | ||
| 137 | op.remove_option("--linear") | ||
| 138 | op.remove_option("--nolinear") | ||
| 139 | op.remove_option("--useLilo") | ||
| 140 | return op | ||
| 141 | |||
| 142 | def parse(self, args): | ||
| 143 | (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno) | ||
| 144 | self._setToSelf(self.op, opts) | ||
| 145 | return self | ||
| 146 | |||
| 147 | class F8_Bootloader(FC4_Bootloader): | ||
| 148 | removedKeywords = FC4_Bootloader.removedKeywords | ||
| 149 | removedAttrs = FC4_Bootloader.removedAttrs | ||
| 150 | |||
| 151 | def __init__(self, writePriority=10, *args, **kwargs): | ||
| 152 | FC4_Bootloader.__init__(self, writePriority, *args, **kwargs) | ||
| 153 | |||
| 154 | self.timeout = kwargs.get("timeout", None) | ||
| 155 | self.default = kwargs.get("default", "") | ||
| 156 | |||
| 157 | def _getArgsAsStr(self): | ||
| 158 | ret = FC4_Bootloader._getArgsAsStr(self) | ||
| 159 | |||
| 160 | if self.timeout is not None: | ||
| 161 | ret += " --timeout=%d" %(self.timeout,) | ||
| 162 | if self.default: | ||
| 163 | ret += " --default=%s" %(self.default,) | ||
| 164 | |||
| 165 | return ret | ||
| 166 | |||
| 167 | def _getParser(self): | ||
| 168 | op = FC4_Bootloader._getParser(self) | ||
| 169 | op.add_option("--timeout", dest="timeout", type="int") | ||
| 170 | op.add_option("--default", dest="default") | ||
| 171 | return op | ||
| 172 | |||
| 173 | class F12_Bootloader(F8_Bootloader): | ||
| 174 | removedKeywords = F8_Bootloader.removedKeywords | ||
| 175 | removedAttrs = F8_Bootloader.removedAttrs | ||
| 176 | |||
| 177 | def _getParser(self): | ||
| 178 | op = F8_Bootloader._getParser(self) | ||
| 179 | op.add_option("--lba32", dest="forceLBA", deprecated=1, action="store_true") | ||
| 180 | return op | ||
| 181 | |||
| 182 | class F14_Bootloader(F12_Bootloader): | ||
| 183 | removedKeywords = F12_Bootloader.removedKeywords + ["forceLBA"] | ||
| 184 | removedAttrs = F12_Bootloader.removedKeywords + ["forceLBA"] | ||
| 185 | |||
| 186 | def _getParser(self): | ||
| 187 | op = F12_Bootloader._getParser(self) | ||
| 188 | op.remove_option("--lba32") | ||
| 189 | return op | ||
| 190 | |||
| 191 | class F15_Bootloader(F14_Bootloader): | ||
| 192 | removedKeywords = F14_Bootloader.removedKeywords | ||
| 193 | removedAttrs = F14_Bootloader.removedAttrs | ||
| 194 | |||
| 195 | def __init__(self, writePriority=10, *args, **kwargs): | ||
| 196 | F14_Bootloader.__init__(self, writePriority, *args, **kwargs) | ||
| 197 | |||
| 198 | self.isCrypted = kwargs.get("isCrypted", False) | ||
| 199 | |||
| 200 | def _getArgsAsStr(self): | ||
| 201 | ret = F14_Bootloader._getArgsAsStr(self) | ||
| 202 | |||
| 203 | if self.isCrypted: | ||
| 204 | ret += " --iscrypted" | ||
| 205 | |||
| 206 | return ret | ||
| 207 | |||
| 208 | def _getParser(self): | ||
| 209 | def password_cb(option, opt_str, value, parser): | ||
| 210 | parser.values.isCrypted = True | ||
| 211 | parser.values.password = value | ||
| 212 | |||
| 213 | op = F14_Bootloader._getParser(self) | ||
| 214 | op.add_option("--iscrypted", dest="isCrypted", action="store_true", default=False) | ||
| 215 | op.add_option("--md5pass", action="callback", callback=password_cb, nargs=1, type="string") | ||
| 216 | return op | ||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/commands/partition.py b/scripts/lib/wic/3rdparty/pykickstart/commands/partition.py new file mode 100644 index 0000000000..56b91aa9d9 --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/commands/partition.py | |||
| @@ -0,0 +1,314 @@ | |||
| 1 | # | ||
| 2 | # Chris Lumens <clumens@redhat.com> | ||
| 3 | # | ||
| 4 | # Copyright 2005, 2006, 2007, 2008 Red Hat, Inc. | ||
| 5 | # | ||
| 6 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 7 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 8 | # General Public License v.2. This program is distributed in the hope that it | ||
| 9 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 10 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 11 | # See the GNU General Public License for more details. | ||
| 12 | # | ||
| 13 | # You should have received a copy of the GNU General Public License along with | ||
| 14 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 15 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat | ||
| 16 | # trademarks that are incorporated in the source code or documentation are not | ||
| 17 | # subject to the GNU General Public License and may only be used or replicated | ||
| 18 | # with the express permission of Red Hat, Inc. | ||
| 19 | # | ||
| 20 | from pykickstart.base import * | ||
| 21 | from pykickstart.errors import * | ||
| 22 | from pykickstart.options import * | ||
| 23 | |||
| 24 | import gettext | ||
| 25 | import warnings | ||
| 26 | _ = lambda x: gettext.ldgettext("pykickstart", x) | ||
| 27 | |||
| 28 | class FC3_PartData(BaseData): | ||
| 29 | removedKeywords = BaseData.removedKeywords | ||
| 30 | removedAttrs = BaseData.removedAttrs | ||
| 31 | |||
| 32 | def __init__(self, *args, **kwargs): | ||
| 33 | BaseData.__init__(self, *args, **kwargs) | ||
| 34 | self.active = kwargs.get("active", False) | ||
| 35 | self.primOnly = kwargs.get("primOnly", False) | ||
| 36 | self.end = kwargs.get("end", 0) | ||
| 37 | self.fstype = kwargs.get("fstype", "") | ||
| 38 | self.grow = kwargs.get("grow", False) | ||
| 39 | self.maxSizeMB = kwargs.get("maxSizeMB", 0) | ||
| 40 | self.format = kwargs.get("format", True) | ||
| 41 | self.onbiosdisk = kwargs.get("onbiosdisk", "") | ||
| 42 | self.disk = kwargs.get("disk", "") | ||
| 43 | self.onPart = kwargs.get("onPart", "") | ||
| 44 | self.recommended = kwargs.get("recommended", False) | ||
| 45 | self.size = kwargs.get("size", None) | ||
| 46 | self.start = kwargs.get("start", 0) | ||
| 47 | self.mountpoint = kwargs.get("mountpoint", "") | ||
| 48 | |||
| 49 | def __eq__(self, y): | ||
| 50 | if self.mountpoint: | ||
| 51 | return self.mountpoint == y.mountpoint | ||
| 52 | else: | ||
| 53 | return False | ||
| 54 | |||
| 55 | def _getArgsAsStr(self): | ||
| 56 | retval = "" | ||
| 57 | |||
| 58 | if self.active: | ||
| 59 | retval += " --active" | ||
| 60 | if self.primOnly: | ||
| 61 | retval += " --asprimary" | ||
| 62 | if hasattr(self, "end") and self.end != 0: | ||
| 63 | retval += " --end=%s" % self.end | ||
| 64 | if self.fstype != "": | ||
| 65 | retval += " --fstype=\"%s\"" % self.fstype | ||
| 66 | if self.grow: | ||
| 67 | retval += " --grow" | ||
| 68 | if self.maxSizeMB > 0: | ||
| 69 | retval += " --maxsize=%d" % self.maxSizeMB | ||
| 70 | if not self.format: | ||
| 71 | retval += " --noformat" | ||
| 72 | if self.onbiosdisk != "": | ||
| 73 | retval += " --onbiosdisk=%s" % self.onbiosdisk | ||
| 74 | if self.disk != "": | ||
| 75 | retval += " --ondisk=%s" % self.disk | ||
| 76 | if self.onPart != "": | ||
| 77 | retval += " --onpart=%s" % self.onPart | ||
| 78 | if self.recommended: | ||
| 79 | retval += " --recommended" | ||
| 80 | if self.size and self.size != 0: | ||
| 81 | retval += " --size=%s" % self.size | ||
| 82 | if hasattr(self, "start") and self.start != 0: | ||
| 83 | retval += " --start=%s" % self.start | ||
| 84 | |||
| 85 | return retval | ||
| 86 | |||
| 87 | def __str__(self): | ||
| 88 | retval = BaseData.__str__(self) | ||
| 89 | if self.mountpoint: | ||
| 90 | mountpoint_str = "%s" % self.mountpoint | ||
| 91 | else: | ||
| 92 | mountpoint_str = "(No mount point)" | ||
| 93 | retval += "part %s%s\n" % (mountpoint_str, self._getArgsAsStr()) | ||
| 94 | return retval | ||
| 95 | |||
| 96 | class FC4_PartData(FC3_PartData): | ||
| 97 | removedKeywords = FC3_PartData.removedKeywords | ||
| 98 | removedAttrs = FC3_PartData.removedAttrs | ||
| 99 | |||
| 100 | def __init__(self, *args, **kwargs): | ||
| 101 | FC3_PartData.__init__(self, *args, **kwargs) | ||
| 102 | self.bytesPerInode = kwargs.get("bytesPerInode", 4096) | ||
| 103 | self.fsopts = kwargs.get("fsopts", "") | ||
| 104 | self.label = kwargs.get("label", "") | ||
| 105 | |||
| 106 | def _getArgsAsStr(self): | ||
| 107 | retval = FC3_PartData._getArgsAsStr(self) | ||
| 108 | |||
| 109 | if hasattr(self, "bytesPerInode") and self.bytesPerInode != 0: | ||
| 110 | retval += " --bytes-per-inode=%d" % self.bytesPerInode | ||
| 111 | if self.fsopts != "": | ||
| 112 | retval += " --fsoptions=\"%s\"" % self.fsopts | ||
| 113 | if self.label != "": | ||
| 114 | retval += " --label=%s" % self.label | ||
| 115 | |||
| 116 | return retval | ||
| 117 | |||
| 118 | class F9_PartData(FC4_PartData): | ||
| 119 | removedKeywords = FC4_PartData.removedKeywords + ["bytesPerInode"] | ||
| 120 | removedAttrs = FC4_PartData.removedAttrs + ["bytesPerInode"] | ||
| 121 | |||
| 122 | def __init__(self, *args, **kwargs): | ||
| 123 | FC4_PartData.__init__(self, *args, **kwargs) | ||
| 124 | self.deleteRemovedAttrs() | ||
| 125 | |||
| 126 | self.fsopts = kwargs.get("fsopts", "") | ||
| 127 | self.label = kwargs.get("label", "") | ||
| 128 | self.fsprofile = kwargs.get("fsprofile", "") | ||
| 129 | self.encrypted = kwargs.get("encrypted", False) | ||
| 130 | self.passphrase = kwargs.get("passphrase", "") | ||
| 131 | |||
| 132 | def _getArgsAsStr(self): | ||
| 133 | retval = FC4_PartData._getArgsAsStr(self) | ||
| 134 | |||
| 135 | if self.fsprofile != "": | ||
| 136 | retval += " --fsprofile=\"%s\"" % self.fsprofile | ||
| 137 | if self.encrypted: | ||
| 138 | retval += " --encrypted" | ||
| 139 | |||
| 140 | if self.passphrase != "": | ||
| 141 | retval += " --passphrase=\"%s\"" % self.passphrase | ||
| 142 | |||
| 143 | return retval | ||
| 144 | |||
| 145 | class F11_PartData(F9_PartData): | ||
| 146 | removedKeywords = F9_PartData.removedKeywords + ["start", "end"] | ||
| 147 | removedAttrs = F9_PartData.removedAttrs + ["start", "end"] | ||
| 148 | |||
| 149 | class F12_PartData(F11_PartData): | ||
| 150 | removedKeywords = F11_PartData.removedKeywords | ||
| 151 | removedAttrs = F11_PartData.removedAttrs | ||
| 152 | |||
| 153 | def __init__(self, *args, **kwargs): | ||
| 154 | F11_PartData.__init__(self, *args, **kwargs) | ||
| 155 | |||
| 156 | self.escrowcert = kwargs.get("escrowcert", "") | ||
| 157 | self.backuppassphrase = kwargs.get("backuppassphrase", False) | ||
| 158 | |||
| 159 | def _getArgsAsStr(self): | ||
| 160 | retval = F11_PartData._getArgsAsStr(self) | ||
| 161 | |||
| 162 | if self.encrypted and self.escrowcert != "": | ||
| 163 | retval += " --escrowcert=\"%s\"" % self.escrowcert | ||
| 164 | |||
| 165 | if self.backuppassphrase: | ||
| 166 | retval += " --backuppassphrase" | ||
| 167 | |||
| 168 | return retval | ||
| 169 | |||
| 170 | F14_PartData = F12_PartData | ||
| 171 | |||
| 172 | class FC3_Partition(KickstartCommand): | ||
| 173 | removedKeywords = KickstartCommand.removedKeywords | ||
| 174 | removedAttrs = KickstartCommand.removedAttrs | ||
| 175 | |||
| 176 | def __init__(self, writePriority=130, *args, **kwargs): | ||
| 177 | KickstartCommand.__init__(self, writePriority, *args, **kwargs) | ||
| 178 | self.op = self._getParser() | ||
| 179 | |||
| 180 | self.partitions = kwargs.get("partitions", []) | ||
| 181 | |||
| 182 | def __str__(self): | ||
| 183 | retval = "" | ||
| 184 | |||
| 185 | for part in self.partitions: | ||
| 186 | retval += part.__str__() | ||
| 187 | |||
| 188 | if retval != "": | ||
| 189 | return "# Disk partitioning information\n" + retval | ||
| 190 | else: | ||
| 191 | return "" | ||
| 192 | |||
| 193 | def _getParser(self): | ||
| 194 | def part_cb (option, opt_str, value, parser): | ||
| 195 | if value.startswith("/dev/"): | ||
| 196 | parser.values.ensure_value(option.dest, value[5:]) | ||
| 197 | else: | ||
| 198 | parser.values.ensure_value(option.dest, value) | ||
| 199 | |||
| 200 | op = KSOptionParser() | ||
| 201 | op.add_option("--active", dest="active", action="store_true", | ||
| 202 | default=False) | ||
| 203 | op.add_option("--asprimary", dest="primOnly", action="store_true", | ||
| 204 | default=False) | ||
| 205 | op.add_option("--end", dest="end", action="store", type="int", | ||
| 206 | nargs=1) | ||
| 207 | op.add_option("--fstype", "--type", dest="fstype") | ||
| 208 | op.add_option("--grow", dest="grow", action="store_true", default=False) | ||
| 209 | op.add_option("--maxsize", dest="maxSizeMB", action="store", type="int", | ||
| 210 | nargs=1) | ||
| 211 | op.add_option("--noformat", dest="format", action="store_false", | ||
| 212 | default=True) | ||
| 213 | op.add_option("--onbiosdisk", dest="onbiosdisk") | ||
| 214 | op.add_option("--ondisk", "--ondrive", dest="disk") | ||
| 215 | op.add_option("--onpart", "--usepart", dest="onPart", action="callback", | ||
| 216 | callback=part_cb, nargs=1, type="string") | ||
| 217 | op.add_option("--recommended", dest="recommended", action="store_true", | ||
| 218 | default=False) | ||
| 219 | op.add_option("--size", dest="size", action="store", type="int", | ||
| 220 | nargs=1) | ||
| 221 | op.add_option("--start", dest="start", action="store", type="int", | ||
| 222 | nargs=1) | ||
| 223 | return op | ||
| 224 | |||
| 225 | def parse(self, args): | ||
| 226 | (opts, extra) = self.op.parse_args(args=args, lineno=self.lineno) | ||
| 227 | |||
| 228 | pd = self.handler.PartData() | ||
| 229 | self._setToObj(self.op, opts, pd) | ||
| 230 | pd.lineno = self.lineno | ||
| 231 | if extra: | ||
| 232 | pd.mountpoint = extra[0] | ||
| 233 | if pd in self.dataList(): | ||
| 234 | warnings.warn(_("A partition with the mountpoint %s has already been defined.") % pd.mountpoint) | ||
| 235 | else: | ||
| 236 | pd.mountpoint = None | ||
| 237 | |||
| 238 | return pd | ||
| 239 | |||
| 240 | def dataList(self): | ||
| 241 | return self.partitions | ||
| 242 | |||
| 243 | class FC4_Partition(FC3_Partition): | ||
| 244 | removedKeywords = FC3_Partition.removedKeywords | ||
| 245 | removedAttrs = FC3_Partition.removedAttrs | ||
| 246 | |||
| 247 | def __init__(self, writePriority=130, *args, **kwargs): | ||
| 248 | FC3_Partition.__init__(self, writePriority, *args, **kwargs) | ||
| 249 | |||
| 250 | def part_cb (option, opt_str, value, parser): | ||
| 251 | if value.startswith("/dev/"): | ||
| 252 | parser.values.ensure_value(option.dest, value[5:]) | ||
| 253 | else: | ||
| 254 | parser.values.ensure_value(option.dest, value) | ||
| 255 | |||
| 256 | def _getParser(self): | ||
| 257 | op = FC3_Partition._getParser(self) | ||
| 258 | op.add_option("--bytes-per-inode", dest="bytesPerInode", action="store", | ||
| 259 | type="int", nargs=1) | ||
| 260 | op.add_option("--fsoptions", dest="fsopts") | ||
| 261 | op.add_option("--label", dest="label") | ||
| 262 | return op | ||
| 263 | |||
| 264 | class F9_Partition(FC4_Partition): | ||
| 265 | removedKeywords = FC4_Partition.removedKeywords | ||
| 266 | removedAttrs = FC4_Partition.removedAttrs | ||
| 267 | |||
| 268 | def __init__(self, writePriority=130, *args, **kwargs): | ||
| 269 | FC4_Partition.__init__(self, writePriority, *args, **kwargs) | ||
| 270 | |||
| 271 | def part_cb (option, opt_str, value, parser): | ||
| 272 | if value.startswith("/dev/"): | ||
| 273 | parser.values.ensure_value(option.dest, value[5:]) | ||
| 274 | else: | ||
| 275 | parser.values.ensure_value(option.dest, value) | ||
| 276 | |||
| 277 | def _getParser(self): | ||
| 278 | op = FC4_Partition._getParser(self) | ||
| 279 | op.add_option("--bytes-per-inode", deprecated=1) | ||
| 280 | op.add_option("--fsprofile") | ||
| 281 | op.add_option("--encrypted", action="store_true", default=False) | ||
| 282 | op.add_option("--passphrase") | ||
| 283 | return op | ||
| 284 | |||
| 285 | class F11_Partition(F9_Partition): | ||
| 286 | removedKeywords = F9_Partition.removedKeywords | ||
| 287 | removedAttrs = F9_Partition.removedAttrs | ||
| 288 | |||
| 289 | def _getParser(self): | ||
| 290 | op = F9_Partition._getParser(self) | ||
| 291 | op.add_option("--start", deprecated=1) | ||
| 292 | op.add_option("--end", deprecated=1) | ||
| 293 | return op | ||
| 294 | |||
| 295 | class F12_Partition(F11_Partition): | ||
| 296 | removedKeywords = F11_Partition.removedKeywords | ||
| 297 | removedAttrs = F11_Partition.removedAttrs | ||
| 298 | |||
| 299 | def _getParser(self): | ||
| 300 | op = F11_Partition._getParser(self) | ||
| 301 | op.add_option("--escrowcert") | ||
| 302 | op.add_option("--backuppassphrase", action="store_true", default=False) | ||
| 303 | return op | ||
| 304 | |||
| 305 | class F14_Partition(F12_Partition): | ||
| 306 | removedKeywords = F12_Partition.removedKeywords | ||
| 307 | removedAttrs = F12_Partition.removedAttrs | ||
| 308 | |||
| 309 | def _getParser(self): | ||
| 310 | op = F12_Partition._getParser(self) | ||
| 311 | op.remove_option("--bytes-per-inode") | ||
| 312 | op.remove_option("--start") | ||
| 313 | op.remove_option("--end") | ||
| 314 | return op | ||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/constants.py b/scripts/lib/wic/3rdparty/pykickstart/constants.py new file mode 100644 index 0000000000..5e12fc80ec --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/constants.py | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | # | ||
| 2 | # Chris Lumens <clumens@redhat.com> | ||
| 3 | # | ||
| 4 | # Copyright 2005-2007 Red Hat, Inc. | ||
| 5 | # | ||
| 6 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 7 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 8 | # General Public License v.2. This program is distributed in the hope that it | ||
| 9 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 10 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 11 | # See the GNU General Public License for more details. | ||
| 12 | # | ||
| 13 | # You should have received a copy of the GNU General Public License along with | ||
| 14 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 15 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat | ||
| 16 | # trademarks that are incorporated in the source code or documentation are not | ||
| 17 | # subject to the GNU General Public License and may only be used or replicated | ||
| 18 | # with the express permission of Red Hat, Inc. | ||
| 19 | # | ||
| 20 | CLEARPART_TYPE_LINUX = 0 | ||
| 21 | CLEARPART_TYPE_ALL = 1 | ||
| 22 | CLEARPART_TYPE_NONE = 2 | ||
| 23 | |||
| 24 | DISPLAY_MODE_CMDLINE = 0 | ||
| 25 | DISPLAY_MODE_GRAPHICAL = 1 | ||
| 26 | DISPLAY_MODE_TEXT = 2 | ||
| 27 | |||
| 28 | FIRSTBOOT_DEFAULT = 0 | ||
| 29 | FIRSTBOOT_SKIP = 1 | ||
| 30 | FIRSTBOOT_RECONFIG = 2 | ||
| 31 | |||
| 32 | KS_MISSING_PROMPT = 0 | ||
| 33 | KS_MISSING_IGNORE = 1 | ||
| 34 | |||
| 35 | SELINUX_DISABLED = 0 | ||
| 36 | SELINUX_ENFORCING = 1 | ||
| 37 | SELINUX_PERMISSIVE = 2 | ||
| 38 | |||
| 39 | KS_SCRIPT_PRE = 0 | ||
| 40 | KS_SCRIPT_POST = 1 | ||
| 41 | KS_SCRIPT_TRACEBACK = 2 | ||
| 42 | |||
| 43 | KS_WAIT = 0 | ||
| 44 | KS_REBOOT = 1 | ||
| 45 | KS_SHUTDOWN = 2 | ||
| 46 | |||
| 47 | KS_INSTKEY_SKIP = -99 | ||
| 48 | |||
| 49 | BOOTPROTO_DHCP = "dhcp" | ||
| 50 | BOOTPROTO_BOOTP = "bootp" | ||
| 51 | BOOTPROTO_STATIC = "static" | ||
| 52 | BOOTPROTO_QUERY = "query" | ||
| 53 | BOOTPROTO_IBFT = "ibft" | ||
| 54 | |||
| 55 | GROUP_REQUIRED = 0 | ||
| 56 | GROUP_DEFAULT = 1 | ||
| 57 | GROUP_ALL = 2 | ||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/errors.py b/scripts/lib/wic/3rdparty/pykickstart/errors.py new file mode 100644 index 0000000000..a234d99d43 --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/errors.py | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | # | ||
| 2 | # errors.py: Kickstart error handling. | ||
| 3 | # | ||
| 4 | # Chris Lumens <clumens@redhat.com> | ||
| 5 | # | ||
| 6 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 7 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 8 | # General Public License v.2. This program is distributed in the hope that it | ||
| 9 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 10 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 11 | # See the GNU General Public License for more details. | ||
| 12 | # | ||
| 13 | # You should have received a copy of the GNU General Public License along with | ||
| 14 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 15 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat | ||
| 16 | # trademarks that are incorporated in the source code or documentation are not | ||
| 17 | # subject to the GNU General Public License and may only be used or replicated | ||
| 18 | # with the express permission of Red Hat, Inc. | ||
| 19 | # | ||
| 20 | """ | ||
| 21 | Error handling classes and functions. | ||
| 22 | |||
| 23 | This module exports a single function: | ||
| 24 | |||
| 25 | formatErrorMsg - Properly formats an error message. | ||
| 26 | |||
| 27 | It also exports several exception classes: | ||
| 28 | |||
| 29 | KickstartError - A generic exception class. | ||
| 30 | |||
| 31 | KickstartParseError - An exception for errors relating to parsing. | ||
| 32 | |||
| 33 | KickstartValueError - An exception for errors relating to option | ||
| 34 | processing. | ||
| 35 | |||
| 36 | KickstartVersionError - An exception for errors relating to unsupported | ||
| 37 | syntax versions. | ||
| 38 | """ | ||
| 39 | import gettext | ||
| 40 | _ = lambda x: gettext.ldgettext("pykickstart", x) | ||
| 41 | |||
| 42 | def formatErrorMsg(lineno, msg=""): | ||
| 43 | """Properly format the error message msg for inclusion in an exception.""" | ||
| 44 | if msg != "": | ||
| 45 | mapping = {"lineno": lineno, "msg": msg} | ||
| 46 | return _("The following problem occurred on line %(lineno)s of the kickstart file:\n\n%(msg)s\n") % mapping | ||
| 47 | else: | ||
| 48 | return _("There was a problem reading from line %s of the kickstart file") % lineno | ||
| 49 | |||
| 50 | class KickstartError(Exception): | ||
| 51 | """A generic exception class for unspecific error conditions.""" | ||
| 52 | def __init__(self, val = ""): | ||
| 53 | """Create a new KickstartError exception instance with the descriptive | ||
| 54 | message val. val should be the return value of formatErrorMsg. | ||
| 55 | """ | ||
| 56 | Exception.__init__(self) | ||
| 57 | self.value = val | ||
| 58 | |||
| 59 | def __str__ (self): | ||
| 60 | return self.value | ||
| 61 | |||
| 62 | class KickstartParseError(KickstartError): | ||
| 63 | """An exception class for errors when processing the input file, such as | ||
| 64 | unknown options, commands, or sections. | ||
| 65 | """ | ||
| 66 | def __init__(self, msg): | ||
| 67 | """Create a new KickstartParseError exception instance with the | ||
| 68 | descriptive message val. val should be the return value of | ||
| 69 | formatErrorMsg. | ||
| 70 | """ | ||
| 71 | KickstartError.__init__(self, msg) | ||
| 72 | |||
| 73 | def __str__(self): | ||
| 74 | return self.value | ||
| 75 | |||
| 76 | class KickstartValueError(KickstartError): | ||
| 77 | """An exception class for errors when processing arguments to commands, | ||
| 78 | such as too many arguments, too few arguments, or missing required | ||
| 79 | arguments. | ||
| 80 | """ | ||
| 81 | def __init__(self, msg): | ||
| 82 | """Create a new KickstartValueError exception instance with the | ||
| 83 | descriptive message val. val should be the return value of | ||
| 84 | formatErrorMsg. | ||
| 85 | """ | ||
| 86 | KickstartError.__init__(self, msg) | ||
| 87 | |||
| 88 | def __str__ (self): | ||
| 89 | return self.value | ||
| 90 | |||
| 91 | class KickstartVersionError(KickstartError): | ||
| 92 | """An exception class for errors related to using an incorrect version of | ||
| 93 | kickstart syntax. | ||
| 94 | """ | ||
| 95 | def __init__(self, msg): | ||
| 96 | """Create a new KickstartVersionError exception instance with the | ||
| 97 | descriptive message val. val should be the return value of | ||
| 98 | formatErrorMsg. | ||
| 99 | """ | ||
| 100 | KickstartError.__init__(self, msg) | ||
| 101 | |||
| 102 | def __str__ (self): | ||
| 103 | return self.value | ||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/handlers/__init__.py b/scripts/lib/wic/3rdparty/pykickstart/handlers/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/handlers/__init__.py | |||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/handlers/control.py b/scripts/lib/wic/3rdparty/pykickstart/handlers/control.py new file mode 100644 index 0000000000..8dc80d1ebe --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/handlers/control.py | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | # | ||
| 2 | # Chris Lumens <clumens@redhat.com> | ||
| 3 | # | ||
| 4 | # Copyright 2007, 2008, 2009, 2010 Red Hat, Inc. | ||
| 5 | # | ||
| 6 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 7 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 8 | # General Public License v.2. This program is distributed in the hope that it | ||
| 9 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 10 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 11 | # See the GNU General Public License for more details. | ||
| 12 | # | ||
| 13 | # You should have received a copy of the GNU General Public License along with | ||
| 14 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 15 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat | ||
| 16 | # trademarks that are incorporated in the source code or documentation are not | ||
| 17 | # subject to the GNU General Public License and may only be used or replicated | ||
| 18 | # with the express permission of Red Hat, Inc. | ||
| 19 | # | ||
| 20 | from pykickstart.version import * | ||
| 21 | from pykickstart.commands import * | ||
| 22 | |||
| 23 | # This map is keyed on kickstart syntax version as provided by | ||
| 24 | # pykickstart.version. Within each sub-dict is a mapping from command name | ||
| 25 | # to the class that handles it. This is an onto mapping - that is, multiple | ||
| 26 | # command names can map to the same class. However, the Handler will ensure | ||
| 27 | # that only one instance of each class ever exists. | ||
| 28 | commandMap = { | ||
| 29 | # based on f15 | ||
| 30 | F16: { | ||
| 31 | "bootloader": bootloader.F15_Bootloader, | ||
| 32 | "part": partition.F14_Partition, | ||
| 33 | "partition": partition.F14_Partition, | ||
| 34 | }, | ||
| 35 | } | ||
| 36 | |||
| 37 | # This map is keyed on kickstart syntax version as provided by | ||
| 38 | # pykickstart.version. Within each sub-dict is a mapping from a data object | ||
| 39 | # name to the class that provides it. This is a bijective mapping - that is, | ||
| 40 | # each name maps to exactly one data class and all data classes have a name. | ||
| 41 | # More than one instance of each class is allowed to exist, however. | ||
| 42 | dataMap = { | ||
| 43 | F16: { | ||
| 44 | "PartData": partition.F14_PartData, | ||
| 45 | }, | ||
| 46 | } | ||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/handlers/f16.py b/scripts/lib/wic/3rdparty/pykickstart/handlers/f16.py new file mode 100644 index 0000000000..3c52f8d754 --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/handlers/f16.py | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | # | ||
| 2 | # Chris Lumens <clumens@redhat.com> | ||
| 3 | # | ||
| 4 | # Copyright 2011 Red Hat, Inc. | ||
| 5 | # | ||
| 6 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 7 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 8 | # General Public License v.2. This program is distributed in the hope that it | ||
| 9 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 10 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 11 | # See the GNU General Public License for more details. | ||
| 12 | # | ||
| 13 | # You should have received a copy of the GNU General Public License along with | ||
| 14 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 15 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat | ||
| 16 | # trademarks that are incorporated in the source code or documentation are not | ||
| 17 | # subject to the GNU General Public License and may only be used or replicated | ||
| 18 | # with the express permission of Red Hat, Inc. | ||
| 19 | # | ||
| 20 | from pykickstart.base import * | ||
| 21 | from pykickstart.version import * | ||
| 22 | |||
| 23 | class F16Handler(BaseHandler): | ||
| 24 | version = F16 | ||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/ko.py b/scripts/lib/wic/3rdparty/pykickstart/ko.py new file mode 100644 index 0000000000..1350d19c70 --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/ko.py | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | # | ||
| 2 | # Chris Lumens <clumens@redhat.com> | ||
| 3 | # | ||
| 4 | # Copyright 2009 Red Hat, Inc. | ||
| 5 | # | ||
| 6 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 7 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 8 | # General Public License v.2. This program is distributed in the hope that it | ||
| 9 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 10 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 11 | # See the GNU General Public License for more details. | ||
| 12 | # | ||
| 13 | # You should have received a copy of the GNU General Public License along with | ||
| 14 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 15 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat | ||
| 16 | # trademarks that are incorporated in the source code or documentation are not | ||
| 17 | # subject to the GNU General Public License and may only be used or replicated | ||
| 18 | # with the express permission of Red Hat, Inc. | ||
| 19 | # | ||
| 20 | """ | ||
| 21 | Base classes for internal pykickstart use. | ||
| 22 | |||
| 23 | The module exports the following important classes: | ||
| 24 | |||
| 25 | KickstartObject - The base class for all classes in pykickstart | ||
| 26 | """ | ||
| 27 | |||
| 28 | class KickstartObject(object): | ||
| 29 | """The base class for all other classes in pykickstart.""" | ||
| 30 | def __init__(self, *args, **kwargs): | ||
| 31 | """Create a new KickstartObject instance. All other classes in | ||
| 32 | pykickstart should be derived from this one. Instance attributes: | ||
| 33 | """ | ||
| 34 | pass | ||
| 35 | |||
| 36 | def __str__(self): | ||
| 37 | return "" | ||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/options.py b/scripts/lib/wic/3rdparty/pykickstart/options.py new file mode 100644 index 0000000000..341c5d7298 --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/options.py | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | # | ||
| 2 | # Chris Lumens <clumens@redhat.com> | ||
| 3 | # | ||
| 4 | # Copyright 2005, 2006, 2007 Red Hat, Inc. | ||
| 5 | # | ||
| 6 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 7 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 8 | # General Public License v.2. This program is distributed in the hope that it | ||
| 9 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 10 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 11 | # See the GNU General Public License for more details. | ||
| 12 | # | ||
| 13 | # You should have received a copy of the GNU General Public License along with | ||
| 14 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 15 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat | ||
| 16 | # trademarks that are incorporated in the source code or documentation are not | ||
| 17 | # subject to the GNU General Public License and may only be used or replicated | ||
| 18 | # with the express permission of Red Hat, Inc. | ||
| 19 | # | ||
| 20 | """ | ||
| 21 | Specialized option handling. | ||
| 22 | |||
| 23 | This module exports two classes: | ||
| 24 | |||
| 25 | KSOptionParser - A specialized subclass of OptionParser to be used | ||
| 26 | in BaseHandler subclasses. | ||
| 27 | |||
| 28 | KSOption - A specialized subclass of Option. | ||
| 29 | """ | ||
| 30 | import warnings | ||
| 31 | from copy import copy | ||
| 32 | from optparse import * | ||
| 33 | |||
| 34 | from constants import * | ||
| 35 | from errors import * | ||
| 36 | from version import * | ||
| 37 | |||
| 38 | import gettext | ||
| 39 | _ = lambda x: gettext.ldgettext("pykickstart", x) | ||
| 40 | |||
| 41 | class KSOptionParser(OptionParser): | ||
| 42 | """A specialized subclass of optparse.OptionParser to handle extra option | ||
| 43 | attribute checking, work error reporting into the KickstartParseError | ||
| 44 | framework, and to turn off the default help. | ||
| 45 | """ | ||
| 46 | def exit(self, status=0, msg=None): | ||
| 47 | pass | ||
| 48 | |||
| 49 | def error(self, msg): | ||
| 50 | if self.lineno != None: | ||
| 51 | raise KickstartParseError, formatErrorMsg(self.lineno, msg=msg) | ||
| 52 | else: | ||
| 53 | raise KickstartParseError, msg | ||
| 54 | |||
| 55 | def keys(self): | ||
| 56 | retval = [] | ||
| 57 | |||
| 58 | for opt in self.option_list: | ||
| 59 | if opt not in retval: | ||
| 60 | retval.append(opt.dest) | ||
| 61 | |||
| 62 | return retval | ||
| 63 | |||
| 64 | def _init_parsing_state (self): | ||
| 65 | OptionParser._init_parsing_state(self) | ||
| 66 | self.option_seen = {} | ||
| 67 | |||
| 68 | def check_values (self, values, args): | ||
| 69 | def seen(self, option): | ||
| 70 | return self.option_seen.has_key(option) | ||
| 71 | |||
| 72 | def usedTooNew(self, option): | ||
| 73 | return option.introduced and option.introduced > self.version | ||
| 74 | |||
| 75 | def usedDeprecated(self, option): | ||
| 76 | return option.deprecated | ||
| 77 | |||
| 78 | def usedRemoved(self, option): | ||
| 79 | return option.removed and option.removed <= self.version | ||
| 80 | |||
| 81 | for option in filter(lambda o: isinstance(o, Option), self.option_list): | ||
| 82 | if option.required and not seen(self, option): | ||
| 83 | raise KickstartValueError, formatErrorMsg(self.lineno, _("Option %s is required") % option) | ||
| 84 | elif seen(self, option) and usedTooNew(self, option): | ||
| 85 | mapping = {"option": option, "intro": versionToString(option.introduced), | ||
| 86 | "version": versionToString(self.version)} | ||
| 87 | self.error(_("The %(option)s option was introduced in version %(intro)s, but you are using kickstart syntax version %(version)s.") % mapping) | ||
| 88 | elif seen(self, option) and usedRemoved(self, option): | ||
| 89 | mapping = {"option": option, "removed": versionToString(option.removed), | ||
| 90 | "version": versionToString(self.version)} | ||
| 91 | |||
| 92 | if option.removed == self.version: | ||
| 93 | self.error(_("The %(option)s option is no longer supported.") % mapping) | ||
| 94 | else: | ||
| 95 | self.error(_("The %(option)s option was removed in version %(removed)s, but you are using kickstart syntax version %(version)s.") % mapping) | ||
| 96 | elif seen(self, option) and usedDeprecated(self, option): | ||
| 97 | mapping = {"lineno": self.lineno, "option": option} | ||
| 98 | warnings.warn(_("Ignoring deprecated option on line %(lineno)s: The %(option)s option has been deprecated and no longer has any effect. It may be removed from future releases, which will result in a fatal error from kickstart. Please modify your kickstart file to remove this option.") % mapping, DeprecationWarning) | ||
| 99 | |||
| 100 | return (values, args) | ||
| 101 | |||
| 102 | def parse_args(self, *args, **kwargs): | ||
| 103 | if kwargs.has_key("lineno"): | ||
| 104 | self.lineno = kwargs.pop("lineno") | ||
| 105 | |||
| 106 | return OptionParser.parse_args(self, **kwargs) | ||
| 107 | |||
| 108 | def __init__(self, mapping=None, version=None): | ||
| 109 | """Create a new KSOptionParser instance. Each KickstartCommand | ||
| 110 | subclass should create one instance of KSOptionParser, providing | ||
| 111 | at least the lineno attribute. mapping and version are not required. | ||
| 112 | Instance attributes: | ||
| 113 | |||
| 114 | mapping -- A mapping from option strings to different values. | ||
| 115 | version -- The version of the kickstart syntax we are checking | ||
| 116 | against. | ||
| 117 | """ | ||
| 118 | OptionParser.__init__(self, option_class=KSOption, | ||
| 119 | add_help_option=False, | ||
| 120 | conflict_handler="resolve") | ||
| 121 | if mapping is None: | ||
| 122 | self.map = {} | ||
| 123 | else: | ||
| 124 | self.map = mapping | ||
| 125 | |||
| 126 | self.lineno = None | ||
| 127 | self.option_seen = {} | ||
| 128 | self.version = version | ||
| 129 | |||
| 130 | def _check_ksboolean(option, opt, value): | ||
| 131 | if value.lower() in ("on", "yes", "true", "1"): | ||
| 132 | return True | ||
| 133 | elif value.lower() in ("off", "no", "false", "0"): | ||
| 134 | return False | ||
| 135 | else: | ||
| 136 | mapping = {"opt": opt, "value": value} | ||
| 137 | raise OptionValueError(_("Option %(opt)s: invalid boolean value: %(value)r") % mapping) | ||
| 138 | |||
| 139 | def _check_string(option, opt, value): | ||
| 140 | if len(value) > 2 and value.startswith("--"): | ||
| 141 | mapping = {"opt": opt, "value": value} | ||
| 142 | raise OptionValueError(_("Option %(opt)s: invalid string value: %(value)r") % mapping) | ||
| 143 | else: | ||
| 144 | return value | ||
| 145 | |||
| 146 | # Creates a new Option class that supports several new attributes: | ||
| 147 | # - required: any option with this attribute must be supplied or an exception | ||
| 148 | # is thrown | ||
| 149 | # - introduced: the kickstart syntax version that this option first appeared | ||
| 150 | # in - an exception will be raised if the option is used and | ||
| 151 | # the specified syntax version is less than the value of this | ||
| 152 | # attribute | ||
| 153 | # - deprecated: the kickstart syntax version that this option was deprecated | ||
| 154 | # in - a DeprecationWarning will be thrown if the option is | ||
| 155 | # used and the specified syntax version is greater than the | ||
| 156 | # value of this attribute | ||
| 157 | # - removed: the kickstart syntax version that this option was removed in - an | ||
| 158 | # exception will be raised if the option is used and the specified | ||
| 159 | # syntax version is greated than the value of this attribute | ||
| 160 | # Also creates a new type: | ||
| 161 | # - ksboolean: support various kinds of boolean values on an option | ||
| 162 | # And two new actions: | ||
| 163 | # - map : allows you to define an opt -> val mapping such that dest gets val | ||
| 164 | # when opt is seen | ||
| 165 | # - map_extend: allows you to define an opt -> [val1, ... valn] mapping such | ||
| 166 | # that dest gets a list of vals built up when opt is seen | ||
| 167 | class KSOption (Option): | ||
| 168 | ATTRS = Option.ATTRS + ['introduced', 'deprecated', 'removed', 'required'] | ||
| 169 | ACTIONS = Option.ACTIONS + ("map", "map_extend",) | ||
| 170 | STORE_ACTIONS = Option.STORE_ACTIONS + ("map", "map_extend",) | ||
| 171 | |||
| 172 | TYPES = Option.TYPES + ("ksboolean", "string") | ||
| 173 | TYPE_CHECKER = copy(Option.TYPE_CHECKER) | ||
| 174 | TYPE_CHECKER["ksboolean"] = _check_ksboolean | ||
| 175 | TYPE_CHECKER["string"] = _check_string | ||
| 176 | |||
| 177 | def _check_required(self): | ||
| 178 | if self.required and not self.takes_value(): | ||
| 179 | raise OptionError(_("Required flag set for option that doesn't take a value"), self) | ||
| 180 | |||
| 181 | # Make sure _check_required() is called from the constructor! | ||
| 182 | CHECK_METHODS = Option.CHECK_METHODS + [_check_required] | ||
| 183 | |||
| 184 | def process (self, opt, value, values, parser): | ||
| 185 | Option.process(self, opt, value, values, parser) | ||
| 186 | parser.option_seen[self] = 1 | ||
| 187 | |||
| 188 | # Override default take_action method to handle our custom actions. | ||
| 189 | def take_action(self, action, dest, opt, value, values, parser): | ||
| 190 | if action == "map": | ||
| 191 | values.ensure_value(dest, parser.map[opt.lstrip('-')]) | ||
| 192 | elif action == "map_extend": | ||
| 193 | values.ensure_value(dest, []).extend(parser.map[opt.lstrip('-')]) | ||
| 194 | else: | ||
| 195 | Option.take_action(self, action, dest, opt, value, values, parser) | ||
| 196 | |||
| 197 | def takes_value(self): | ||
| 198 | # Deprecated options don't take a value. | ||
| 199 | return Option.takes_value(self) and not self.deprecated | ||
| 200 | |||
| 201 | def __init__(self, *args, **kwargs): | ||
| 202 | self.deprecated = False | ||
| 203 | self.required = False | ||
| 204 | Option.__init__(self, *args, **kwargs) | ||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/parser.py b/scripts/lib/wic/3rdparty/pykickstart/parser.py new file mode 100644 index 0000000000..9c9674bf73 --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/parser.py | |||
| @@ -0,0 +1,619 @@ | |||
| 1 | # | ||
| 2 | # parser.py: Kickstart file parser. | ||
| 3 | # | ||
| 4 | # Chris Lumens <clumens@redhat.com> | ||
| 5 | # | ||
| 6 | # Copyright 2005, 2006, 2007, 2008, 2011 Red Hat, Inc. | ||
| 7 | # | ||
| 8 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 9 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 10 | # General Public License v.2. This program is distributed in the hope that it | ||
| 11 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 12 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 13 | # See the GNU General Public License for more details. | ||
| 14 | # | ||
| 15 | # You should have received a copy of the GNU General Public License along with | ||
| 16 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 17 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat | ||
| 18 | # trademarks that are incorporated in the source code or documentation are not | ||
| 19 | # subject to the GNU General Public License and may only be used or replicated | ||
| 20 | # with the express permission of Red Hat, Inc. | ||
| 21 | # | ||
| 22 | """ | ||
| 23 | Main kickstart file processing module. | ||
| 24 | |||
| 25 | This module exports several important classes: | ||
| 26 | |||
| 27 | Script - Representation of a single %pre, %post, or %traceback script. | ||
| 28 | |||
| 29 | Packages - Representation of the %packages section. | ||
| 30 | |||
| 31 | KickstartParser - The kickstart file parser state machine. | ||
| 32 | """ | ||
| 33 | |||
| 34 | from collections import Iterator | ||
| 35 | import os | ||
| 36 | import shlex | ||
| 37 | import sys | ||
| 38 | import tempfile | ||
| 39 | from copy import copy | ||
| 40 | from optparse import * | ||
| 41 | |||
| 42 | import constants | ||
| 43 | from errors import KickstartError, KickstartParseError, KickstartValueError, formatErrorMsg | ||
| 44 | from ko import KickstartObject | ||
| 45 | from sections import * | ||
| 46 | import version | ||
| 47 | |||
| 48 | import gettext | ||
| 49 | _ = lambda x: gettext.ldgettext("pykickstart", x) | ||
| 50 | |||
| 51 | STATE_END = "end" | ||
| 52 | STATE_COMMANDS = "commands" | ||
| 53 | |||
| 54 | ver = version.DEVEL | ||
| 55 | |||
| 56 | |||
| 57 | class PutBackIterator(Iterator): | ||
| 58 | def __init__(self, iterable): | ||
| 59 | self._iterable = iter(iterable) | ||
| 60 | self._buf = None | ||
| 61 | |||
| 62 | def __iter__(self): | ||
| 63 | return self | ||
| 64 | |||
| 65 | def put(self, s): | ||
| 66 | self._buf = s | ||
| 67 | |||
| 68 | def next(self): | ||
| 69 | if self._buf: | ||
| 70 | retval = self._buf | ||
| 71 | self._buf = None | ||
| 72 | return retval | ||
| 73 | else: | ||
| 74 | return self._iterable.next() | ||
| 75 | |||
| 76 | ### | ||
| 77 | ### SCRIPT HANDLING | ||
| 78 | ### | ||
| 79 | class Script(KickstartObject): | ||
| 80 | """A class representing a single kickstart script. If functionality beyond | ||
| 81 | just a data representation is needed (for example, a run method in | ||
| 82 | anaconda), Script may be subclassed. Although a run method is not | ||
| 83 | provided, most of the attributes of Script have to do with running the | ||
| 84 | script. Instances of Script are held in a list by the Version object. | ||
| 85 | """ | ||
| 86 | def __init__(self, script, *args , **kwargs): | ||
| 87 | """Create a new Script instance. Instance attributes: | ||
| 88 | |||
| 89 | errorOnFail -- If execution of the script fails, should anaconda | ||
| 90 | stop, display an error, and then reboot without | ||
| 91 | running any other scripts? | ||
| 92 | inChroot -- Does the script execute in anaconda's chroot | ||
| 93 | environment or not? | ||
| 94 | interp -- The program that should be used to interpret this | ||
| 95 | script. | ||
| 96 | lineno -- The line number this script starts on. | ||
| 97 | logfile -- Where all messages from the script should be logged. | ||
| 98 | script -- A string containing all the lines of the script. | ||
| 99 | type -- The type of the script, which can be KS_SCRIPT_* from | ||
| 100 | pykickstart.constants. | ||
| 101 | """ | ||
| 102 | KickstartObject.__init__(self, *args, **kwargs) | ||
| 103 | self.script = "".join(script) | ||
| 104 | |||
| 105 | self.interp = kwargs.get("interp", "/bin/sh") | ||
| 106 | self.inChroot = kwargs.get("inChroot", False) | ||
| 107 | self.lineno = kwargs.get("lineno", None) | ||
| 108 | self.logfile = kwargs.get("logfile", None) | ||
| 109 | self.errorOnFail = kwargs.get("errorOnFail", False) | ||
| 110 | self.type = kwargs.get("type", constants.KS_SCRIPT_PRE) | ||
| 111 | |||
| 112 | def __str__(self): | ||
| 113 | """Return a string formatted for output to a kickstart file.""" | ||
| 114 | retval = "" | ||
| 115 | |||
| 116 | if self.type == constants.KS_SCRIPT_PRE: | ||
| 117 | retval += '\n%pre' | ||
| 118 | elif self.type == constants.KS_SCRIPT_POST: | ||
| 119 | retval += '\n%post' | ||
| 120 | elif self.type == constants.KS_SCRIPT_TRACEBACK: | ||
| 121 | retval += '\n%traceback' | ||
| 122 | |||
| 123 | if self.interp != "/bin/sh" and self.interp != "": | ||
| 124 | retval += " --interpreter=%s" % self.interp | ||
| 125 | if self.type == constants.KS_SCRIPT_POST and not self.inChroot: | ||
| 126 | retval += " --nochroot" | ||
| 127 | if self.logfile != None: | ||
| 128 | retval += " --logfile %s" % self.logfile | ||
| 129 | if self.errorOnFail: | ||
| 130 | retval += " --erroronfail" | ||
| 131 | |||
| 132 | if self.script.endswith("\n"): | ||
| 133 | if ver >= version.F8: | ||
| 134 | return retval + "\n%s%%end\n" % self.script | ||
| 135 | else: | ||
| 136 | return retval + "\n%s\n" % self.script | ||
| 137 | else: | ||
| 138 | if ver >= version.F8: | ||
| 139 | return retval + "\n%s\n%%end\n" % self.script | ||
| 140 | else: | ||
| 141 | return retval + "\n%s\n" % self.script | ||
| 142 | |||
| 143 | |||
| 144 | ## | ||
| 145 | ## PACKAGE HANDLING | ||
| 146 | ## | ||
| 147 | class Group: | ||
| 148 | """A class representing a single group in the %packages section.""" | ||
| 149 | def __init__(self, name="", include=constants.GROUP_DEFAULT): | ||
| 150 | """Create a new Group instance. Instance attributes: | ||
| 151 | |||
| 152 | name -- The group's identifier | ||
| 153 | include -- The level of how much of the group should be included. | ||
| 154 | Values can be GROUP_* from pykickstart.constants. | ||
| 155 | """ | ||
| 156 | self.name = name | ||
| 157 | self.include = include | ||
| 158 | |||
| 159 | def __str__(self): | ||
| 160 | """Return a string formatted for output to a kickstart file.""" | ||
| 161 | if self.include == constants.GROUP_REQUIRED: | ||
| 162 | return "@%s --nodefaults" % self.name | ||
| 163 | elif self.include == constants.GROUP_ALL: | ||
| 164 | return "@%s --optional" % self.name | ||
| 165 | else: | ||
| 166 | return "@%s" % self.name | ||
| 167 | |||
| 168 | def __cmp__(self, other): | ||
| 169 | if self.name < other.name: | ||
| 170 | return -1 | ||
| 171 | elif self.name > other.name: | ||
| 172 | return 1 | ||
| 173 | return 0 | ||
| 174 | |||
| 175 | class Packages(KickstartObject): | ||
| 176 | """A class representing the %packages section of the kickstart file.""" | ||
| 177 | def __init__(self, *args, **kwargs): | ||
| 178 | """Create a new Packages instance. Instance attributes: | ||
| 179 | |||
| 180 | addBase -- Should the Base group be installed even if it is | ||
| 181 | not specified? | ||
| 182 | default -- Should the default package set be selected? | ||
| 183 | excludedList -- A list of all the packages marked for exclusion in | ||
| 184 | the %packages section, without the leading minus | ||
| 185 | symbol. | ||
| 186 | excludeDocs -- Should documentation in each package be excluded? | ||
| 187 | groupList -- A list of Group objects representing all the groups | ||
| 188 | specified in the %packages section. Names will be | ||
| 189 | stripped of the leading @ symbol. | ||
| 190 | excludedGroupList -- A list of Group objects representing all the | ||
| 191 | groups specified for removal in the %packages | ||
| 192 | section. Names will be stripped of the leading | ||
| 193 | -@ symbols. | ||
| 194 | handleMissing -- If unknown packages are specified in the %packages | ||
| 195 | section, should it be ignored or not? Values can | ||
| 196 | be KS_MISSING_* from pykickstart.constants. | ||
| 197 | packageList -- A list of all the packages specified in the | ||
| 198 | %packages section. | ||
| 199 | instLangs -- A list of languages to install. | ||
| 200 | """ | ||
| 201 | KickstartObject.__init__(self, *args, **kwargs) | ||
| 202 | |||
| 203 | self.addBase = True | ||
| 204 | self.default = False | ||
| 205 | self.excludedList = [] | ||
| 206 | self.excludedGroupList = [] | ||
| 207 | self.excludeDocs = False | ||
| 208 | self.groupList = [] | ||
| 209 | self.handleMissing = constants.KS_MISSING_PROMPT | ||
| 210 | self.packageList = [] | ||
| 211 | self.instLangs = None | ||
| 212 | |||
| 213 | def __str__(self): | ||
| 214 | """Return a string formatted for output to a kickstart file.""" | ||
| 215 | pkgs = "" | ||
| 216 | |||
| 217 | if not self.default: | ||
| 218 | grps = self.groupList | ||
| 219 | grps.sort() | ||
| 220 | for grp in grps: | ||
| 221 | pkgs += "%s\n" % grp.__str__() | ||
| 222 | |||
| 223 | p = self.packageList | ||
| 224 | p.sort() | ||
| 225 | for pkg in p: | ||
| 226 | pkgs += "%s\n" % pkg | ||
| 227 | |||
| 228 | grps = self.excludedGroupList | ||
| 229 | grps.sort() | ||
| 230 | for grp in grps: | ||
| 231 | pkgs += "-%s\n" % grp.__str__() | ||
| 232 | |||
| 233 | p = self.excludedList | ||
| 234 | p.sort() | ||
| 235 | for pkg in p: | ||
| 236 | pkgs += "-%s\n" % pkg | ||
| 237 | |||
| 238 | if pkgs == "": | ||
| 239 | return "" | ||
| 240 | |||
| 241 | retval = "\n%packages" | ||
| 242 | |||
| 243 | if self.default: | ||
| 244 | retval += " --default" | ||
| 245 | if self.excludeDocs: | ||
| 246 | retval += " --excludedocs" | ||
| 247 | if not self.addBase: | ||
| 248 | retval += " --nobase" | ||
| 249 | if self.handleMissing == constants.KS_MISSING_IGNORE: | ||
| 250 | retval += " --ignoremissing" | ||
| 251 | if self.instLangs: | ||
| 252 | retval += " --instLangs=%s" % self.instLangs | ||
| 253 | |||
| 254 | if ver >= version.F8: | ||
| 255 | return retval + "\n" + pkgs + "\n%end\n" | ||
| 256 | else: | ||
| 257 | return retval + "\n" + pkgs + "\n" | ||
| 258 | |||
| 259 | def _processGroup (self, line): | ||
| 260 | op = OptionParser() | ||
| 261 | op.add_option("--nodefaults", action="store_true", default=False) | ||
| 262 | op.add_option("--optional", action="store_true", default=False) | ||
| 263 | |||
| 264 | (opts, extra) = op.parse_args(args=line.split()) | ||
| 265 | |||
| 266 | if opts.nodefaults and opts.optional: | ||
| 267 | raise KickstartValueError, _("Group cannot specify both --nodefaults and --optional") | ||
| 268 | |||
| 269 | # If the group name has spaces in it, we have to put it back together | ||
| 270 | # now. | ||
| 271 | grp = " ".join(extra) | ||
| 272 | |||
| 273 | if opts.nodefaults: | ||
| 274 | self.groupList.append(Group(name=grp, include=constants.GROUP_REQUIRED)) | ||
| 275 | elif opts.optional: | ||
| 276 | self.groupList.append(Group(name=grp, include=constants.GROUP_ALL)) | ||
| 277 | else: | ||
| 278 | self.groupList.append(Group(name=grp, include=constants.GROUP_DEFAULT)) | ||
| 279 | |||
| 280 | def add (self, pkgList): | ||
| 281 | """Given a list of lines from the input file, strip off any leading | ||
| 282 | symbols and add the result to the appropriate list. | ||
| 283 | """ | ||
| 284 | existingExcludedSet = set(self.excludedList) | ||
| 285 | existingPackageSet = set(self.packageList) | ||
| 286 | newExcludedSet = set() | ||
| 287 | newPackageSet = set() | ||
| 288 | |||
| 289 | excludedGroupList = [] | ||
| 290 | |||
| 291 | for pkg in pkgList: | ||
| 292 | stripped = pkg.strip() | ||
| 293 | |||
| 294 | if stripped[0] == "@": | ||
| 295 | self._processGroup(stripped[1:]) | ||
| 296 | elif stripped[0] == "-": | ||
| 297 | if stripped[1] == "@": | ||
| 298 | excludedGroupList.append(Group(name=stripped[2:])) | ||
| 299 | else: | ||
| 300 | newExcludedSet.add(stripped[1:]) | ||
| 301 | else: | ||
| 302 | newPackageSet.add(stripped) | ||
| 303 | |||
| 304 | # Groups have to be excluded in two different ways (note: can't use | ||
| 305 | # sets here because we have to store objects): | ||
| 306 | excludedGroupNames = map(lambda g: g.name, excludedGroupList) | ||
| 307 | |||
| 308 | # First, an excluded group may be cancelling out a previously given | ||
| 309 | # one. This is often the case when using %include. So there we should | ||
| 310 | # just remove the group from the list. | ||
| 311 | self.groupList = filter(lambda g: g.name not in excludedGroupNames, self.groupList) | ||
| 312 | |||
| 313 | # Second, the package list could have included globs which are not | ||
| 314 | # processed by pykickstart. In that case we need to preserve a list of | ||
| 315 | # excluded groups so whatever tool doing package/group installation can | ||
| 316 | # take appropriate action. | ||
| 317 | self.excludedGroupList.extend(excludedGroupList) | ||
| 318 | |||
| 319 | existingPackageSet = (existingPackageSet - newExcludedSet) | newPackageSet | ||
| 320 | existingExcludedSet = (existingExcludedSet - existingPackageSet) | newExcludedSet | ||
| 321 | |||
| 322 | self.packageList = list(existingPackageSet) | ||
| 323 | self.excludedList = list(existingExcludedSet) | ||
| 324 | |||
| 325 | |||
| 326 | ### | ||
| 327 | ### PARSER | ||
| 328 | ### | ||
| 329 | class KickstartParser: | ||
| 330 | """The kickstart file parser class as represented by a basic state | ||
| 331 | machine. To create a specialized parser, make a subclass and override | ||
| 332 | any of the methods you care about. Methods that don't need to do | ||
| 333 | anything may just pass. However, _stateMachine should never be | ||
| 334 | overridden. | ||
| 335 | """ | ||
| 336 | def __init__ (self, handler, followIncludes=True, errorsAreFatal=True, | ||
| 337 | missingIncludeIsFatal=True): | ||
| 338 | """Create a new KickstartParser instance. Instance attributes: | ||
| 339 | |||
| 340 | errorsAreFatal -- Should errors cause processing to halt, or | ||
| 341 | just print a message to the screen? This | ||
| 342 | is most useful for writing syntax checkers | ||
| 343 | that may want to continue after an error is | ||
| 344 | encountered. | ||
| 345 | followIncludes -- If %include is seen, should the included | ||
| 346 | file be checked as well or skipped? | ||
| 347 | handler -- An instance of a BaseHandler subclass. If | ||
| 348 | None, the input file will still be parsed | ||
| 349 | but no data will be saved and no commands | ||
| 350 | will be executed. | ||
| 351 | missingIncludeIsFatal -- Should missing include files be fatal, even | ||
| 352 | if errorsAreFatal is False? | ||
| 353 | """ | ||
| 354 | self.errorsAreFatal = errorsAreFatal | ||
| 355 | self.followIncludes = followIncludes | ||
| 356 | self.handler = handler | ||
| 357 | self.currentdir = {} | ||
| 358 | self.missingIncludeIsFatal = missingIncludeIsFatal | ||
| 359 | |||
| 360 | self._state = STATE_COMMANDS | ||
| 361 | self._includeDepth = 0 | ||
| 362 | self._line = "" | ||
| 363 | |||
| 364 | self.version = self.handler.version | ||
| 365 | |||
| 366 | global ver | ||
| 367 | ver = self.version | ||
| 368 | |||
| 369 | self._sections = {} | ||
| 370 | self.setupSections() | ||
| 371 | |||
| 372 | def _reset(self): | ||
| 373 | """Reset the internal variables of the state machine for a new kickstart file.""" | ||
| 374 | self._state = STATE_COMMANDS | ||
| 375 | self._includeDepth = 0 | ||
| 376 | |||
| 377 | def getSection(self, s): | ||
| 378 | """Return a reference to the requested section (s must start with '%'s), | ||
| 379 | or raise KeyError if not found. | ||
| 380 | """ | ||
| 381 | return self._sections[s] | ||
| 382 | |||
| 383 | def handleCommand (self, lineno, args): | ||
| 384 | """Given the list of command and arguments, call the Version's | ||
| 385 | dispatcher method to handle the command. Returns the command or | ||
| 386 | data object returned by the dispatcher. This method may be | ||
| 387 | overridden in a subclass if necessary. | ||
| 388 | """ | ||
| 389 | if self.handler: | ||
| 390 | self.handler.currentCmd = args[0] | ||
| 391 | self.handler.currentLine = self._line | ||
| 392 | retval = self.handler.dispatcher(args, lineno) | ||
| 393 | |||
| 394 | return retval | ||
| 395 | |||
| 396 | def registerSection(self, obj): | ||
| 397 | """Given an instance of a Section subclass, register the new section | ||
| 398 | with the parser. Calling this method means the parser will | ||
| 399 | recognize your new section and dispatch into the given object to | ||
| 400 | handle it. | ||
| 401 | """ | ||
| 402 | if not obj.sectionOpen: | ||
| 403 | raise TypeError, "no sectionOpen given for section %s" % obj | ||
| 404 | |||
| 405 | if not obj.sectionOpen.startswith("%"): | ||
| 406 | raise TypeError, "section %s tag does not start with a %%" % obj.sectionOpen | ||
| 407 | |||
| 408 | self._sections[obj.sectionOpen] = obj | ||
| 409 | |||
| 410 | def _finalize(self, obj): | ||
| 411 | """Called at the close of a kickstart section to take any required | ||
| 412 | actions. Internally, this is used to add scripts once we have the | ||
| 413 | whole body read. | ||
| 414 | """ | ||
| 415 | obj.finalize() | ||
| 416 | self._state = STATE_COMMANDS | ||
| 417 | |||
| 418 | def _handleSpecialComments(self, line): | ||
| 419 | """Kickstart recognizes a couple special comments.""" | ||
| 420 | if self._state != STATE_COMMANDS: | ||
| 421 | return | ||
| 422 | |||
| 423 | # Save the platform for s-c-kickstart. | ||
| 424 | if line[:10] == "#platform=": | ||
| 425 | self.handler.platform = self._line[11:] | ||
| 426 | |||
| 427 | def _readSection(self, lineIter, lineno): | ||
| 428 | obj = self._sections[self._state] | ||
| 429 | |||
| 430 | while True: | ||
| 431 | try: | ||
| 432 | line = lineIter.next() | ||
| 433 | if line == "": | ||
| 434 | # This section ends at the end of the file. | ||
| 435 | if self.version >= version.F8: | ||
| 436 | raise KickstartParseError, formatErrorMsg(lineno, msg=_("Section does not end with %%end.")) | ||
| 437 | |||
| 438 | self._finalize(obj) | ||
| 439 | except StopIteration: | ||
| 440 | break | ||
| 441 | |||
| 442 | lineno += 1 | ||
| 443 | |||
| 444 | # Throw away blank lines and comments, unless the section wants all | ||
| 445 | # lines. | ||
| 446 | if self._isBlankOrComment(line) and not obj.allLines: | ||
| 447 | continue | ||
| 448 | |||
| 449 | if line.startswith("%"): | ||
| 450 | args = shlex.split(line) | ||
| 451 | |||
| 452 | if args and args[0] == "%end": | ||
| 453 | # This is a properly terminated section. | ||
| 454 | self._finalize(obj) | ||
| 455 | break | ||
| 456 | elif args and args[0] == "%ksappend": | ||
| 457 | continue | ||
| 458 | elif args and (self._validState(args[0]) or args[0] in ["%include", "%ksappend"]): | ||
| 459 | # This is an unterminated section. | ||
| 460 | if self.version >= version.F8: | ||
| 461 | raise KickstartParseError, formatErrorMsg(lineno, msg=_("Section does not end with %%end.")) | ||
| 462 | |||
| 463 | # Finish up. We do not process the header here because | ||
| 464 | # kicking back out to STATE_COMMANDS will ensure that happens. | ||
| 465 | lineIter.put(line) | ||
| 466 | lineno -= 1 | ||
| 467 | self._finalize(obj) | ||
| 468 | break | ||
| 469 | else: | ||
| 470 | # This is just a line within a section. Pass it off to whatever | ||
| 471 | # section handles it. | ||
| 472 | obj.handleLine(line) | ||
| 473 | |||
| 474 | return lineno | ||
| 475 | |||
| 476 | def _validState(self, st): | ||
| 477 | """Is the given section tag one that has been registered with the parser?""" | ||
| 478 | return st in self._sections.keys() | ||
| 479 | |||
| 480 | def _tryFunc(self, fn): | ||
| 481 | """Call the provided function (which doesn't take any arguments) and | ||
| 482 | do the appropriate error handling. If errorsAreFatal is False, this | ||
| 483 | function will just print the exception and keep going. | ||
| 484 | """ | ||
| 485 | try: | ||
| 486 | fn() | ||
| 487 | except Exception, msg: | ||
| 488 | if self.errorsAreFatal: | ||
| 489 | raise | ||
| 490 | else: | ||
| 491 | print msg | ||
| 492 | |||
| 493 | def _isBlankOrComment(self, line): | ||
| 494 | return line.isspace() or line == "" or line.lstrip()[0] == '#' | ||
| 495 | |||
| 496 | def _stateMachine(self, lineIter): | ||
| 497 | # For error reporting. | ||
| 498 | lineno = 0 | ||
| 499 | |||
| 500 | while True: | ||
| 501 | # Get the next line out of the file, quitting if this is the last line. | ||
| 502 | try: | ||
| 503 | self._line = lineIter.next() | ||
| 504 | if self._line == "": | ||
| 505 | break | ||
| 506 | except StopIteration: | ||
| 507 | break | ||
| 508 | |||
| 509 | lineno += 1 | ||
| 510 | |||
| 511 | # Eliminate blank lines, whitespace-only lines, and comments. | ||
| 512 | if self._isBlankOrComment(self._line): | ||
| 513 | self._handleSpecialComments(self._line) | ||
| 514 | continue | ||
| 515 | |||
| 516 | # Remove any end-of-line comments. | ||
| 517 | sanitized = self._line.split("#")[0] | ||
| 518 | |||
| 519 | # Then split the line. | ||
| 520 | args = shlex.split(sanitized.rstrip()) | ||
| 521 | |||
| 522 | if args[0] == "%include": | ||
| 523 | # This case comes up primarily in ksvalidator. | ||
| 524 | if not self.followIncludes: | ||
| 525 | continue | ||
| 526 | |||
| 527 | if len(args) == 1 or not args[1]: | ||
| 528 | raise KickstartParseError, formatErrorMsg(lineno) | ||
| 529 | |||
| 530 | self._includeDepth += 1 | ||
| 531 | |||
| 532 | try: | ||
| 533 | self.readKickstart(args[1], reset=False) | ||
| 534 | except KickstartError: | ||
| 535 | # Handle the include file being provided over the | ||
| 536 | # network in a %pre script. This case comes up in the | ||
| 537 | # early parsing in anaconda. | ||
| 538 | if self.missingIncludeIsFatal: | ||
| 539 | raise | ||
| 540 | |||
| 541 | self._includeDepth -= 1 | ||
| 542 | continue | ||
| 543 | |||
| 544 | # Now on to the main event. | ||
| 545 | if self._state == STATE_COMMANDS: | ||
| 546 | if args[0] == "%ksappend": | ||
| 547 | # This is handled by the preprocess* functions, so continue. | ||
| 548 | continue | ||
| 549 | elif args[0][0] == '%': | ||
| 550 | # This is the beginning of a new section. Handle its header | ||
| 551 | # here. | ||
| 552 | newSection = args[0] | ||
| 553 | if not self._validState(newSection): | ||
| 554 | raise KickstartParseError, formatErrorMsg(lineno, msg=_("Unknown kickstart section: %s" % newSection)) | ||
| 555 | |||
| 556 | self._state = newSection | ||
| 557 | obj = self._sections[self._state] | ||
| 558 | self._tryFunc(lambda: obj.handleHeader(lineno, args)) | ||
| 559 | |||
| 560 | # This will handle all section processing, kicking us back | ||
| 561 | # out to STATE_COMMANDS at the end with the current line | ||
| 562 | # being the next section header, etc. | ||
| 563 | lineno = self._readSection(lineIter, lineno) | ||
| 564 | else: | ||
| 565 | # This is a command in the command section. Dispatch to it. | ||
| 566 | self._tryFunc(lambda: self.handleCommand(lineno, args)) | ||
| 567 | elif self._state == STATE_END: | ||
| 568 | break | ||
| 569 | |||
| 570 | def readKickstartFromString (self, s, reset=True): | ||
| 571 | """Process a kickstart file, provided as the string str.""" | ||
| 572 | if reset: | ||
| 573 | self._reset() | ||
| 574 | |||
| 575 | # Add a "" to the end of the list so the string reader acts like the | ||
| 576 | # file reader and we only get StopIteration when we're after the final | ||
| 577 | # line of input. | ||
| 578 | i = PutBackIterator(s.splitlines(True) + [""]) | ||
| 579 | self._stateMachine (i) | ||
| 580 | |||
| 581 | def readKickstart(self, f, reset=True): | ||
| 582 | """Process a kickstart file, given by the filename f.""" | ||
| 583 | if reset: | ||
| 584 | self._reset() | ||
| 585 | |||
| 586 | # an %include might not specify a full path. if we don't try to figure | ||
| 587 | # out what the path should have been, then we're unable to find it | ||
| 588 | # requiring full path specification, though, sucks. so let's make | ||
| 589 | # the reading "smart" by keeping track of what the path is at each | ||
| 590 | # include depth. | ||
| 591 | if not os.path.exists(f): | ||
| 592 | if self.currentdir.has_key(self._includeDepth - 1): | ||
| 593 | if os.path.exists(os.path.join(self.currentdir[self._includeDepth - 1], f)): | ||
| 594 | f = os.path.join(self.currentdir[self._includeDepth - 1], f) | ||
| 595 | |||
| 596 | cd = os.path.dirname(f) | ||
| 597 | if not cd.startswith("/"): | ||
| 598 | cd = os.path.abspath(cd) | ||
| 599 | self.currentdir[self._includeDepth] = cd | ||
| 600 | |||
| 601 | try: | ||
| 602 | s = file(f).read() | ||
| 603 | except IOError, e: | ||
| 604 | raise KickstartError, formatErrorMsg(0, msg=_("Unable to open input kickstart file: %s") % e.strerror) | ||
| 605 | |||
| 606 | self.readKickstartFromString(s, reset=False) | ||
| 607 | |||
| 608 | def setupSections(self): | ||
| 609 | """Install the sections all kickstart files support. You may override | ||
| 610 | this method in a subclass, but should avoid doing so unless you know | ||
| 611 | what you're doing. | ||
| 612 | """ | ||
| 613 | self._sections = {} | ||
| 614 | |||
| 615 | # Install the sections all kickstart files support. | ||
| 616 | self.registerSection(PreScriptSection(self.handler, dataObj=Script)) | ||
| 617 | self.registerSection(PostScriptSection(self.handler, dataObj=Script)) | ||
| 618 | self.registerSection(TracebackScriptSection(self.handler, dataObj=Script)) | ||
| 619 | self.registerSection(PackageSection(self.handler)) | ||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/sections.py b/scripts/lib/wic/3rdparty/pykickstart/sections.py new file mode 100644 index 0000000000..44df856b8d --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/sections.py | |||
| @@ -0,0 +1,244 @@ | |||
| 1 | # | ||
| 2 | # sections.py: Kickstart file sections. | ||
| 3 | # | ||
| 4 | # Chris Lumens <clumens@redhat.com> | ||
| 5 | # | ||
| 6 | # Copyright 2011 Red Hat, Inc. | ||
| 7 | # | ||
| 8 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 9 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 10 | # General Public License v.2. This program is distributed in the hope that it | ||
| 11 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 12 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 13 | # See the GNU General Public License for more details. | ||
| 14 | # | ||
| 15 | # You should have received a copy of the GNU General Public License along with | ||
| 16 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 17 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat | ||
| 18 | # trademarks that are incorporated in the source code or documentation are not | ||
| 19 | # subject to the GNU General Public License and may only be used or replicated | ||
| 20 | # with the express permission of Red Hat, Inc. | ||
| 21 | # | ||
| 22 | """ | ||
| 23 | This module exports the classes that define a section of a kickstart file. A | ||
| 24 | section is a chunk of the file starting with a %tag and ending with a %end. | ||
| 25 | Examples of sections include %packages, %pre, and %post. | ||
| 26 | |||
| 27 | You may use this module to define your own custom sections which will be | ||
| 28 | treated just the same as a predefined one by the kickstart parser. All that | ||
| 29 | is necessary is to create a new subclass of Section and call | ||
| 30 | parser.registerSection with an instance of your new class. | ||
| 31 | """ | ||
| 32 | from constants import * | ||
| 33 | from options import KSOptionParser | ||
| 34 | from version import * | ||
| 35 | |||
| 36 | class Section(object): | ||
| 37 | """The base class for defining kickstart sections. You are free to | ||
| 38 | subclass this as appropriate. | ||
| 39 | |||
| 40 | Class attributes: | ||
| 41 | |||
| 42 | allLines -- Does this section require the parser to call handleLine | ||
| 43 | for every line in the section, even blanks and comments? | ||
| 44 | sectionOpen -- The string that denotes the start of this section. You | ||
| 45 | must start your tag with a percent sign. | ||
| 46 | timesSeen -- This attribute is for informational purposes only. It is | ||
| 47 | incremented every time handleHeader is called to keep | ||
| 48 | track of the number of times a section of this type is | ||
| 49 | seen. | ||
| 50 | """ | ||
| 51 | allLines = False | ||
| 52 | sectionOpen = "" | ||
| 53 | timesSeen = 0 | ||
| 54 | |||
| 55 | def __init__(self, handler, **kwargs): | ||
| 56 | """Create a new Script instance. At the least, you must pass in an | ||
| 57 | instance of a baseHandler subclass. | ||
| 58 | |||
| 59 | Valid kwargs: | ||
| 60 | |||
| 61 | dataObj -- | ||
| 62 | """ | ||
| 63 | self.handler = handler | ||
| 64 | |||
| 65 | self.version = self.handler.version | ||
| 66 | |||
| 67 | self.dataObj = kwargs.get("dataObj", None) | ||
| 68 | |||
| 69 | def finalize(self): | ||
| 70 | """This method is called when the %end tag for a section is seen. It | ||
| 71 | is not required to be provided. | ||
| 72 | """ | ||
| 73 | pass | ||
| 74 | |||
| 75 | def handleLine(self, line): | ||
| 76 | """This method is called for every line of a section. Take whatever | ||
| 77 | action is appropriate. While this method is not required to be | ||
| 78 | provided, not providing it does not make a whole lot of sense. | ||
| 79 | |||
| 80 | Arguments: | ||
| 81 | |||
| 82 | line -- The complete line, with any trailing newline. | ||
| 83 | """ | ||
| 84 | pass | ||
| 85 | |||
| 86 | def handleHeader(self, lineno, args): | ||
| 87 | """This method is called when the opening tag for a section is seen. | ||
| 88 | Not all sections will need this method, though all provided with | ||
| 89 | kickstart include one. | ||
| 90 | |||
| 91 | Arguments: | ||
| 92 | |||
| 93 | args -- A list of all strings passed as arguments to the section | ||
| 94 | opening tag. | ||
| 95 | """ | ||
| 96 | self.timesSeen += 1 | ||
| 97 | |||
| 98 | class NullSection(Section): | ||
| 99 | """This defines a section that pykickstart will recognize but do nothing | ||
| 100 | with. If the parser runs across a %section that has no object registered, | ||
| 101 | it will raise an error. Sometimes, you may want to simply ignore those | ||
| 102 | sections instead. This class is useful for that purpose. | ||
| 103 | """ | ||
| 104 | def __init__(self, *args, **kwargs): | ||
| 105 | """Create a new NullSection instance. You must pass a sectionOpen | ||
| 106 | parameter (including a leading '%') for the section you wish to | ||
| 107 | ignore. | ||
| 108 | """ | ||
| 109 | Section.__init__(self, *args, **kwargs) | ||
| 110 | self.sectionOpen = kwargs.get("sectionOpen") | ||
| 111 | |||
| 112 | class ScriptSection(Section): | ||
| 113 | allLines = True | ||
| 114 | |||
| 115 | def __init__(self, *args, **kwargs): | ||
| 116 | Section.__init__(self, *args, **kwargs) | ||
| 117 | self._script = {} | ||
| 118 | self._resetScript() | ||
| 119 | |||
| 120 | def _getParser(self): | ||
| 121 | op = KSOptionParser(self.version) | ||
| 122 | op.add_option("--erroronfail", dest="errorOnFail", action="store_true", | ||
| 123 | default=False) | ||
| 124 | op.add_option("--interpreter", dest="interpreter", default="/bin/sh") | ||
| 125 | op.add_option("--log", "--logfile", dest="log") | ||
| 126 | return op | ||
| 127 | |||
| 128 | def _resetScript(self): | ||
| 129 | self._script = {"interp": "/bin/sh", "log": None, "errorOnFail": False, | ||
| 130 | "lineno": None, "chroot": False, "body": []} | ||
| 131 | |||
| 132 | def handleLine(self, line): | ||
| 133 | self._script["body"].append(line) | ||
| 134 | |||
| 135 | def finalize(self): | ||
| 136 | if " ".join(self._script["body"]).strip() == "": | ||
| 137 | return | ||
| 138 | |||
| 139 | kwargs = {"interp": self._script["interp"], | ||
| 140 | "inChroot": self._script["chroot"], | ||
| 141 | "lineno": self._script["lineno"], | ||
| 142 | "logfile": self._script["log"], | ||
| 143 | "errorOnFail": self._script["errorOnFail"], | ||
| 144 | "type": self._script["type"]} | ||
| 145 | |||
| 146 | s = self.dataObj (self._script["body"], **kwargs) | ||
| 147 | self._resetScript() | ||
| 148 | |||
| 149 | if self.handler: | ||
| 150 | self.handler.scripts.append(s) | ||
| 151 | |||
| 152 | def handleHeader(self, lineno, args): | ||
| 153 | """Process the arguments to a %pre/%post/%traceback header for later | ||
| 154 | setting on a Script instance once the end of the script is found. | ||
| 155 | This method may be overridden in a subclass if necessary. | ||
| 156 | """ | ||
| 157 | Section.handleHeader(self, lineno, args) | ||
| 158 | op = self._getParser() | ||
| 159 | |||
| 160 | (opts, extra) = op.parse_args(args=args[1:], lineno=lineno) | ||
| 161 | |||
| 162 | self._script["interp"] = opts.interpreter | ||
| 163 | self._script["lineno"] = lineno | ||
| 164 | self._script["log"] = opts.log | ||
| 165 | self._script["errorOnFail"] = opts.errorOnFail | ||
| 166 | if hasattr(opts, "nochroot"): | ||
| 167 | self._script["chroot"] = not opts.nochroot | ||
| 168 | |||
| 169 | class PreScriptSection(ScriptSection): | ||
| 170 | sectionOpen = "%pre" | ||
| 171 | |||
| 172 | def _resetScript(self): | ||
| 173 | ScriptSection._resetScript(self) | ||
| 174 | self._script["type"] = KS_SCRIPT_PRE | ||
| 175 | |||
| 176 | class PostScriptSection(ScriptSection): | ||
| 177 | sectionOpen = "%post" | ||
| 178 | |||
| 179 | def _getParser(self): | ||
| 180 | op = ScriptSection._getParser(self) | ||
| 181 | op.add_option("--nochroot", dest="nochroot", action="store_true", | ||
| 182 | default=False) | ||
| 183 | return op | ||
| 184 | |||
| 185 | def _resetScript(self): | ||
| 186 | ScriptSection._resetScript(self) | ||
| 187 | self._script["chroot"] = True | ||
| 188 | self._script["type"] = KS_SCRIPT_POST | ||
| 189 | |||
| 190 | class TracebackScriptSection(ScriptSection): | ||
| 191 | sectionOpen = "%traceback" | ||
| 192 | |||
| 193 | def _resetScript(self): | ||
| 194 | ScriptSection._resetScript(self) | ||
| 195 | self._script["type"] = KS_SCRIPT_TRACEBACK | ||
| 196 | |||
| 197 | class PackageSection(Section): | ||
| 198 | sectionOpen = "%packages" | ||
| 199 | |||
| 200 | def handleLine(self, line): | ||
| 201 | if not self.handler: | ||
| 202 | return | ||
| 203 | |||
| 204 | (h, s, t) = line.partition('#') | ||
| 205 | line = h.rstrip() | ||
| 206 | |||
| 207 | self.handler.packages.add([line]) | ||
| 208 | |||
| 209 | def handleHeader(self, lineno, args): | ||
| 210 | """Process the arguments to the %packages header and set attributes | ||
| 211 | on the Version's Packages instance appropriate. This method may be | ||
| 212 | overridden in a subclass if necessary. | ||
| 213 | """ | ||
| 214 | Section.handleHeader(self, lineno, args) | ||
| 215 | op = KSOptionParser(version=self.version) | ||
| 216 | op.add_option("--excludedocs", dest="excludedocs", action="store_true", | ||
| 217 | default=False) | ||
| 218 | op.add_option("--ignoremissing", dest="ignoremissing", | ||
| 219 | action="store_true", default=False) | ||
| 220 | op.add_option("--nobase", dest="nobase", action="store_true", | ||
| 221 | default=False) | ||
| 222 | op.add_option("--ignoredeps", dest="resolveDeps", action="store_false", | ||
| 223 | deprecated=FC4, removed=F9) | ||
| 224 | op.add_option("--resolvedeps", dest="resolveDeps", action="store_true", | ||
| 225 | deprecated=FC4, removed=F9) | ||
| 226 | op.add_option("--default", dest="defaultPackages", action="store_true", | ||
| 227 | default=False, introduced=F7) | ||
| 228 | op.add_option("--instLangs", dest="instLangs", type="string", | ||
| 229 | default="", introduced=F9) | ||
| 230 | |||
| 231 | (opts, extra) = op.parse_args(args=args[1:], lineno=lineno) | ||
| 232 | |||
| 233 | self.handler.packages.excludeDocs = opts.excludedocs | ||
| 234 | self.handler.packages.addBase = not opts.nobase | ||
| 235 | if opts.ignoremissing: | ||
| 236 | self.handler.packages.handleMissing = KS_MISSING_IGNORE | ||
| 237 | else: | ||
| 238 | self.handler.packages.handleMissing = KS_MISSING_PROMPT | ||
| 239 | |||
| 240 | if opts.defaultPackages: | ||
| 241 | self.handler.packages.default = True | ||
| 242 | |||
| 243 | if opts.instLangs: | ||
| 244 | self.handler.packages.instLangs = opts.instLangs | ||
diff --git a/scripts/lib/wic/3rdparty/pykickstart/version.py b/scripts/lib/wic/3rdparty/pykickstart/version.py new file mode 100644 index 0000000000..8a8e6aad22 --- /dev/null +++ b/scripts/lib/wic/3rdparty/pykickstart/version.py | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | # | ||
| 2 | # Chris Lumens <clumens@redhat.com> | ||
| 3 | # | ||
| 4 | # Copyright 2006, 2007, 2008, 2009, 2010 Red Hat, Inc. | ||
| 5 | # | ||
| 6 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 7 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 8 | # General Public License v.2. This program is distributed in the hope that it | ||
| 9 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 10 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 11 | # See the GNU General Public License for more details. | ||
| 12 | # | ||
| 13 | # You should have received a copy of the GNU General Public License along with | ||
| 14 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 15 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat | ||
| 16 | # trademarks that are incorporated in the source code or documentation are not | ||
| 17 | # subject to the GNU General Public License and may only be used or replicated | ||
| 18 | # with the express permission of Red Hat, Inc. | ||
| 19 | # | ||
| 20 | """ | ||
| 21 | Methods for working with kickstart versions. | ||
| 22 | |||
| 23 | This module defines several symbolic constants that specify kickstart syntax | ||
| 24 | versions. Each version corresponds roughly to one release of Red Hat Linux, | ||
| 25 | Red Hat Enterprise Linux, or Fedora Core as these are where most syntax | ||
| 26 | changes take place. | ||
| 27 | |||
| 28 | This module also exports several functions: | ||
| 29 | |||
| 30 | makeVersion - Given a version number, return an instance of the | ||
| 31 | matching handler class. | ||
| 32 | |||
| 33 | returnClassForVersion - Given a version number, return the matching | ||
| 34 | handler class. This does not return an | ||
| 35 | instance of that class, however. | ||
| 36 | |||
| 37 | stringToVersion - Convert a string representation of a version number | ||
| 38 | into the symbolic constant. | ||
| 39 | |||
| 40 | versionToString - Perform the reverse mapping. | ||
| 41 | |||
| 42 | versionFromFile - Read a kickstart file and determine the version of | ||
| 43 | syntax it uses. This requires the kickstart file to | ||
| 44 | have a version= comment in it. | ||
| 45 | """ | ||
| 46 | import imputil, re, sys | ||
| 47 | |||
| 48 | import gettext | ||
| 49 | _ = lambda x: gettext.ldgettext("pykickstart", x) | ||
| 50 | |||
| 51 | from pykickstart.errors import KickstartVersionError | ||
| 52 | |||
| 53 | # Symbolic names for internal version numbers. | ||
| 54 | RHEL3 = 900 | ||
| 55 | FC3 = 1000 | ||
| 56 | RHEL4 = 1100 | ||
| 57 | FC4 = 2000 | ||
| 58 | FC5 = 3000 | ||
| 59 | FC6 = 4000 | ||
| 60 | RHEL5 = 4100 | ||
| 61 | F7 = 5000 | ||
| 62 | F8 = 6000 | ||
| 63 | F9 = 7000 | ||
| 64 | F10 = 8000 | ||
| 65 | F11 = 9000 | ||
| 66 | F12 = 10000 | ||
| 67 | F13 = 11000 | ||
| 68 | RHEL6 = 11100 | ||
| 69 | F14 = 12000 | ||
| 70 | F15 = 13000 | ||
| 71 | F16 = 14000 | ||
| 72 | |||
| 73 | # This always points at the latest version and is the default. | ||
| 74 | DEVEL = F16 | ||
| 75 | |||
| 76 | # A one-to-one mapping from string representations to version numbers. | ||
| 77 | versionMap = { | ||
| 78 | "DEVEL": DEVEL, | ||
| 79 | "FC3": FC3, "FC4": FC4, "FC5": FC5, "FC6": FC6, "F7": F7, "F8": F8, | ||
| 80 | "F9": F9, "F10": F10, "F11": F11, "F12": F12, "F13": F13, | ||
| 81 | "F14": F14, "F15": F15, "F16": F16, | ||
| 82 | "RHEL3": RHEL3, "RHEL4": RHEL4, "RHEL5": RHEL5, "RHEL6": RHEL6 | ||
| 83 | } | ||
| 84 | |||
| 85 | def stringToVersion(s): | ||
| 86 | """Convert string into one of the provided version constants. Raises | ||
| 87 | KickstartVersionError if string does not match anything. | ||
| 88 | """ | ||
| 89 | # First try these short forms. | ||
| 90 | try: | ||
| 91 | return versionMap[s.upper()] | ||
| 92 | except KeyError: | ||
| 93 | pass | ||
| 94 | |||
| 95 | # Now try the Fedora versions. | ||
| 96 | m = re.match("^fedora.* (\d+)$", s, re.I) | ||
| 97 | |||
| 98 | if m and m.group(1): | ||
| 99 | if versionMap.has_key("FC" + m.group(1)): | ||
| 100 | return versionMap["FC" + m.group(1)] | ||
| 101 | elif versionMap.has_key("F" + m.group(1)): | ||
| 102 | return versionMap["F" + m.group(1)] | ||
| 103 | else: | ||
| 104 | raise KickstartVersionError(_("Unsupported version specified: %s") % s) | ||
| 105 | |||
| 106 | # Now try the RHEL versions. | ||
| 107 | m = re.match("^red hat enterprise linux.* (\d+)([\.\d]*)$", s, re.I) | ||
| 108 | |||
| 109 | if m and m.group(1): | ||
| 110 | if versionMap.has_key("RHEL" + m.group(1)): | ||
| 111 | return versionMap["RHEL" + m.group(1)] | ||
| 112 | else: | ||
| 113 | raise KickstartVersionError(_("Unsupported version specified: %s") % s) | ||
| 114 | |||
| 115 | # If nothing else worked, we're out of options. | ||
| 116 | raise KickstartVersionError(_("Unsupported version specified: %s") % s) | ||
| 117 | |||
| 118 | def versionToString(version, skipDevel=False): | ||
| 119 | """Convert version into a string representation of the version number. | ||
| 120 | This is the reverse operation of stringToVersion. Raises | ||
| 121 | KickstartVersionError if version does not match anything. | ||
| 122 | """ | ||
| 123 | if not skipDevel and version == versionMap["DEVEL"]: | ||
| 124 | return "DEVEL" | ||
| 125 | |||
| 126 | for (key, val) in versionMap.iteritems(): | ||
| 127 | if key == "DEVEL": | ||
| 128 | continue | ||
| 129 | elif val == version: | ||
| 130 | return key | ||
| 131 | |||
| 132 | raise KickstartVersionError(_("Unsupported version specified: %s") % version) | ||
| 133 | |||
| 134 | def returnClassForVersion(version=DEVEL): | ||
| 135 | """Return the class of the syntax handler for version. version can be | ||
| 136 | either a string or the matching constant. Raises KickstartValueError | ||
| 137 | if version does not match anything. | ||
| 138 | """ | ||
| 139 | try: | ||
| 140 | version = int(version) | ||
| 141 | module = "%s" % versionToString(version, skipDevel=True) | ||
| 142 | except ValueError: | ||
| 143 | module = "%s" % version | ||
| 144 | version = stringToVersion(version) | ||
| 145 | |||
| 146 | module = module.lower() | ||
| 147 | |||
| 148 | try: | ||
| 149 | import pykickstart.handlers | ||
| 150 | sys.path.extend(pykickstart.handlers.__path__) | ||
| 151 | found = imputil.imp.find_module(module) | ||
| 152 | loaded = imputil.imp.load_module(module, found[0], found[1], found[2]) | ||
| 153 | |||
| 154 | for (k, v) in loaded.__dict__.iteritems(): | ||
| 155 | if k.lower().endswith("%shandler" % module): | ||
| 156 | return v | ||
| 157 | except: | ||
| 158 | raise KickstartVersionError(_("Unsupported version specified: %s") % version) | ||
| 159 | |||
| 160 | def makeVersion(version=DEVEL): | ||
| 161 | """Return a new instance of the syntax handler for version. version can be | ||
| 162 | either a string or the matching constant. This function is useful for | ||
| 163 | standalone programs which just need to handle a specific version of | ||
| 164 | kickstart syntax (as provided by a command line argument, for example) | ||
| 165 | and need to instantiate the correct object. | ||
| 166 | """ | ||
| 167 | cl = returnClassForVersion(version) | ||
| 168 | return cl() | ||
diff --git a/scripts/lib/wic/__init__.py b/scripts/lib/wic/__init__.py new file mode 100644 index 0000000000..63c1d9c846 --- /dev/null +++ b/scripts/lib/wic/__init__.py | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | import os, sys | ||
| 2 | |||
| 3 | cur_path = os.path.dirname(__file__) or '.' | ||
| 4 | sys.path.insert(0, cur_path + '/3rdparty') | ||
diff --git a/scripts/lib/wic/__version__.py b/scripts/lib/wic/__version__.py new file mode 100644 index 0000000000..5452a46712 --- /dev/null +++ b/scripts/lib/wic/__version__.py | |||
| @@ -0,0 +1 @@ | |||
| VERSION = "2.00" | |||
diff --git a/scripts/lib/wic/conf.py b/scripts/lib/wic/conf.py new file mode 100644 index 0000000000..be34355ce4 --- /dev/null +++ b/scripts/lib/wic/conf.py | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2011 Intel, Inc. | ||
| 4 | # | ||
| 5 | # This program is free software; you can redistribute it and/or modify it | ||
| 6 | # under the terms of the GNU General Public License as published by the Free | ||
| 7 | # Software Foundation; version 2 of the License | ||
| 8 | # | ||
| 9 | # This program is distributed in the hope that it will be useful, but | ||
| 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 12 | # for more details. | ||
| 13 | # | ||
| 14 | # You should have received a copy of the GNU General Public License along | ||
| 15 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 16 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 17 | |||
| 18 | import os, sys, re | ||
| 19 | import ConfigParser | ||
| 20 | |||
| 21 | from wic import msger | ||
| 22 | from wic import kickstart | ||
| 23 | from wic.utils import misc, runner, errors | ||
| 24 | |||
| 25 | |||
| 26 | def get_siteconf(): | ||
| 27 | wic_path = os.path.dirname(__file__) | ||
| 28 | eos = wic_path.find('scripts') + len('scripts') | ||
| 29 | scripts_path = wic_path[:eos] | ||
| 30 | |||
| 31 | return scripts_path + "/lib/image/config/wic.conf" | ||
| 32 | |||
| 33 | class ConfigMgr(object): | ||
| 34 | DEFAULTS = {'common': { | ||
| 35 | "distro_name": "Default Distribution", | ||
| 36 | "plugin_dir": "/usr/lib/wic/plugins", # TODO use prefix also? | ||
| 37 | }, | ||
| 38 | 'create': { | ||
| 39 | "tmpdir": '/var/tmp/wic', | ||
| 40 | "outdir": './wic-output', | ||
| 41 | |||
| 42 | "release": None, | ||
| 43 | "logfile": None, | ||
| 44 | "name_prefix": None, | ||
| 45 | "name_suffix": None, | ||
| 46 | }, | ||
| 47 | } | ||
| 48 | |||
| 49 | # make the manager class as singleton | ||
| 50 | _instance = None | ||
| 51 | def __new__(cls, *args, **kwargs): | ||
| 52 | if not cls._instance: | ||
| 53 | cls._instance = super(ConfigMgr, cls).__new__(cls, *args, **kwargs) | ||
| 54 | |||
| 55 | return cls._instance | ||
| 56 | |||
| 57 | def __init__(self, ksconf=None, siteconf=None): | ||
| 58 | # reset config options | ||
| 59 | self.reset() | ||
| 60 | |||
| 61 | if not siteconf: | ||
| 62 | siteconf = get_siteconf() | ||
| 63 | |||
| 64 | # initial options from siteconf | ||
| 65 | self._siteconf = siteconf | ||
| 66 | |||
| 67 | if ksconf: | ||
| 68 | self._ksconf = ksconf | ||
| 69 | |||
| 70 | def reset(self): | ||
| 71 | self.__ksconf = None | ||
| 72 | self.__siteconf = None | ||
| 73 | |||
| 74 | # initialize the values with defaults | ||
| 75 | for sec, vals in self.DEFAULTS.iteritems(): | ||
| 76 | setattr(self, sec, vals) | ||
| 77 | |||
| 78 | def __set_ksconf(self, ksconf): | ||
| 79 | if not os.path.isfile(ksconf): | ||
| 80 | msger.error('Cannot find ks file: %s' % ksconf) | ||
| 81 | |||
| 82 | self.__ksconf = ksconf | ||
| 83 | self._parse_kickstart(ksconf) | ||
| 84 | def __get_ksconf(self): | ||
| 85 | return self.__ksconf | ||
| 86 | _ksconf = property(__get_ksconf, __set_ksconf) | ||
| 87 | |||
| 88 | def _parse_kickstart(self, ksconf=None): | ||
| 89 | if not ksconf: | ||
| 90 | return | ||
| 91 | |||
| 92 | ks = kickstart.read_kickstart(ksconf) | ||
| 93 | |||
| 94 | self.create['ks'] = ks | ||
| 95 | self.create['name'] = os.path.splitext(os.path.basename(ksconf))[0] | ||
| 96 | |||
| 97 | self.create['name'] = misc.build_name(ksconf, | ||
| 98 | self.create['release'], | ||
| 99 | self.create['name_prefix'], | ||
| 100 | self.create['name_suffix']) | ||
| 101 | |||
| 102 | configmgr = ConfigMgr() | ||
diff --git a/scripts/lib/wic/creator.py b/scripts/lib/wic/creator.py new file mode 100644 index 0000000000..2219377b38 --- /dev/null +++ b/scripts/lib/wic/creator.py | |||
| @@ -0,0 +1,187 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2011 Intel, Inc. | ||
| 4 | # | ||
| 5 | # This program is free software; you can redistribute it and/or modify it | ||
| 6 | # under the terms of the GNU General Public License as published by the Free | ||
| 7 | # Software Foundation; version 2 of the License | ||
| 8 | # | ||
| 9 | # This program is distributed in the hope that it will be useful, but | ||
| 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 12 | # for more details. | ||
| 13 | # | ||
| 14 | # You should have received a copy of the GNU General Public License along | ||
| 15 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 16 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 17 | |||
| 18 | import os, sys, re | ||
| 19 | from optparse import SUPPRESS_HELP | ||
| 20 | |||
| 21 | from wic import msger | ||
| 22 | from wic.utils import cmdln, errors | ||
| 23 | from wic.conf import configmgr | ||
| 24 | from wic.plugin import pluginmgr | ||
| 25 | |||
| 26 | |||
| 27 | class Creator(cmdln.Cmdln): | ||
| 28 | """${name}: create an image | ||
| 29 | |||
| 30 | Usage: | ||
| 31 | ${name} SUBCOMMAND <ksfile> [OPTS] | ||
| 32 | |||
| 33 | ${command_list} | ||
| 34 | ${option_list} | ||
| 35 | """ | ||
| 36 | |||
| 37 | name = 'wic create(cr)' | ||
| 38 | |||
| 39 | def __init__(self, *args, **kwargs): | ||
| 40 | cmdln.Cmdln.__init__(self, *args, **kwargs) | ||
| 41 | self._subcmds = [] | ||
| 42 | |||
| 43 | # get cmds from pluginmgr | ||
| 44 | # mix-in do_subcmd interface | ||
| 45 | for subcmd, klass in pluginmgr.get_plugins('imager').iteritems(): | ||
| 46 | if not hasattr(klass, 'do_create'): | ||
| 47 | msger.warning("Unsupported subcmd: %s" % subcmd) | ||
| 48 | continue | ||
| 49 | |||
| 50 | func = getattr(klass, 'do_create') | ||
| 51 | setattr(self.__class__, "do_"+subcmd, func) | ||
| 52 | self._subcmds.append(subcmd) | ||
| 53 | |||
| 54 | def get_optparser(self): | ||
| 55 | optparser = cmdln.CmdlnOptionParser(self) | ||
| 56 | optparser.add_option('-d', '--debug', action='store_true', | ||
| 57 | dest='debug', | ||
| 58 | help=SUPPRESS_HELP) | ||
| 59 | optparser.add_option('-v', '--verbose', action='store_true', | ||
| 60 | dest='verbose', | ||
| 61 | help=SUPPRESS_HELP) | ||
| 62 | optparser.add_option('', '--logfile', type='string', dest='logfile', | ||
| 63 | default=None, | ||
| 64 | help='Path of logfile') | ||
| 65 | optparser.add_option('-c', '--config', type='string', dest='config', | ||
| 66 | default=None, | ||
| 67 | help='Specify config file for wic') | ||
| 68 | optparser.add_option('-o', '--outdir', type='string', action='store', | ||
| 69 | dest='outdir', default=None, | ||
| 70 | help='Output directory') | ||
| 71 | optparser.add_option('', '--tmpfs', action='store_true', dest='enabletmpfs', | ||
| 72 | help='Setup tmpdir as tmpfs to accelerate, experimental' | ||
| 73 | ' feature, use it if you have more than 4G memory') | ||
| 74 | return optparser | ||
| 75 | |||
| 76 | def preoptparse(self, argv): | ||
| 77 | optparser = self.get_optparser() | ||
| 78 | |||
| 79 | largs = [] | ||
| 80 | rargs = [] | ||
| 81 | while argv: | ||
| 82 | arg = argv.pop(0) | ||
| 83 | |||
| 84 | if arg in ('-h', '--help'): | ||
| 85 | rargs.append(arg) | ||
| 86 | |||
| 87 | elif optparser.has_option(arg): | ||
| 88 | largs.append(arg) | ||
| 89 | |||
| 90 | if optparser.get_option(arg).takes_value(): | ||
| 91 | try: | ||
| 92 | largs.append(argv.pop(0)) | ||
| 93 | except IndexError: | ||
| 94 | raise errors.Usage("option %s requires arguments" % arg) | ||
| 95 | |||
| 96 | else: | ||
| 97 | if arg.startswith("--"): | ||
| 98 | if "=" in arg: | ||
| 99 | opt = arg.split("=")[0] | ||
| 100 | else: | ||
| 101 | opt = None | ||
| 102 | elif arg.startswith("-") and len(arg) > 2: | ||
| 103 | opt = arg[0:2] | ||
| 104 | else: | ||
| 105 | opt = None | ||
| 106 | |||
| 107 | if opt and optparser.has_option(opt): | ||
| 108 | largs.append(arg) | ||
| 109 | else: | ||
| 110 | rargs.append(arg) | ||
| 111 | |||
| 112 | return largs + rargs | ||
| 113 | |||
| 114 | def postoptparse(self): | ||
| 115 | abspath = lambda pth: os.path.abspath(os.path.expanduser(pth)) | ||
| 116 | |||
| 117 | if self.options.verbose: | ||
| 118 | msger.set_loglevel('verbose') | ||
| 119 | if self.options.debug: | ||
| 120 | msger.set_loglevel('debug') | ||
| 121 | |||
| 122 | if self.options.logfile: | ||
| 123 | logfile_abs_path = abspath(self.options.logfile) | ||
| 124 | if os.path.isdir(logfile_abs_path): | ||
| 125 | raise errors.Usage("logfile's path %s should be file" | ||
| 126 | % self.options.logfile) | ||
| 127 | if not os.path.exists(os.path.dirname(logfile_abs_path)): | ||
| 128 | os.makedirs(os.path.dirname(logfile_abs_path)) | ||
| 129 | msger.set_interactive(False) | ||
| 130 | msger.set_logfile(logfile_abs_path) | ||
| 131 | configmgr.create['logfile'] = self.options.logfile | ||
| 132 | |||
| 133 | if self.options.config: | ||
| 134 | configmgr.reset() | ||
| 135 | configmgr._siteconf = self.options.config | ||
| 136 | |||
| 137 | if self.options.outdir is not None: | ||
| 138 | configmgr.create['outdir'] = abspath(self.options.outdir) | ||
| 139 | |||
| 140 | cdir = 'outdir' | ||
| 141 | if os.path.exists(configmgr.create[cdir]) \ | ||
| 142 | and not os.path.isdir(configmgr.create[cdir]): | ||
| 143 | msger.error('Invalid directory specified: %s' \ | ||
| 144 | % configmgr.create[cdir]) | ||
| 145 | |||
| 146 | if self.options.enabletmpfs: | ||
| 147 | configmgr.create['enabletmpfs'] = self.options.enabletmpfs | ||
| 148 | |||
| 149 | def main(self, argv=None): | ||
| 150 | if argv is None: | ||
| 151 | argv = sys.argv | ||
| 152 | else: | ||
| 153 | argv = argv[:] # don't modify caller's list | ||
| 154 | |||
| 155 | self.optparser = self.get_optparser() | ||
| 156 | if self.optparser: | ||
| 157 | try: | ||
| 158 | argv = self.preoptparse(argv) | ||
| 159 | self.options, args = self.optparser.parse_args(argv) | ||
| 160 | |||
| 161 | except cmdln.CmdlnUserError, ex: | ||
| 162 | msg = "%s: %s\nTry '%s help' for info.\n"\ | ||
| 163 | % (self.name, ex, self.name) | ||
| 164 | msger.error(msg) | ||
| 165 | |||
| 166 | except cmdln.StopOptionProcessing, ex: | ||
| 167 | return 0 | ||
| 168 | else: | ||
| 169 | # optparser=None means no process for opts | ||
| 170 | self.options, args = None, argv[1:] | ||
| 171 | |||
| 172 | if not args: | ||
| 173 | return self.emptyline() | ||
| 174 | |||
| 175 | self.postoptparse() | ||
| 176 | |||
| 177 | return self.cmd(args) | ||
| 178 | |||
| 179 | def precmd(self, argv): # check help before cmd | ||
| 180 | |||
| 181 | if '-h' in argv or '?' in argv or '--help' in argv or 'help' in argv: | ||
| 182 | return argv | ||
| 183 | |||
| 184 | if len(argv) == 1: | ||
| 185 | return ['help', argv[0]] | ||
| 186 | |||
| 187 | return argv | ||
diff --git a/scripts/lib/wic/imager/__init__.py b/scripts/lib/wic/imager/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/scripts/lib/wic/imager/__init__.py | |||
diff --git a/scripts/lib/wic/imager/baseimager.py b/scripts/lib/wic/imager/baseimager.py new file mode 100644 index 0000000000..e8305272a2 --- /dev/null +++ b/scripts/lib/wic/imager/baseimager.py | |||
| @@ -0,0 +1,193 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2007 Red Hat Inc. | ||
| 4 | # Copyright (c) 2009, 2010, 2011 Intel, Inc. | ||
| 5 | # | ||
| 6 | # This program is free software; you can redistribute it and/or modify it | ||
| 7 | # under the terms of the GNU General Public License as published by the Free | ||
| 8 | # Software Foundation; version 2 of the License | ||
| 9 | # | ||
| 10 | # This program is distributed in the hope that it will be useful, but | ||
| 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 12 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 13 | # for more details. | ||
| 14 | # | ||
| 15 | # You should have received a copy of the GNU General Public License along | ||
| 16 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 17 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 18 | |||
| 19 | from __future__ import with_statement | ||
| 20 | import os, sys | ||
| 21 | import tempfile | ||
| 22 | import shutil | ||
| 23 | |||
| 24 | from wic import kickstart | ||
| 25 | from wic import msger | ||
| 26 | from wic.utils.errors import CreatorError | ||
| 27 | from wic.utils import misc, runner, fs_related as fs | ||
| 28 | |||
| 29 | class BaseImageCreator(object): | ||
| 30 | """Base class for image creation. | ||
| 31 | |||
| 32 | BaseImageCreator is the simplest creator class available; it will | ||
| 33 | create a system image according to the supplied kickstart file. | ||
| 34 | |||
| 35 | e.g. | ||
| 36 | |||
| 37 | import wic.imgcreate as imgcreate | ||
| 38 | ks = imgcreate.read_kickstart("foo.ks") | ||
| 39 | imgcreate.ImageCreator(ks, "foo").create() | ||
| 40 | """ | ||
| 41 | |||
| 42 | def __del__(self): | ||
| 43 | self.cleanup() | ||
| 44 | |||
| 45 | def __init__(self, createopts = None): | ||
| 46 | """Initialize an ImageCreator instance. | ||
| 47 | |||
| 48 | ks -- a pykickstart.KickstartParser instance; this instance will be | ||
| 49 | used to drive the install by e.g. providing the list of packages | ||
| 50 | to be installed, the system configuration and %post scripts | ||
| 51 | |||
| 52 | name -- a name for the image; used for e.g. image filenames or | ||
| 53 | filesystem labels | ||
| 54 | """ | ||
| 55 | |||
| 56 | self.__builddir = None | ||
| 57 | |||
| 58 | self.ks = None | ||
| 59 | self.name = "target" | ||
| 60 | self.tmpdir = "/var/tmp/wic" | ||
| 61 | self.workdir = "/var/tmp/wic/build" | ||
| 62 | |||
| 63 | # setup tmpfs tmpdir when enabletmpfs is True | ||
| 64 | self.enabletmpfs = False | ||
| 65 | |||
| 66 | if createopts: | ||
| 67 | # Mapping table for variables that have different names. | ||
| 68 | optmap = {"outdir" : "destdir", | ||
| 69 | } | ||
| 70 | |||
| 71 | # update setting from createopts | ||
| 72 | for key in createopts.keys(): | ||
| 73 | if key in optmap: | ||
| 74 | option = optmap[key] | ||
| 75 | else: | ||
| 76 | option = key | ||
| 77 | setattr(self, option, createopts[key]) | ||
| 78 | |||
| 79 | self.destdir = os.path.abspath(os.path.expanduser(self.destdir)) | ||
| 80 | |||
| 81 | self._dep_checks = ["ls", "bash", "cp", "echo"] | ||
| 82 | |||
| 83 | # Output image file names | ||
| 84 | self.outimage = [] | ||
| 85 | |||
| 86 | # No ks provided when called by convertor, so skip the dependency check | ||
| 87 | if self.ks: | ||
| 88 | # If we have btrfs partition we need to check necessary tools | ||
| 89 | for part in self.ks.handler.partition.partitions: | ||
| 90 | if part.fstype and part.fstype == "btrfs": | ||
| 91 | self._dep_checks.append("mkfs.btrfs") | ||
| 92 | break | ||
| 93 | |||
| 94 | # make sure the specified tmpdir and cachedir exist | ||
| 95 | if not os.path.exists(self.tmpdir): | ||
| 96 | os.makedirs(self.tmpdir) | ||
| 97 | |||
| 98 | |||
| 99 | # | ||
| 100 | # Hooks for subclasses | ||
| 101 | # | ||
| 102 | def _create(self): | ||
| 103 | """Create partitions for the disk image(s) | ||
| 104 | |||
| 105 | This is the hook where subclasses may create the partitions | ||
| 106 | that will be assembled into disk image(s). | ||
| 107 | |||
| 108 | There is no default implementation. | ||
| 109 | """ | ||
| 110 | pass | ||
| 111 | |||
| 112 | def _cleanup(self): | ||
| 113 | """Undo anything performed in _create(). | ||
| 114 | |||
| 115 | This is the hook where subclasses must undo anything which was | ||
| 116 | done in _create(). | ||
| 117 | |||
| 118 | There is no default implementation. | ||
| 119 | |||
| 120 | """ | ||
| 121 | pass | ||
| 122 | |||
| 123 | # | ||
| 124 | # Actual implementation | ||
| 125 | # | ||
| 126 | def __ensure_builddir(self): | ||
| 127 | if not self.__builddir is None: | ||
| 128 | return | ||
| 129 | |||
| 130 | try: | ||
| 131 | self.workdir = os.path.join(self.tmpdir, "build") | ||
| 132 | if not os.path.exists(self.workdir): | ||
| 133 | os.makedirs(self.workdir) | ||
| 134 | self.__builddir = tempfile.mkdtemp(dir = self.workdir, | ||
| 135 | prefix = "imgcreate-") | ||
| 136 | except OSError, (err, msg): | ||
| 137 | raise CreatorError("Failed create build directory in %s: %s" % | ||
| 138 | (self.tmpdir, msg)) | ||
| 139 | |||
| 140 | def __setup_tmpdir(self): | ||
| 141 | if not self.enabletmpfs: | ||
| 142 | return | ||
| 143 | |||
| 144 | runner.show('mount -t tmpfs -o size=4G tmpfs %s' % self.workdir) | ||
| 145 | |||
| 146 | def __clean_tmpdir(self): | ||
| 147 | if not self.enabletmpfs: | ||
| 148 | return | ||
| 149 | |||
| 150 | runner.show('umount -l %s' % self.workdir) | ||
| 151 | |||
| 152 | def create(self): | ||
| 153 | """Create partitions for the disk image(s) | ||
| 154 | |||
| 155 | Create the partitions that will be assembled into disk | ||
| 156 | image(s). | ||
| 157 | """ | ||
| 158 | self.__setup_tmpdir() | ||
| 159 | self.__ensure_builddir() | ||
| 160 | |||
| 161 | self._create() | ||
| 162 | |||
| 163 | def cleanup(self): | ||
| 164 | """Undo anything performed in create(). | ||
| 165 | |||
| 166 | Note, make sure to call this method once finished with the creator | ||
| 167 | instance in order to ensure no stale files are left on the host e.g.: | ||
| 168 | |||
| 169 | creator = ImageCreator(ks, name) | ||
| 170 | try: | ||
| 171 | creator.create() | ||
| 172 | finally: | ||
| 173 | creator.cleanup() | ||
| 174 | |||
| 175 | """ | ||
| 176 | if not self.__builddir: | ||
| 177 | return | ||
| 178 | |||
| 179 | self._cleanup() | ||
| 180 | |||
| 181 | shutil.rmtree(self.__builddir, ignore_errors = True) | ||
| 182 | self.__builddir = None | ||
| 183 | |||
| 184 | self.__clean_tmpdir() | ||
| 185 | |||
| 186 | |||
| 187 | def print_outimage_info(self): | ||
| 188 | msg = "The new image can be found here:\n" | ||
| 189 | self.outimage.sort() | ||
| 190 | for file in self.outimage: | ||
| 191 | msg += ' %s\n' % os.path.abspath(file) | ||
| 192 | |||
| 193 | msger.info(msg) | ||
diff --git a/scripts/lib/wic/imager/direct.py b/scripts/lib/wic/imager/direct.py new file mode 100644 index 0000000000..d0ae504daf --- /dev/null +++ b/scripts/lib/wic/imager/direct.py | |||
| @@ -0,0 +1,363 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2013, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This implements the 'direct' image creator class for 'wic' | ||
| 22 | # | ||
| 23 | # AUTHORS | ||
| 24 | # Tom Zanussi <tom.zanussi (at] linux.intel.com> | ||
| 25 | # | ||
| 26 | |||
| 27 | import os | ||
| 28 | import stat | ||
| 29 | import shutil | ||
| 30 | |||
| 31 | from wic import kickstart, msger | ||
| 32 | from wic.utils import fs_related, runner, misc | ||
| 33 | from wic.utils.partitionedfs import Image | ||
| 34 | from wic.utils.errors import CreatorError, ImageError | ||
| 35 | from wic.imager.baseimager import BaseImageCreator | ||
| 36 | from wic.utils.oe.misc import * | ||
| 37 | from wic.plugin import pluginmgr | ||
| 38 | |||
| 39 | disk_methods = { | ||
| 40 | "do_install_disk":None, | ||
| 41 | } | ||
| 42 | |||
| 43 | class DirectImageCreator(BaseImageCreator): | ||
| 44 | """ | ||
| 45 | Installs a system into a file containing a partitioned disk image. | ||
| 46 | |||
| 47 | DirectImageCreator is an advanced ImageCreator subclass; an image | ||
| 48 | file is formatted with a partition table, each partition created | ||
| 49 | from a rootfs or other OpenEmbedded build artifact and dd'ed into | ||
| 50 | the virtual disk. The disk image can subsequently be dd'ed onto | ||
| 51 | media and used on actual hardware. | ||
| 52 | """ | ||
| 53 | |||
| 54 | def __init__(self, oe_builddir, image_output_dir, rootfs_dir, bootimg_dir, | ||
| 55 | kernel_dir, native_sysroot, creatoropts=None): | ||
| 56 | """ | ||
| 57 | Initialize a DirectImageCreator instance. | ||
| 58 | |||
| 59 | This method takes the same arguments as ImageCreator.__init__() | ||
| 60 | """ | ||
| 61 | BaseImageCreator.__init__(self, creatoropts) | ||
| 62 | |||
| 63 | self.__image = None | ||
| 64 | self.__disks = {} | ||
| 65 | self.__disk_format = "direct" | ||
| 66 | self._disk_names = [] | ||
| 67 | self._ptable_format = self.ks.handler.bootloader.ptable | ||
| 68 | |||
| 69 | self.oe_builddir = oe_builddir | ||
| 70 | if image_output_dir: | ||
| 71 | self.tmpdir = image_output_dir | ||
| 72 | self.rootfs_dir = rootfs_dir | ||
| 73 | self.bootimg_dir = bootimg_dir | ||
| 74 | self.kernel_dir = kernel_dir | ||
| 75 | self.native_sysroot = native_sysroot | ||
| 76 | |||
| 77 | def __write_fstab(self, image_rootfs): | ||
| 78 | """overriden to generate fstab (temporarily) in rootfs. This is called | ||
| 79 | from _create, make sure it doesn't get called from | ||
| 80 | BaseImage.create() | ||
| 81 | """ | ||
| 82 | if image_rootfs is None: | ||
| 83 | return None | ||
| 84 | |||
| 85 | fstab = image_rootfs + "/etc/fstab" | ||
| 86 | if not os.path.isfile(fstab): | ||
| 87 | return None | ||
| 88 | |||
| 89 | parts = self._get_parts() | ||
| 90 | |||
| 91 | self._save_fstab(fstab) | ||
| 92 | fstab_lines = self._get_fstab(fstab, parts) | ||
| 93 | self._update_fstab(fstab_lines, parts) | ||
| 94 | self._write_fstab(fstab, fstab_lines) | ||
| 95 | |||
| 96 | return fstab | ||
| 97 | |||
| 98 | def _update_fstab(self, fstab_lines, parts): | ||
| 99 | """Assume partition order same as in wks""" | ||
| 100 | for num, p in enumerate(parts, 1): | ||
| 101 | if not p.mountpoint or p.mountpoint == "/" or p.mountpoint == "/boot": | ||
| 102 | continue | ||
| 103 | if self._ptable_format == 'msdos' and num > 3: | ||
| 104 | device_name = "/dev/" + p.disk + str(num + 1) | ||
| 105 | else: | ||
| 106 | device_name = "/dev/" + p.disk + str(num) | ||
| 107 | |||
| 108 | opts = "defaults" | ||
| 109 | if p.fsopts: | ||
| 110 | opts = p.fsopts | ||
| 111 | |||
| 112 | fstab_entry = device_name + "\t" + \ | ||
| 113 | p.mountpoint + "\t" + \ | ||
| 114 | p.fstype + "\t" + \ | ||
| 115 | opts + "\t0\t0\n" | ||
| 116 | fstab_lines.append(fstab_entry) | ||
| 117 | |||
| 118 | def _write_fstab(self, fstab, fstab_lines): | ||
| 119 | fstab = open(fstab, "w") | ||
| 120 | for line in fstab_lines: | ||
| 121 | fstab.write(line) | ||
| 122 | fstab.close() | ||
| 123 | |||
| 124 | def _save_fstab(self, fstab): | ||
| 125 | """Save the current fstab in rootfs""" | ||
| 126 | shutil.copyfile(fstab, fstab + ".orig") | ||
| 127 | |||
| 128 | def _restore_fstab(self, fstab): | ||
| 129 | """Restore the saved fstab in rootfs""" | ||
| 130 | if fstab is None: | ||
| 131 | return | ||
| 132 | shutil.move(fstab + ".orig", fstab) | ||
| 133 | |||
| 134 | def _get_fstab(self, fstab, parts): | ||
| 135 | """Return the desired contents of /etc/fstab.""" | ||
| 136 | f = open(fstab, "r") | ||
| 137 | fstab_contents = f.readlines() | ||
| 138 | f.close() | ||
| 139 | |||
| 140 | return fstab_contents | ||
| 141 | |||
| 142 | def set_bootimg_dir(self, bootimg_dir): | ||
| 143 | """ | ||
| 144 | Accessor for bootimg_dir, the actual location used for the source | ||
| 145 | of the bootimg. Should be set by source plugins (only if they | ||
| 146 | change the default bootimg source) so the correct info gets | ||
| 147 | displayed for print_outimage_info(). | ||
| 148 | """ | ||
| 149 | self.bootimg_dir = bootimg_dir | ||
| 150 | |||
| 151 | def _get_parts(self): | ||
| 152 | if not self.ks: | ||
| 153 | raise CreatorError("Failed to get partition info, " | ||
| 154 | "please check your kickstart setting.") | ||
| 155 | |||
| 156 | # Set a default partition if no partition is given out | ||
| 157 | if not self.ks.handler.partition.partitions: | ||
| 158 | partstr = "part / --size 1900 --ondisk sda --fstype=ext3" | ||
| 159 | args = partstr.split() | ||
| 160 | pd = self.ks.handler.partition.parse(args[1:]) | ||
| 161 | if pd not in self.ks.handler.partition.partitions: | ||
| 162 | self.ks.handler.partition.partitions.append(pd) | ||
| 163 | |||
| 164 | # partitions list from kickstart file | ||
| 165 | return kickstart.get_partitions(self.ks) | ||
| 166 | |||
| 167 | def get_disk_names(self): | ||
| 168 | """ Returns a list of physical target disk names (e.g., 'sdb') which | ||
| 169 | will be created. """ | ||
| 170 | |||
| 171 | if self._disk_names: | ||
| 172 | return self._disk_names | ||
| 173 | |||
| 174 | #get partition info from ks handler | ||
| 175 | parts = self._get_parts() | ||
| 176 | |||
| 177 | for i in range(len(parts)): | ||
| 178 | if parts[i].disk: | ||
| 179 | disk_name = parts[i].disk | ||
| 180 | else: | ||
| 181 | raise CreatorError("Failed to create disks, no --ondisk " | ||
| 182 | "specified in partition line of ks file") | ||
| 183 | |||
| 184 | if parts[i].mountpoint and not parts[i].fstype: | ||
| 185 | raise CreatorError("Failed to create disks, no --fstype " | ||
| 186 | "specified for partition with mountpoint " | ||
| 187 | "'%s' in the ks file") | ||
| 188 | |||
| 189 | self._disk_names.append(disk_name) | ||
| 190 | |||
| 191 | return self._disk_names | ||
| 192 | |||
| 193 | def _full_name(self, name, extention): | ||
| 194 | """ Construct full file name for a file we generate. """ | ||
| 195 | return "%s-%s.%s" % (self.name, name, extention) | ||
| 196 | |||
| 197 | def _full_path(self, path, name, extention): | ||
| 198 | """ Construct full file path to a file we generate. """ | ||
| 199 | return os.path.join(path, self._full_name(name, extention)) | ||
| 200 | |||
| 201 | def get_default_source_plugin(self): | ||
| 202 | """ | ||
| 203 | The default source plugin i.e. the plugin that's consulted for | ||
| 204 | overall image generation tasks outside of any particular | ||
| 205 | partition. For convenience, we just hang it off the | ||
| 206 | bootloader handler since it's the one non-partition object in | ||
| 207 | any setup. By default the default plugin is set to the same | ||
| 208 | plugin as the /boot partition; since we hang it off the | ||
| 209 | bootloader object, the default can be explicitly set using the | ||
| 210 | --source bootloader param. | ||
| 211 | """ | ||
| 212 | return self.ks.handler.bootloader.source | ||
| 213 | |||
| 214 | # | ||
| 215 | # Actual implemention | ||
| 216 | # | ||
| 217 | def _create(self): | ||
| 218 | """ | ||
| 219 | For 'wic', we already have our build artifacts - we just create | ||
| 220 | filesystems from the artifacts directly and combine them into | ||
| 221 | a partitioned image. | ||
| 222 | """ | ||
| 223 | parts = self._get_parts() | ||
| 224 | |||
| 225 | self.__image = Image() | ||
| 226 | |||
| 227 | for p in parts: | ||
| 228 | # as a convenience, set source to the boot partition source | ||
| 229 | # instead of forcing it to be set via bootloader --source | ||
| 230 | if not self.ks.handler.bootloader.source and p.mountpoint == "/boot": | ||
| 231 | self.ks.handler.bootloader.source = p.source | ||
| 232 | |||
| 233 | for p in parts: | ||
| 234 | # need to create the filesystems in order to get their | ||
| 235 | # sizes before we can add them and do the layout. | ||
| 236 | # Image.create() actually calls __format_disks() to create | ||
| 237 | # the disk images and carve out the partitions, then | ||
| 238 | # self.assemble() calls Image.assemble() which calls | ||
| 239 | # __write_partitition() for each partition to dd the fs | ||
| 240 | # into the partitions. | ||
| 241 | |||
| 242 | p.install_pkgs(self, self.workdir, self.oe_builddir, self.rootfs_dir, | ||
| 243 | self.bootimg_dir, self.kernel_dir, self.native_sysroot) | ||
| 244 | |||
| 245 | fstab = self.__write_fstab(self.rootfs_dir.get("ROOTFS_DIR")) | ||
| 246 | |||
| 247 | p.prepare(self, self.workdir, self.oe_builddir, self.rootfs_dir, | ||
| 248 | self.bootimg_dir, self.kernel_dir, self.native_sysroot) | ||
| 249 | |||
| 250 | self._restore_fstab(fstab) | ||
| 251 | |||
| 252 | self.__image.add_partition(int(p.size), | ||
| 253 | p.disk, | ||
| 254 | p.mountpoint, | ||
| 255 | p.source_file, | ||
| 256 | p.fstype, | ||
| 257 | p.label, | ||
| 258 | fsopts = p.fsopts, | ||
| 259 | boot = p.active, | ||
| 260 | align = p.align, | ||
| 261 | part_type = p.part_type) | ||
| 262 | |||
| 263 | self.__image.layout_partitions(self._ptable_format) | ||
| 264 | |||
| 265 | self.__imgdir = self.workdir | ||
| 266 | for disk_name, disk in self.__image.disks.items(): | ||
| 267 | full_path = self._full_path(self.__imgdir, disk_name, "direct") | ||
| 268 | msger.debug("Adding disk %s as %s with size %s bytes" \ | ||
| 269 | % (disk_name, full_path, disk['min_size'])) | ||
| 270 | disk_obj = fs_related.DiskImage(full_path, disk['min_size']) | ||
| 271 | self.__disks[disk_name] = disk_obj | ||
| 272 | self.__image.add_disk(disk_name, disk_obj) | ||
| 273 | |||
| 274 | self.__image.create() | ||
| 275 | |||
| 276 | def assemble(self): | ||
| 277 | """ | ||
| 278 | Assemble partitions into disk image(s) | ||
| 279 | """ | ||
| 280 | for disk_name, disk in self.__image.disks.items(): | ||
| 281 | full_path = self._full_path(self.__imgdir, disk_name, "direct") | ||
| 282 | msger.debug("Assembling disk %s as %s with size %s bytes" \ | ||
| 283 | % (disk_name, full_path, disk['min_size'])) | ||
| 284 | self.__image.assemble(full_path) | ||
| 285 | |||
| 286 | def finalize(self): | ||
| 287 | """ | ||
| 288 | Finalize the disk image. | ||
| 289 | |||
| 290 | For example, prepare the image to be bootable by e.g. | ||
| 291 | creating and installing a bootloader configuration. | ||
| 292 | |||
| 293 | """ | ||
| 294 | source_plugin = self.get_default_source_plugin() | ||
| 295 | if source_plugin: | ||
| 296 | self._source_methods = pluginmgr.get_source_plugin_methods(source_plugin, disk_methods) | ||
| 297 | for disk_name, disk in self.__image.disks.items(): | ||
| 298 | self._source_methods["do_install_disk"](disk, disk_name, self, | ||
| 299 | self.workdir, | ||
| 300 | self.oe_builddir, | ||
| 301 | self.bootimg_dir, | ||
| 302 | self.kernel_dir, | ||
| 303 | self.native_sysroot) | ||
| 304 | |||
| 305 | def print_outimage_info(self): | ||
| 306 | """ | ||
| 307 | Print the image(s) and artifacts used, for the user. | ||
| 308 | """ | ||
| 309 | msg = "The new image(s) can be found here:\n" | ||
| 310 | |||
| 311 | parts = self._get_parts() | ||
| 312 | |||
| 313 | for disk_name, disk in self.__image.disks.items(): | ||
| 314 | full_path = self._full_path(self.__imgdir, disk_name, "direct") | ||
| 315 | msg += ' %s\n\n' % full_path | ||
| 316 | |||
| 317 | msg += 'The following build artifacts were used to create the image(s):\n' | ||
| 318 | for p in parts: | ||
| 319 | if p.get_rootfs() is None: | ||
| 320 | continue | ||
| 321 | if p.mountpoint == '/': | ||
| 322 | str = ':' | ||
| 323 | else: | ||
| 324 | str = '["%s"]:' % p.label | ||
| 325 | msg += ' ROOTFS_DIR%s%s\n' % (str.ljust(20), p.get_rootfs()) | ||
| 326 | |||
| 327 | msg += ' BOOTIMG_DIR: %s\n' % self.bootimg_dir | ||
| 328 | msg += ' KERNEL_DIR: %s\n' % self.kernel_dir | ||
| 329 | msg += ' NATIVE_SYSROOT: %s\n' % self.native_sysroot | ||
| 330 | |||
| 331 | msger.info(msg) | ||
| 332 | |||
| 333 | def _get_boot_config(self): | ||
| 334 | """ | ||
| 335 | Return the rootdev/root_part_uuid (if specified by | ||
| 336 | --part-type) | ||
| 337 | |||
| 338 | Assume partition order same as in wks | ||
| 339 | """ | ||
| 340 | rootdev = None | ||
| 341 | root_part_uuid = None | ||
| 342 | parts = self._get_parts() | ||
| 343 | for num, p in enumerate(parts, 1): | ||
| 344 | if p.mountpoint == "/": | ||
| 345 | part = '' | ||
| 346 | if p.disk.startswith('mmcblk'): | ||
| 347 | part = 'p' | ||
| 348 | |||
| 349 | if self._ptable_format == 'msdos' and num > 3: | ||
| 350 | rootdev = "/dev/%s%s%-d" % (p.disk, part, num + 1) | ||
| 351 | else: | ||
| 352 | rootdev = "/dev/%s%s%-d" % (p.disk, part, num) | ||
| 353 | root_part_uuid = p.part_type | ||
| 354 | |||
| 355 | return (rootdev, root_part_uuid) | ||
| 356 | |||
| 357 | def _cleanup(self): | ||
| 358 | if not self.__image is None: | ||
| 359 | try: | ||
| 360 | self.__image.cleanup() | ||
| 361 | except ImageError, err: | ||
| 362 | msger.warning("%s" % err) | ||
| 363 | |||
diff --git a/scripts/lib/wic/kickstart/__init__.py b/scripts/lib/wic/kickstart/__init__.py new file mode 100644 index 0000000000..600098293a --- /dev/null +++ b/scripts/lib/wic/kickstart/__init__.py | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2007 Red Hat, Inc. | ||
| 4 | # Copyright (c) 2009, 2010, 2011 Intel, Inc. | ||
| 5 | # | ||
| 6 | # This program is free software; you can redistribute it and/or modify it | ||
| 7 | # under the terms of the GNU General Public License as published by the Free | ||
| 8 | # Software Foundation; version 2 of the License | ||
| 9 | # | ||
| 10 | # This program is distributed in the hope that it will be useful, but | ||
| 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 12 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 13 | # for more details. | ||
| 14 | # | ||
| 15 | # You should have received a copy of the GNU General Public License along | ||
| 16 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 17 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 18 | |||
| 19 | import os, sys, re | ||
| 20 | import shutil | ||
| 21 | import subprocess | ||
| 22 | import string | ||
| 23 | |||
| 24 | import pykickstart.sections as kssections | ||
| 25 | import pykickstart.commands as kscommands | ||
| 26 | import pykickstart.constants as ksconstants | ||
| 27 | import pykickstart.errors as kserrors | ||
| 28 | import pykickstart.parser as ksparser | ||
| 29 | import pykickstart.version as ksversion | ||
| 30 | from pykickstart.handlers.control import commandMap | ||
| 31 | from pykickstart.handlers.control import dataMap | ||
| 32 | |||
| 33 | from wic import msger | ||
| 34 | from wic.utils import errors, misc, runner, fs_related as fs | ||
| 35 | from custom_commands import wicboot, partition | ||
| 36 | |||
| 37 | def read_kickstart(path): | ||
| 38 | """Parse a kickstart file and return a KickstartParser instance. | ||
| 39 | |||
| 40 | This is a simple utility function which takes a path to a kickstart file, | ||
| 41 | parses it and returns a pykickstart KickstartParser instance which can | ||
| 42 | be then passed to an ImageCreator constructor. | ||
| 43 | |||
| 44 | If an error occurs, a CreatorError exception is thrown. | ||
| 45 | """ | ||
| 46 | |||
| 47 | #version = ksversion.makeVersion() | ||
| 48 | #ks = ksparser.KickstartParser(version) | ||
| 49 | |||
| 50 | using_version = ksversion.DEVEL | ||
| 51 | commandMap[using_version]["bootloader"] = wicboot.Wic_Bootloader | ||
| 52 | commandMap[using_version]["part"] = partition.Wic_Partition | ||
| 53 | commandMap[using_version]["partition"] = partition.Wic_Partition | ||
| 54 | dataMap[using_version]["PartData"] = partition.Wic_PartData | ||
| 55 | superclass = ksversion.returnClassForVersion(version=using_version) | ||
| 56 | |||
| 57 | class KSHandlers(superclass): | ||
| 58 | def __init__(self): | ||
| 59 | superclass.__init__(self, mapping=commandMap[using_version]) | ||
| 60 | |||
| 61 | ks = ksparser.KickstartParser(KSHandlers(), errorsAreFatal=False) | ||
| 62 | |||
| 63 | try: | ||
| 64 | ks.readKickstart(path) | ||
| 65 | except (kserrors.KickstartParseError, kserrors.KickstartError), err: | ||
| 66 | if msger.ask("Errors occured on kickstart file, skip and continue?"): | ||
| 67 | msger.warning("%s" % err) | ||
| 68 | pass | ||
| 69 | else: | ||
| 70 | raise errors.KsError("%s" % err) | ||
| 71 | |||
| 72 | return ks | ||
| 73 | |||
| 74 | def get_image_size(ks, default = None): | ||
| 75 | __size = 0 | ||
| 76 | for p in ks.handler.partition.partitions: | ||
| 77 | if p.mountpoint == "/" and p.size: | ||
| 78 | __size = p.size | ||
| 79 | if __size > 0: | ||
| 80 | return int(__size) * 1024L * 1024L | ||
| 81 | else: | ||
| 82 | return default | ||
| 83 | |||
| 84 | def get_image_fstype(ks, default = None): | ||
| 85 | for p in ks.handler.partition.partitions: | ||
| 86 | if p.mountpoint == "/" and p.fstype: | ||
| 87 | return p.fstype | ||
| 88 | return default | ||
| 89 | |||
| 90 | def get_image_fsopts(ks, default = None): | ||
| 91 | for p in ks.handler.partition.partitions: | ||
| 92 | if p.mountpoint == "/" and p.fsopts: | ||
| 93 | return p.fsopts | ||
| 94 | return default | ||
| 95 | |||
| 96 | def get_timeout(ks, default = None): | ||
| 97 | if not hasattr(ks.handler.bootloader, "timeout"): | ||
| 98 | return default | ||
| 99 | if ks.handler.bootloader.timeout is None: | ||
| 100 | return default | ||
| 101 | return int(ks.handler.bootloader.timeout) | ||
| 102 | |||
| 103 | def get_kernel_args(ks, default = "ro rd.live.image"): | ||
| 104 | if not hasattr(ks.handler.bootloader, "appendLine"): | ||
| 105 | return default | ||
| 106 | if ks.handler.bootloader.appendLine is None: | ||
| 107 | return default | ||
| 108 | return "%s %s" %(default, ks.handler.bootloader.appendLine) | ||
| 109 | |||
| 110 | def get_menu_args(ks, default = ""): | ||
| 111 | if not hasattr(ks.handler.bootloader, "menus"): | ||
| 112 | return default | ||
| 113 | if ks.handler.bootloader.menus in (None, ""): | ||
| 114 | return default | ||
| 115 | return "%s" % ks.handler.bootloader.menus | ||
| 116 | |||
| 117 | def get_default_kernel(ks, default = None): | ||
| 118 | if not hasattr(ks.handler.bootloader, "default"): | ||
| 119 | return default | ||
| 120 | if not ks.handler.bootloader.default: | ||
| 121 | return default | ||
| 122 | return ks.handler.bootloader.default | ||
| 123 | |||
| 124 | def get_partitions(ks): | ||
| 125 | return ks.handler.partition.partitions | ||
diff --git a/scripts/lib/wic/kickstart/custom_commands/__init__.py b/scripts/lib/wic/kickstart/custom_commands/__init__.py new file mode 100644 index 0000000000..f84c6d9e00 --- /dev/null +++ b/scripts/lib/wic/kickstart/custom_commands/__init__.py | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | from micpartition import Mic_Partition | ||
| 2 | from micpartition import Mic_PartData | ||
| 3 | from partition import Wic_Partition | ||
| 4 | |||
| 5 | __all__ = ( | ||
| 6 | "Mic_Partition", | ||
| 7 | "Mic_PartData", | ||
| 8 | "Wic_Partition", | ||
| 9 | "Wic_PartData", | ||
| 10 | ) | ||
diff --git a/scripts/lib/wic/kickstart/custom_commands/micboot.py b/scripts/lib/wic/kickstart/custom_commands/micboot.py new file mode 100644 index 0000000000..d162142506 --- /dev/null +++ b/scripts/lib/wic/kickstart/custom_commands/micboot.py | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2008, 2009, 2010 Intel, Inc. | ||
| 4 | # | ||
| 5 | # Anas Nashif | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify it | ||
| 8 | # under the terms of the GNU General Public License as published by the Free | ||
| 9 | # Software Foundation; version 2 of the License | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, but | ||
| 12 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 13 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 14 | # for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 18 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 19 | |||
| 20 | from pykickstart.base import * | ||
| 21 | from pykickstart.errors import * | ||
| 22 | from pykickstart.options import * | ||
| 23 | from pykickstart.commands.bootloader import * | ||
| 24 | |||
| 25 | class Mic_Bootloader(F8_Bootloader): | ||
| 26 | def __init__(self, writePriority=10, appendLine="", driveorder=None, | ||
| 27 | forceLBA=False, location="", md5pass="", password="", | ||
| 28 | upgrade=False, menus=""): | ||
| 29 | F8_Bootloader.__init__(self, writePriority, appendLine, driveorder, | ||
| 30 | forceLBA, location, md5pass, password, upgrade) | ||
| 31 | |||
| 32 | self.menus = "" | ||
| 33 | self.ptable = "msdos" | ||
| 34 | |||
| 35 | def _getArgsAsStr(self): | ||
| 36 | ret = F8_Bootloader._getArgsAsStr(self) | ||
| 37 | |||
| 38 | if self.menus == "": | ||
| 39 | ret += " --menus=%s" %(self.menus,) | ||
| 40 | if self.ptable: | ||
| 41 | ret += " --ptable=\"%s\"" %(self.ptable,) | ||
| 42 | return ret | ||
| 43 | |||
| 44 | def _getParser(self): | ||
| 45 | op = F8_Bootloader._getParser(self) | ||
| 46 | op.add_option("--menus", dest="menus") | ||
| 47 | op.add_option("--ptable", dest="ptable", type="string") | ||
| 48 | return op | ||
| 49 | |||
diff --git a/scripts/lib/wic/kickstart/custom_commands/micpartition.py b/scripts/lib/wic/kickstart/custom_commands/micpartition.py new file mode 100644 index 0000000000..43d04f1294 --- /dev/null +++ b/scripts/lib/wic/kickstart/custom_commands/micpartition.py | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # | ||
| 3 | # Marko Saukko <marko.saukko@cybercom.com> | ||
| 4 | # | ||
| 5 | # Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | ||
| 6 | # | ||
| 7 | # This copyrighted material is made available to anyone wishing to use, modify, | ||
| 8 | # copy, or redistribute it subject to the terms and conditions of the GNU | ||
| 9 | # General Public License v.2. This program is distributed in the hope that it | ||
| 10 | # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the | ||
| 11 | # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 12 | # See the GNU General Public License for more details. | ||
| 13 | # | ||
| 14 | # You should have received a copy of the GNU General Public License along with | ||
| 15 | # this program; if not, write to the Free Software Foundation, Inc., 51 | ||
| 16 | # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| 17 | |||
| 18 | from pykickstart.commands.partition import * | ||
| 19 | |||
| 20 | class Mic_PartData(FC4_PartData): | ||
| 21 | removedKeywords = FC4_PartData.removedKeywords | ||
| 22 | removedAttrs = FC4_PartData.removedAttrs | ||
| 23 | |||
| 24 | def __init__(self, *args, **kwargs): | ||
| 25 | FC4_PartData.__init__(self, *args, **kwargs) | ||
| 26 | self.deleteRemovedAttrs() | ||
| 27 | self.align = kwargs.get("align", None) | ||
| 28 | self.extopts = kwargs.get("extopts", None) | ||
| 29 | self.part_type = kwargs.get("part_type", None) | ||
| 30 | |||
| 31 | def _getArgsAsStr(self): | ||
| 32 | retval = FC4_PartData._getArgsAsStr(self) | ||
| 33 | |||
| 34 | if self.align: | ||
| 35 | retval += " --align" | ||
| 36 | if self.extopts: | ||
| 37 | retval += " --extoptions=%s" % self.extopts | ||
| 38 | if self.part_type: | ||
| 39 | retval += " --part-type=%s" % self.part_type | ||
| 40 | |||
| 41 | return retval | ||
| 42 | |||
| 43 | class Mic_Partition(FC4_Partition): | ||
| 44 | removedKeywords = FC4_Partition.removedKeywords | ||
| 45 | removedAttrs = FC4_Partition.removedAttrs | ||
| 46 | |||
| 47 | def _getParser(self): | ||
| 48 | op = FC4_Partition._getParser(self) | ||
| 49 | # The alignment value is given in kBytes. e.g., value 8 means that | ||
| 50 | # the partition is aligned to start from 8096 byte boundary. | ||
| 51 | op.add_option("--align", type="int", action="store", dest="align", | ||
| 52 | default=None) | ||
| 53 | op.add_option("--extoptions", type="string", action="store", dest="extopts", | ||
| 54 | default=None) | ||
| 55 | op.add_option("--part-type", type="string", action="store", dest="part_type", | ||
| 56 | default=None) | ||
| 57 | return op | ||
diff --git a/scripts/lib/wic/kickstart/custom_commands/partition.py b/scripts/lib/wic/kickstart/custom_commands/partition.py new file mode 100644 index 0000000000..03332194df --- /dev/null +++ b/scripts/lib/wic/kickstart/custom_commands/partition.py | |||
| @@ -0,0 +1,652 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2013, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This module provides the OpenEmbedded partition object definitions. | ||
| 22 | # | ||
| 23 | # AUTHORS | ||
| 24 | # Tom Zanussi <tom.zanussi (at] linux.intel.com> | ||
| 25 | # | ||
| 26 | |||
| 27 | import shutil | ||
| 28 | import os | ||
| 29 | import tempfile | ||
| 30 | |||
| 31 | from pykickstart.commands.partition import * | ||
| 32 | from wic.utils.oe.misc import * | ||
| 33 | from wic.kickstart.custom_commands import * | ||
| 34 | from wic.plugin import pluginmgr | ||
| 35 | |||
| 36 | import os | ||
| 37 | from mic.utils.oe.package_manager import * | ||
| 38 | |||
| 39 | partition_methods = { | ||
| 40 | "do_install_pkgs":None, | ||
| 41 | "do_stage_partition":None, | ||
| 42 | "do_prepare_partition":None, | ||
| 43 | "do_configure_partition":None, | ||
| 44 | } | ||
| 45 | |||
| 46 | class Wic_PartData(Mic_PartData): | ||
| 47 | removedKeywords = Mic_PartData.removedKeywords | ||
| 48 | removedAttrs = Mic_PartData.removedAttrs | ||
| 49 | |||
| 50 | def __init__(self, *args, **kwargs): | ||
| 51 | Mic_PartData.__init__(self, *args, **kwargs) | ||
| 52 | self.deleteRemovedAttrs() | ||
| 53 | self.source = kwargs.get("source", None) | ||
| 54 | self.sourceparams = kwargs.get("sourceparams", None) | ||
| 55 | self.rootfs = kwargs.get("rootfs-dir", None) | ||
| 56 | self.source_file = "" | ||
| 57 | self.size = 0 | ||
| 58 | |||
| 59 | def _getArgsAsStr(self): | ||
| 60 | retval = Mic_PartData._getArgsAsStr(self) | ||
| 61 | |||
| 62 | if self.source: | ||
| 63 | retval += " --source=%s" % self.source | ||
| 64 | if self.sourceparams: | ||
| 65 | retval += " --sourceparams=%s" % self.sourceparams | ||
| 66 | if self.rootfs: | ||
| 67 | retval += " --rootfs-dir=%s" % self.rootfs | ||
| 68 | |||
| 69 | return retval | ||
| 70 | |||
| 71 | def get_rootfs(self): | ||
| 72 | """ | ||
| 73 | Acessor for rootfs dir | ||
| 74 | """ | ||
| 75 | return self.rootfs | ||
| 76 | |||
| 77 | def set_rootfs(self, rootfs): | ||
| 78 | """ | ||
| 79 | Acessor for actual rootfs dir, which must be set by source | ||
| 80 | plugins. | ||
| 81 | """ | ||
| 82 | self.rootfs = rootfs | ||
| 83 | |||
| 84 | def get_size(self): | ||
| 85 | """ | ||
| 86 | Accessor for partition size, 0 or --size before set_size(). | ||
| 87 | """ | ||
| 88 | return self.size | ||
| 89 | |||
| 90 | def set_size(self, size): | ||
| 91 | """ | ||
| 92 | Accessor for actual partition size, which must be set by source | ||
| 93 | plugins. | ||
| 94 | """ | ||
| 95 | self.size = size | ||
| 96 | |||
| 97 | def set_source_file(self, source_file): | ||
| 98 | """ | ||
| 99 | Accessor for source_file, the location of the generated partition | ||
| 100 | image, which must be set by source plugins. | ||
| 101 | """ | ||
| 102 | self.source_file = source_file | ||
| 103 | |||
| 104 | def get_extra_block_count(self, current_blocks): | ||
| 105 | """ | ||
| 106 | The --size param is reflected in self.size (in MB), and we already | ||
| 107 | have current_blocks (1k) blocks, calculate and return the | ||
| 108 | number of (1k) blocks we need to add to get to --size, 0 if | ||
| 109 | we're already there or beyond. | ||
| 110 | """ | ||
| 111 | msger.debug("Requested partition size for %s: %d" % \ | ||
| 112 | (self.mountpoint, self.size)) | ||
| 113 | |||
| 114 | if not self.size: | ||
| 115 | return 0 | ||
| 116 | |||
| 117 | requested_blocks = self.size * 1024 | ||
| 118 | |||
| 119 | msger.debug("Requested blocks %d, current_blocks %d" % \ | ||
| 120 | (requested_blocks, current_blocks)) | ||
| 121 | |||
| 122 | if requested_blocks > current_blocks: | ||
| 123 | return requested_blocks - current_blocks | ||
| 124 | else: | ||
| 125 | return 0 | ||
| 126 | |||
| 127 | def install_pkgs(self, creator, cr_workdir, oe_builddir, rootfs_dir, | ||
| 128 | bootimg_dir, kernel_dir, native_sysroot): | ||
| 129 | """ | ||
| 130 | Prepare content for individual partitions, installing packages. | ||
| 131 | """ | ||
| 132 | |||
| 133 | if not self.source: | ||
| 134 | return | ||
| 135 | |||
| 136 | self._source_methods = pluginmgr.get_source_plugin_methods(self.source, partition_methods) | ||
| 137 | self._source_methods["do_install_pkgs"](self, creator, | ||
| 138 | cr_workdir, | ||
| 139 | oe_builddir, | ||
| 140 | rootfs_dir, | ||
| 141 | bootimg_dir, | ||
| 142 | kernel_dir, | ||
| 143 | native_sysroot) | ||
| 144 | |||
| 145 | def install_pkgs_ipk(self, cr_workdir, oe_builddir, rootfs_dir, | ||
| 146 | native_sysroot, packages, repourl): | ||
| 147 | """ | ||
| 148 | Install packages specified into wks file using opkg package manager. | ||
| 149 | This method is dependend on bb module. | ||
| 150 | """ | ||
| 151 | |||
| 152 | gVar = {} | ||
| 153 | gVar["DEPLOY_DIR_IPK"] = os.path.join(oe_builddir, "tmp/deploy/ipk") | ||
| 154 | |||
| 155 | # Run postinstall scripts even in offline mode | ||
| 156 | # Use the arch priority package rather than higher version one if more than one candidate is found. | ||
| 157 | #d.setVar("OPKG_ARGS", "--force_postinstall --prefer-arch-to-version") | ||
| 158 | gVar["OPKG_ARGS"] = "--force_postinstall" | ||
| 159 | |||
| 160 | # OPKG path relative to /output_path | ||
| 161 | gVar["OPKGLIBDIR"] = "var/lib" | ||
| 162 | |||
| 163 | source_url = repourl.split() | ||
| 164 | |||
| 165 | # Generate feed uri's names, it doesn't seem to matter what name they have | ||
| 166 | feed_uris = "" | ||
| 167 | cnt = 0 | ||
| 168 | archs = "" | ||
| 169 | for url in source_url: | ||
| 170 | feed_uris += "cl_def_feed%d##%s\n" % (cnt, url) | ||
| 171 | cnt += 1 | ||
| 172 | head, tail = os.path.split(url) | ||
| 173 | archs += " " + tail | ||
| 174 | |||
| 175 | # IPK_FEED_URIS with special formating defines the URI's used as source for packages | ||
| 176 | gVar['IPK_FEED_URIS'] = feed_uris | ||
| 177 | |||
| 178 | gVar['BUILD_IMAGES_FROM_FEEDS'] = "1" | ||
| 179 | |||
| 180 | # We need to provide sysroot for utilities | ||
| 181 | gVar['STAGING_DIR_NATIVE'] = native_sysroot | ||
| 182 | |||
| 183 | # Set WORKDIR for output | ||
| 184 | gVar['WORKDIR'] = cr_workdir | ||
| 185 | |||
| 186 | # Set TMPDIR for output | ||
| 187 | gVar['TMPDIR'] = os.path.join(cr_workdir, "tmp") | ||
| 188 | |||
| 189 | if 'ROOTFS_DIR' in rootfs_dir: | ||
| 190 | target_dir = rootfs_dir['ROOTFS_DIR'] | ||
| 191 | elif os.path.isdir(rootfs_dir): | ||
| 192 | target_dir = rootfs_dir | ||
| 193 | else: | ||
| 194 | msg = "Couldn't find --rootfs-dir=%s connection" | ||
| 195 | msg += " or it is not a valid path, exiting" | ||
| 196 | msger.error(msg % rootfs_dir) | ||
| 197 | |||
| 198 | # Need native sysroot /usr/bin/ for opkg-cl | ||
| 199 | # chnage PATH var to avoid issues with host tools | ||
| 200 | defpath = os.environ['PATH'] | ||
| 201 | os.environ['PATH'] = native_sysroot + "/usr/bin/" + ":/bin:/usr/bin:" | ||
| 202 | |||
| 203 | pseudo = "export PSEUDO_PREFIX=%s/usr;" % native_sysroot | ||
| 204 | pseudo += "export PSEUDO_LOCALSTATEDIR=%s/../pseudo;" % target_dir | ||
| 205 | pseudo += "export PSEUDO_PASSWD=%s;" % target_dir | ||
| 206 | pseudo += "export PSEUDO_NOSYMLINKEXP=1;" | ||
| 207 | pseudo += "%s/usr/bin/pseudo " % native_sysroot | ||
| 208 | |||
| 209 | pm = WicOpkgPM(gVar, | ||
| 210 | target_dir, | ||
| 211 | 'opkg.conf', | ||
| 212 | archs, | ||
| 213 | pseudo, | ||
| 214 | native_sysroot) | ||
| 215 | |||
| 216 | pm.update() | ||
| 217 | |||
| 218 | pm.install(packages) | ||
| 219 | |||
| 220 | os.environ['PATH'] += defpath + ":" + native_sysroot + "/usr/bin/" | ||
| 221 | |||
| 222 | |||
| 223 | def prepare(self, cr, cr_workdir, oe_builddir, rootfs_dir, bootimg_dir, | ||
| 224 | kernel_dir, native_sysroot): | ||
| 225 | """ | ||
| 226 | Prepare content for individual partitions, depending on | ||
| 227 | partition command parameters. | ||
| 228 | """ | ||
| 229 | self.sourceparams_dict = {} | ||
| 230 | |||
| 231 | if self.sourceparams: | ||
| 232 | self.sourceparams_dict = parse_sourceparams(self.sourceparams) | ||
| 233 | |||
| 234 | if not self.source: | ||
| 235 | if not self.size: | ||
| 236 | msger.error("The %s partition has a size of zero. Please specify a non-zero --size for that partition." % self.mountpoint) | ||
| 237 | if self.fstype and self.fstype == "swap": | ||
| 238 | self.prepare_swap_partition(cr_workdir, oe_builddir, | ||
| 239 | native_sysroot) | ||
| 240 | elif self.fstype: | ||
| 241 | self.prepare_empty_partition(cr_workdir, oe_builddir, | ||
| 242 | native_sysroot) | ||
| 243 | return | ||
| 244 | |||
| 245 | plugins = pluginmgr.get_source_plugins() | ||
| 246 | |||
| 247 | if self.source not in plugins: | ||
| 248 | msger.error("The '%s' --source specified for %s doesn't exist.\n\tSee 'wic list source-plugins' for a list of available --sources.\n\tSee 'wic help source-plugins' for details on adding a new source plugin." % (self.source, self.mountpoint)) | ||
| 249 | |||
| 250 | self._source_methods = pluginmgr.get_source_plugin_methods(self.source, partition_methods) | ||
| 251 | self._source_methods["do_configure_partition"](self, self.sourceparams_dict, | ||
| 252 | cr, cr_workdir, | ||
| 253 | oe_builddir, | ||
| 254 | bootimg_dir, | ||
| 255 | kernel_dir, | ||
| 256 | native_sysroot) | ||
| 257 | self._source_methods["do_stage_partition"](self, self.sourceparams_dict, | ||
| 258 | cr, cr_workdir, | ||
| 259 | oe_builddir, | ||
| 260 | bootimg_dir, kernel_dir, | ||
| 261 | native_sysroot) | ||
| 262 | self._source_methods["do_prepare_partition"](self, self.sourceparams_dict, | ||
| 263 | cr, cr_workdir, | ||
| 264 | oe_builddir, | ||
| 265 | bootimg_dir, kernel_dir, rootfs_dir, | ||
| 266 | native_sysroot) | ||
| 267 | |||
| 268 | def prepare_rootfs_from_fs_image(self, cr_workdir, oe_builddir, | ||
| 269 | rootfs_dir): | ||
| 270 | """ | ||
| 271 | Handle an already-created partition e.g. xxx.ext3 | ||
| 272 | """ | ||
| 273 | rootfs = oe_builddir | ||
| 274 | du_cmd = "du -Lbms %s" % rootfs | ||
| 275 | out = exec_cmd(du_cmd) | ||
| 276 | rootfs_size = out.split()[0] | ||
| 277 | |||
| 278 | self.size = rootfs_size | ||
| 279 | self.source_file = rootfs | ||
| 280 | |||
| 281 | def prepare_rootfs(self, cr_workdir, oe_builddir, rootfs_dir, | ||
| 282 | native_sysroot): | ||
| 283 | """ | ||
| 284 | Prepare content for a rootfs partition i.e. create a partition | ||
| 285 | and fill it from a /rootfs dir. | ||
| 286 | |||
| 287 | Currently handles ext2/3/4, btrfs and vfat. | ||
| 288 | """ | ||
| 289 | pseudo = "export PSEUDO_PREFIX=%s/usr;" % native_sysroot | ||
| 290 | pseudo += "export PSEUDO_LOCALSTATEDIR=%s/../pseudo;" % rootfs_dir | ||
| 291 | pseudo += "export PSEUDO_PASSWD=%s;" % rootfs_dir | ||
| 292 | pseudo += "export PSEUDO_NOSYMLINKEXP=1;" | ||
| 293 | pseudo += "%s/usr/bin/pseudo " % native_sysroot | ||
| 294 | |||
| 295 | if self.fstype.startswith("ext"): | ||
| 296 | return self.prepare_rootfs_ext(cr_workdir, oe_builddir, | ||
| 297 | rootfs_dir, native_sysroot, | ||
| 298 | pseudo) | ||
| 299 | elif self.fstype.startswith("btrfs"): | ||
| 300 | return self.prepare_rootfs_btrfs(cr_workdir, oe_builddir, | ||
| 301 | rootfs_dir, native_sysroot, | ||
| 302 | pseudo) | ||
| 303 | |||
| 304 | elif self.fstype.startswith("vfat"): | ||
| 305 | return self.prepare_rootfs_vfat(cr_workdir, oe_builddir, | ||
| 306 | rootfs_dir, native_sysroot, | ||
| 307 | pseudo) | ||
| 308 | elif self.fstype.startswith("squashfs"): | ||
| 309 | return self.prepare_rootfs_squashfs(cr_workdir, oe_builddir, | ||
| 310 | rootfs_dir, native_sysroot, | ||
| 311 | pseudo) | ||
| 312 | |||
| 313 | def prepare_rootfs_ext(self, cr_workdir, oe_builddir, rootfs_dir, | ||
| 314 | native_sysroot, pseudo): | ||
| 315 | """ | ||
| 316 | Prepare content for an ext2/3/4 rootfs partition. | ||
| 317 | """ | ||
| 318 | |||
| 319 | image_rootfs = rootfs_dir | ||
| 320 | rootfs = "%s/rootfs_%s.%s" % (cr_workdir, self.label ,self.fstype) | ||
| 321 | |||
| 322 | du_cmd = "du -ks %s" % image_rootfs | ||
| 323 | out = exec_cmd(du_cmd) | ||
| 324 | actual_rootfs_size = int(out.split()[0]) | ||
| 325 | |||
| 326 | extra_blocks = self.get_extra_block_count(actual_rootfs_size) | ||
| 327 | |||
| 328 | if extra_blocks < IMAGE_EXTRA_SPACE: | ||
| 329 | extra_blocks = IMAGE_EXTRA_SPACE | ||
| 330 | |||
| 331 | rootfs_size = actual_rootfs_size + extra_blocks | ||
| 332 | rootfs_size *= IMAGE_OVERHEAD_FACTOR | ||
| 333 | |||
| 334 | msger.debug("Added %d extra blocks to %s to get to %d total blocks" % \ | ||
| 335 | (extra_blocks, self.mountpoint, rootfs_size)) | ||
| 336 | |||
| 337 | dd_cmd = "dd if=/dev/zero of=%s bs=1024 seek=%d count=0 bs=1k" % \ | ||
| 338 | (rootfs, rootfs_size) | ||
| 339 | exec_cmd(dd_cmd) | ||
| 340 | |||
| 341 | extra_imagecmd = "-i 8192" | ||
| 342 | |||
| 343 | mkfs_cmd = "mkfs.%s -F %s %s -d %s" % \ | ||
| 344 | (self.fstype, extra_imagecmd, rootfs, image_rootfs) | ||
| 345 | (rc, out) = exec_native_cmd(pseudo + mkfs_cmd, native_sysroot) | ||
| 346 | if rc: | ||
| 347 | print "rootfs_dir: %s" % rootfs_dir | ||
| 348 | msger.error("ERROR: mkfs.%s returned '%s' instead of 0 (which you probably don't want to ignore, use --debug for details) when creating filesystem from rootfs directory: %s" % (self.fstype, rc, rootfs_dir)) | ||
| 349 | |||
| 350 | # get the rootfs size in the right units for kickstart (Mb) | ||
| 351 | du_cmd = "du -Lbms %s" % rootfs | ||
| 352 | out = exec_cmd(du_cmd) | ||
| 353 | rootfs_size = out.split()[0] | ||
| 354 | |||
| 355 | self.size = rootfs_size | ||
| 356 | self.source_file = rootfs | ||
| 357 | |||
| 358 | return 0 | ||
| 359 | |||
| 360 | def prepare_for_uboot(self, arch, cr_workdir, oe_builddir, rootfs_dir, | ||
| 361 | native_sysroot): | ||
| 362 | """ | ||
| 363 | Generates u-boot image from source_file( ext2/3/4 ) | ||
| 364 | |||
| 365 | """ | ||
| 366 | pseudo = "export PSEUDO_PREFIX=%s/usr;" % native_sysroot | ||
| 367 | pseudo += "export PSEUDO_LOCALSTATEDIR=%s/../pseudo;" % rootfs_dir | ||
| 368 | pseudo += "export PSEUDO_PASSWD=%s;" % rootfs_dir | ||
| 369 | pseudo += "export PSEUDO_NOSYMLINKEXP=1;" | ||
| 370 | pseudo += "%s/usr/bin/pseudo " % native_sysroot | ||
| 371 | |||
| 372 | # 1) compress image | ||
| 373 | rootfs = self.source_file | ||
| 374 | rootfs_gzip = "%s.gz" % rootfs | ||
| 375 | gzip_cmd = "gzip -f -9 -c %s > %s" % (rootfs, rootfs_gzip) | ||
| 376 | rc, out = exec_native_cmd(pseudo + gzip_cmd, native_sysroot) | ||
| 377 | |||
| 378 | # 2) image for U-Boot | ||
| 379 | rootfs_uboot = "%s.u-boot" % rootfs_gzip | ||
| 380 | mkimage_cmd = "mkimage -A %s -O linux -T ramdisk -C gzip -n %s -d %s %s" % \ | ||
| 381 | (arch, self.label, rootfs_gzip, rootfs_uboot) | ||
| 382 | rc, out = exec_native_cmd(pseudo + mkimage_cmd, native_sysroot) | ||
| 383 | |||
| 384 | msger.info("\n\n\tThe new U-Boot ramdisk image can be found here:\n\t\t%s\n\n" % rootfs_uboot) | ||
| 385 | |||
| 386 | return 0 | ||
| 387 | |||
| 388 | def prepare_rootfs_btrfs(self, cr_workdir, oe_builddir, rootfs_dir, | ||
| 389 | native_sysroot, pseudo): | ||
| 390 | """ | ||
| 391 | Prepare content for a btrfs rootfs partition. | ||
| 392 | |||
| 393 | Currently handles ext2/3/4 and btrfs. | ||
| 394 | """ | ||
| 395 | image_rootfs = rootfs_dir | ||
| 396 | rootfs = "%s/rootfs_%s.%s" % (cr_workdir, self.label, self.fstype) | ||
| 397 | |||
| 398 | du_cmd = "du -ks %s" % image_rootfs | ||
| 399 | out = exec_cmd(du_cmd) | ||
| 400 | actual_rootfs_size = int(out.split()[0]) | ||
| 401 | |||
| 402 | extra_blocks = self.get_extra_block_count(actual_rootfs_size) | ||
| 403 | |||
| 404 | if extra_blocks < IMAGE_EXTRA_SPACE: | ||
| 405 | extra_blocks = IMAGE_EXTRA_SPACE | ||
| 406 | |||
| 407 | rootfs_size = actual_rootfs_size + extra_blocks | ||
| 408 | rootfs_size *= IMAGE_OVERHEAD_FACTOR | ||
| 409 | |||
| 410 | msger.debug("Added %d extra blocks to %s to get to %d total blocks" % \ | ||
| 411 | (extra_blocks, self.mountpoint, rootfs_size)) | ||
| 412 | |||
| 413 | dd_cmd = "dd if=/dev/zero of=%s bs=1024 seek=%d count=0 bs=1k" % \ | ||
| 414 | (rootfs, rootfs_size) | ||
| 415 | exec_cmd(dd_cmd) | ||
| 416 | |||
| 417 | mkfs_cmd = "mkfs.%s -b %d -r %s %s" % \ | ||
| 418 | (self.fstype, rootfs_size * 1024, image_rootfs, rootfs) | ||
| 419 | (rc, out) = exec_native_cmd(pseudo + mkfs_cmd, native_sysroot) | ||
| 420 | if rc: | ||
| 421 | msger.error("ERROR: mkfs.%s returned '%s' instead of 0 (which you probably don't want to ignore, use --debug for details) when creating filesystem from rootfs directory: %s" % (self.fstype, rc, rootfs_dir)) | ||
| 422 | |||
| 423 | # get the rootfs size in the right units for kickstart (Mb) | ||
| 424 | du_cmd = "du -Lbms %s" % rootfs | ||
| 425 | out = exec_cmd(du_cmd) | ||
| 426 | rootfs_size = out.split()[0] | ||
| 427 | |||
| 428 | self.size = rootfs_size | ||
| 429 | self.source_file = rootfs | ||
| 430 | |||
| 431 | def prepare_rootfs_vfat(self, cr_workdir, oe_builddir, rootfs_dir, | ||
| 432 | native_sysroot, pseudo): | ||
| 433 | """ | ||
| 434 | Prepare content for a vfat rootfs partition. | ||
| 435 | """ | ||
| 436 | image_rootfs = rootfs_dir | ||
| 437 | rootfs = "%s/rootfs_%s.%s" % (cr_workdir, self.label, self.fstype) | ||
| 438 | |||
| 439 | du_cmd = "du -bks %s" % image_rootfs | ||
| 440 | out = exec_cmd(du_cmd) | ||
| 441 | blocks = int(out.split()[0]) | ||
| 442 | |||
| 443 | extra_blocks = self.get_extra_block_count(blocks) | ||
| 444 | |||
| 445 | if extra_blocks < IMAGE_EXTRA_SPACE: | ||
| 446 | extra_blocks = IMAGE_EXTRA_SPACE | ||
| 447 | |||
| 448 | blocks += extra_blocks | ||
| 449 | |||
| 450 | msger.debug("Added %d extra blocks to %s to get to %d total blocks" % \ | ||
| 451 | (extra_blocks, self.mountpoint, blocks)) | ||
| 452 | |||
| 453 | # Ensure total sectors is an integral number of sectors per | ||
| 454 | # track or mcopy will complain. Sectors are 512 bytes, and we | ||
| 455 | # generate images with 32 sectors per track. This calculation | ||
| 456 | # is done in blocks, thus the mod by 16 instead of 32. Apply | ||
| 457 | # sector count fix only when needed. | ||
| 458 | if blocks % 16 != 0: | ||
| 459 | blocks += (16 - (blocks % 16)) | ||
| 460 | |||
| 461 | dosfs_cmd = "mkdosfs -n boot -S 512 -C %s %d" % (rootfs, blocks) | ||
| 462 | exec_native_cmd(dosfs_cmd, native_sysroot) | ||
| 463 | |||
| 464 | mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (rootfs, image_rootfs) | ||
| 465 | rc, out = exec_native_cmd(mcopy_cmd, native_sysroot) | ||
| 466 | if rc: | ||
| 467 | msger.error("ERROR: mcopy returned '%s' instead of 0 (which you probably don't want to ignore, use --debug for details)" % rc) | ||
| 468 | |||
| 469 | chmod_cmd = "chmod 644 %s" % rootfs | ||
| 470 | exec_cmd(chmod_cmd) | ||
| 471 | |||
| 472 | # get the rootfs size in the right units for kickstart (Mb) | ||
| 473 | du_cmd = "du -Lbms %s" % rootfs | ||
| 474 | out = exec_cmd(du_cmd) | ||
| 475 | rootfs_size = out.split()[0] | ||
| 476 | |||
| 477 | self.set_size(rootfs_size) | ||
| 478 | self.set_source_file(rootfs) | ||
| 479 | |||
| 480 | def prepare_rootfs_squashfs(self, cr_workdir, oe_builddir, rootfs_dir, | ||
| 481 | native_sysroot, pseudo): | ||
| 482 | """ | ||
| 483 | Prepare content for a squashfs rootfs partition. | ||
| 484 | """ | ||
| 485 | image_rootfs = rootfs_dir | ||
| 486 | rootfs = "%s/rootfs_%s.%s" % (cr_workdir, self.label ,self.fstype) | ||
| 487 | |||
| 488 | squashfs_cmd = "mksquashfs %s %s -noappend" % \ | ||
| 489 | (image_rootfs, rootfs) | ||
| 490 | exec_native_cmd(pseudo + squashfs_cmd, native_sysroot) | ||
| 491 | |||
| 492 | # get the rootfs size in the right units for kickstart (Mb) | ||
| 493 | du_cmd = "du -Lbms %s" % rootfs | ||
| 494 | out = exec_cmd(du_cmd) | ||
| 495 | rootfs_size = out.split()[0] | ||
| 496 | |||
| 497 | self.size = rootfs_size | ||
| 498 | self.source_file = rootfs | ||
| 499 | |||
| 500 | return 0 | ||
| 501 | |||
| 502 | def prepare_empty_partition(self, cr_workdir, oe_builddir, native_sysroot): | ||
| 503 | """ | ||
| 504 | Prepare an empty partition. | ||
| 505 | """ | ||
| 506 | if self.fstype.startswith("ext"): | ||
| 507 | return self.prepare_empty_partition_ext(cr_workdir, oe_builddir, | ||
| 508 | native_sysroot) | ||
| 509 | elif self.fstype.startswith("btrfs"): | ||
| 510 | return self.prepare_empty_partition_btrfs(cr_workdir, oe_builddir, | ||
| 511 | native_sysroot) | ||
| 512 | elif self.fstype.startswith("vfat"): | ||
| 513 | return self.prepare_empty_partition_vfat(cr_workdir, oe_builddir, | ||
| 514 | native_sysroot) | ||
| 515 | elif self.fstype.startswith("squashfs"): | ||
| 516 | return self.prepare_empty_partition_squashfs(cr_workdir, oe_builddir, | ||
| 517 | native_sysroot) | ||
| 518 | |||
| 519 | def prepare_empty_partition_ext(self, cr_workdir, oe_builddir, | ||
| 520 | native_sysroot): | ||
| 521 | """ | ||
| 522 | Prepare an empty ext2/3/4 partition. | ||
| 523 | """ | ||
| 524 | fs = "%s/fs_%s.%s" % (cr_workdir, self.label, self.fstype) | ||
| 525 | |||
| 526 | dd_cmd = "dd if=/dev/zero of=%s bs=1M seek=%d count=0" % \ | ||
| 527 | (fs, self.size) | ||
| 528 | exec_cmd(dd_cmd) | ||
| 529 | |||
| 530 | extra_imagecmd = "-i 8192" | ||
| 531 | |||
| 532 | mkfs_cmd = "mkfs.%s -F %s %s" % (self.fstype, extra_imagecmd, fs) | ||
| 533 | (rc, out) = exec_native_cmd(mkfs_cmd, native_sysroot) | ||
| 534 | if rc: | ||
| 535 | msger.error("ERROR: mkfs.%s returned '%s' instead of 0 (which you probably don't want to ignore, use --debug for details)" % (self.fstype, rc)) | ||
| 536 | |||
| 537 | self.source_file = fs | ||
| 538 | |||
| 539 | return 0 | ||
| 540 | |||
| 541 | def prepare_empty_partition_btrfs(self, cr_workdir, oe_builddir, | ||
| 542 | native_sysroot): | ||
| 543 | """ | ||
| 544 | Prepare an empty btrfs partition. | ||
| 545 | """ | ||
| 546 | fs = "%s/fs_%s.%s" % (cr_workdir, self.label, self.fstype) | ||
| 547 | |||
| 548 | dd_cmd = "dd if=/dev/zero of=%s bs=1M seek=%d count=0" % \ | ||
| 549 | (fs, self.size) | ||
| 550 | exec_cmd(dd_cmd) | ||
| 551 | |||
| 552 | mkfs_cmd = "mkfs.%s -b %d %s" % (self.fstype, self.size * 1024, rootfs) | ||
| 553 | (rc, out) = exec_native_cmd(mkfs_cmd, native_sysroot) | ||
| 554 | if rc: | ||
| 555 | msger.error("ERROR: mkfs.%s returned '%s' instead of 0 (which you probably don't want to ignore, use --debug for details)" % (self.fstype, rc)) | ||
| 556 | |||
| 557 | mkfs_cmd = "mkfs.%s -F %s %s" % (self.fstype, extra_imagecmd, fs) | ||
| 558 | (rc, out) = exec_native_cmd(mkfs_cmd, native_sysroot) | ||
| 559 | if rc: | ||
| 560 | msger.error("ERROR: mkfs.%s returned '%s' instead of 0 (which you probably don't want to ignore, use --debug for details)" % (self.fstype, rc)) | ||
| 561 | |||
| 562 | self.source_file = fs | ||
| 563 | |||
| 564 | return 0 | ||
| 565 | |||
| 566 | def prepare_empty_partition_vfat(self, cr_workdir, oe_builddir, | ||
| 567 | native_sysroot): | ||
| 568 | """ | ||
| 569 | Prepare an empty vfat partition. | ||
| 570 | """ | ||
| 571 | fs = "%s/fs_%s.%s" % (cr_workdir, self.label, self.fstype) | ||
| 572 | |||
| 573 | blocks = self.size * 1024 | ||
| 574 | |||
| 575 | dosfs_cmd = "mkdosfs -n boot -S 512 -C %s %d" % (fs, blocks) | ||
| 576 | exec_native_cmd(dosfs_cmd, native_sysroot) | ||
| 577 | |||
| 578 | chmod_cmd = "chmod 644 %s" % fs | ||
| 579 | exec_cmd(chmod_cmd) | ||
| 580 | |||
| 581 | self.source_file = fs | ||
| 582 | |||
| 583 | return 0 | ||
| 584 | |||
| 585 | def prepare_empty_partition_squashfs(self, cr_workdir, oe_builddir, | ||
| 586 | native_sysroot): | ||
| 587 | """ | ||
| 588 | Prepare an empty squashfs partition. | ||
| 589 | """ | ||
| 590 | msger.warning("Creating of an empty squashfs %s partition was attempted. " \ | ||
| 591 | "Proceeding as requested." % self.mountpoint) | ||
| 592 | |||
| 593 | fs = "%s/fs_%s.%s" % (cr_workdir, self.label, self.fstype) | ||
| 594 | |||
| 595 | # it is not possible to create a squashfs without source data, | ||
| 596 | # thus prepare an empty temp dir that is used as source | ||
| 597 | tmpdir = tempfile.mkdtemp() | ||
| 598 | |||
| 599 | squashfs_cmd = "mksquashfs %s %s -noappend" % \ | ||
| 600 | (tmpdir, fs) | ||
| 601 | exec_native_cmd(squashfs_cmd, native_sysroot) | ||
| 602 | |||
| 603 | os.rmdir(tmpdir) | ||
| 604 | |||
| 605 | # get the rootfs size in the right units for kickstart (Mb) | ||
| 606 | du_cmd = "du -Lbms %s" % fs | ||
| 607 | out = exec_cmd(du_cmd) | ||
| 608 | fs_size = out.split()[0] | ||
| 609 | |||
| 610 | self.size = fs_size | ||
| 611 | self.source_file = fs | ||
| 612 | |||
| 613 | return 0 | ||
| 614 | |||
| 615 | def prepare_swap_partition(self, cr_workdir, oe_builddir, native_sysroot): | ||
| 616 | """ | ||
| 617 | Prepare a swap partition. | ||
| 618 | """ | ||
| 619 | fs = "%s/fs.%s" % (cr_workdir, self.fstype) | ||
| 620 | |||
| 621 | dd_cmd = "dd if=/dev/zero of=%s bs=1M seek=%d count=0" % \ | ||
| 622 | (fs, self.size) | ||
| 623 | exec_cmd(dd_cmd) | ||
| 624 | |||
| 625 | import uuid | ||
| 626 | label_str = "" | ||
| 627 | if self.label: | ||
| 628 | label_str = "-L %s" % self.label | ||
| 629 | mkswap_cmd = "mkswap %s -U %s %s" % (label_str, str(uuid.uuid1()), fs) | ||
| 630 | exec_native_cmd(mkswap_cmd, native_sysroot) | ||
| 631 | |||
| 632 | self.source_file = fs | ||
| 633 | |||
| 634 | return 0 | ||
| 635 | |||
| 636 | class Wic_Partition(Mic_Partition): | ||
| 637 | removedKeywords = Mic_Partition.removedKeywords | ||
| 638 | removedAttrs = Mic_Partition.removedAttrs | ||
| 639 | |||
| 640 | def _getParser(self): | ||
| 641 | op = Mic_Partition._getParser(self) | ||
| 642 | # use specified source file to fill the partition | ||
| 643 | # and calculate partition size | ||
| 644 | op.add_option("--source", type="string", action="store", | ||
| 645 | dest="source", default=None) | ||
| 646 | # comma-separated list of param=value pairs | ||
| 647 | op.add_option("--sourceparams", type="string", action="store", | ||
| 648 | dest="sourceparams", default=None) | ||
| 649 | # use specified rootfs path to fill the partition | ||
| 650 | op.add_option("--rootfs-dir", type="string", action="store", | ||
| 651 | dest="rootfs", default=None) | ||
| 652 | return op | ||
diff --git a/scripts/lib/wic/kickstart/custom_commands/wicboot.py b/scripts/lib/wic/kickstart/custom_commands/wicboot.py new file mode 100644 index 0000000000..f1914169d8 --- /dev/null +++ b/scripts/lib/wic/kickstart/custom_commands/wicboot.py | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2014, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This module provides the OpenEmbedded bootloader object definitions. | ||
| 22 | # | ||
| 23 | # AUTHORS | ||
| 24 | # Tom Zanussi <tom.zanussi (at] linux.intel.com> | ||
| 25 | # | ||
| 26 | |||
| 27 | from pykickstart.base import * | ||
| 28 | from pykickstart.errors import * | ||
| 29 | from pykickstart.options import * | ||
| 30 | from pykickstart.commands.bootloader import * | ||
| 31 | |||
| 32 | from wic.kickstart.custom_commands.micboot import * | ||
| 33 | |||
| 34 | class Wic_Bootloader(Mic_Bootloader): | ||
| 35 | def __init__(self, writePriority=10, appendLine="", driveorder=None, | ||
| 36 | forceLBA=False, location="", md5pass="", password="", | ||
| 37 | upgrade=False, menus=""): | ||
| 38 | Mic_Bootloader.__init__(self, writePriority, appendLine, driveorder, | ||
| 39 | forceLBA, location, md5pass, password, upgrade) | ||
| 40 | |||
| 41 | self.source = "" | ||
| 42 | |||
| 43 | def _getArgsAsStr(self): | ||
| 44 | retval = Mic_Bootloader._getArgsAsStr(self) | ||
| 45 | |||
| 46 | if self.source: | ||
| 47 | retval += " --source=%s" % self.source | ||
| 48 | |||
| 49 | return retval | ||
| 50 | |||
| 51 | def _getParser(self): | ||
| 52 | op = Mic_Bootloader._getParser(self) | ||
| 53 | # use specified source plugin to implement bootloader-specific methods | ||
| 54 | op.add_option("--source", type="string", action="store", | ||
| 55 | dest="source", default=None) | ||
| 56 | return op | ||
| 57 | |||
diff --git a/scripts/lib/wic/msger.py b/scripts/lib/wic/msger.py new file mode 100644 index 0000000000..9f557e7b9a --- /dev/null +++ b/scripts/lib/wic/msger.py | |||
| @@ -0,0 +1,309 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # vim: ai ts=4 sts=4 et sw=4 | ||
| 3 | # | ||
| 4 | # Copyright (c) 2009, 2010, 2011 Intel, Inc. | ||
| 5 | # | ||
| 6 | # This program is free software; you can redistribute it and/or modify it | ||
| 7 | # under the terms of the GNU General Public License as published by the Free | ||
| 8 | # Software Foundation; version 2 of the License | ||
| 9 | # | ||
| 10 | # This program is distributed in the hope that it will be useful, but | ||
| 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 12 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 13 | # for more details. | ||
| 14 | # | ||
| 15 | # You should have received a copy of the GNU General Public License along | ||
| 16 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 17 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 18 | |||
| 19 | import os,sys | ||
| 20 | import re | ||
| 21 | import time | ||
| 22 | |||
| 23 | __ALL__ = ['set_mode', | ||
| 24 | 'get_loglevel', | ||
| 25 | 'set_loglevel', | ||
| 26 | 'set_logfile', | ||
| 27 | 'raw', | ||
| 28 | 'debug', | ||
| 29 | 'verbose', | ||
| 30 | 'info', | ||
| 31 | 'warning', | ||
| 32 | 'error', | ||
| 33 | 'ask', | ||
| 34 | 'pause', | ||
| 35 | ] | ||
| 36 | |||
| 37 | # COLORs in ANSI | ||
| 38 | INFO_COLOR = 32 # green | ||
| 39 | WARN_COLOR = 33 # yellow | ||
| 40 | ERR_COLOR = 31 # red | ||
| 41 | ASK_COLOR = 34 # blue | ||
| 42 | NO_COLOR = 0 | ||
| 43 | |||
| 44 | PREFIX_RE = re.compile('^<(.*?)>\s*(.*)', re.S) | ||
| 45 | |||
| 46 | INTERACTIVE = True | ||
| 47 | |||
| 48 | LOG_LEVEL = 1 | ||
| 49 | LOG_LEVELS = { | ||
| 50 | 'quiet': 0, | ||
| 51 | 'normal': 1, | ||
| 52 | 'verbose': 2, | ||
| 53 | 'debug': 3, | ||
| 54 | 'never': 4, | ||
| 55 | } | ||
| 56 | |||
| 57 | LOG_FILE_FP = None | ||
| 58 | LOG_CONTENT = '' | ||
| 59 | CATCHERR_BUFFILE_FD = -1 | ||
| 60 | CATCHERR_BUFFILE_PATH = None | ||
| 61 | CATCHERR_SAVED_2 = -1 | ||
| 62 | |||
| 63 | def _general_print(head, color, msg = None, stream = None, level = 'normal'): | ||
| 64 | global LOG_CONTENT | ||
| 65 | if not stream: | ||
| 66 | stream = sys.stdout | ||
| 67 | |||
| 68 | if LOG_LEVELS[level] > LOG_LEVEL: | ||
| 69 | # skip | ||
| 70 | return | ||
| 71 | |||
| 72 | # encode raw 'unicode' str to utf8 encoded str | ||
| 73 | if msg and isinstance(msg, unicode): | ||
| 74 | msg = msg.encode('utf-8', 'ignore') | ||
| 75 | |||
| 76 | errormsg = '' | ||
| 77 | if CATCHERR_BUFFILE_FD > 0: | ||
| 78 | size = os.lseek(CATCHERR_BUFFILE_FD , 0, os.SEEK_END) | ||
| 79 | os.lseek(CATCHERR_BUFFILE_FD, 0, os.SEEK_SET) | ||
| 80 | errormsg = os.read(CATCHERR_BUFFILE_FD, size) | ||
| 81 | os.ftruncate(CATCHERR_BUFFILE_FD, 0) | ||
| 82 | |||
| 83 | # append error msg to LOG | ||
| 84 | if errormsg: | ||
| 85 | LOG_CONTENT += errormsg | ||
| 86 | |||
| 87 | # append normal msg to LOG | ||
| 88 | save_msg = msg.strip() if msg else None | ||
| 89 | if save_msg: | ||
| 90 | timestr = time.strftime("[%m/%d %H:%M:%S %Z] ", time.localtime()) | ||
| 91 | LOG_CONTENT += timestr + save_msg + '\n' | ||
| 92 | |||
| 93 | if errormsg: | ||
| 94 | _color_print('', NO_COLOR, errormsg, stream, level) | ||
| 95 | |||
| 96 | _color_print(head, color, msg, stream, level) | ||
| 97 | |||
| 98 | def _color_print(head, color, msg, stream, level): | ||
| 99 | colored = True | ||
| 100 | if color == NO_COLOR or \ | ||
| 101 | not stream.isatty() or \ | ||
| 102 | os.getenv('ANSI_COLORS_DISABLED') is not None: | ||
| 103 | colored = False | ||
| 104 | |||
| 105 | if head.startswith('\r'): | ||
| 106 | # need not \n at last | ||
| 107 | newline = False | ||
| 108 | else: | ||
| 109 | newline = True | ||
| 110 | |||
| 111 | if colored: | ||
| 112 | head = '\033[%dm%s:\033[0m ' %(color, head) | ||
| 113 | if not newline: | ||
| 114 | # ESC cmd to clear line | ||
| 115 | head = '\033[2K' + head | ||
| 116 | else: | ||
| 117 | if head: | ||
| 118 | head += ': ' | ||
| 119 | if head.startswith('\r'): | ||
| 120 | head = head.lstrip() | ||
| 121 | newline = True | ||
| 122 | |||
| 123 | if msg is not None: | ||
| 124 | if isinstance(msg, unicode): | ||
| 125 | msg = msg.encode('utf8', 'ignore') | ||
| 126 | |||
| 127 | stream.write('%s%s' % (head, msg)) | ||
| 128 | if newline: | ||
| 129 | stream.write('\n') | ||
| 130 | |||
| 131 | stream.flush() | ||
| 132 | |||
| 133 | def _color_perror(head, color, msg, level = 'normal'): | ||
| 134 | if CATCHERR_BUFFILE_FD > 0: | ||
| 135 | _general_print(head, color, msg, sys.stdout, level) | ||
| 136 | else: | ||
| 137 | _general_print(head, color, msg, sys.stderr, level) | ||
| 138 | |||
| 139 | def _split_msg(head, msg): | ||
| 140 | if isinstance(msg, list): | ||
| 141 | msg = '\n'.join(map(str, msg)) | ||
| 142 | |||
| 143 | if msg.startswith('\n'): | ||
| 144 | # means print \n at first | ||
| 145 | msg = msg.lstrip() | ||
| 146 | head = '\n' + head | ||
| 147 | |||
| 148 | elif msg.startswith('\r'): | ||
| 149 | # means print \r at first | ||
| 150 | msg = msg.lstrip() | ||
| 151 | head = '\r' + head | ||
| 152 | |||
| 153 | m = PREFIX_RE.match(msg) | ||
| 154 | if m: | ||
| 155 | head += ' <%s>' % m.group(1) | ||
| 156 | msg = m.group(2) | ||
| 157 | |||
| 158 | return head, msg | ||
| 159 | |||
| 160 | def get_loglevel(): | ||
| 161 | return (k for k,v in LOG_LEVELS.items() if v==LOG_LEVEL).next() | ||
| 162 | |||
| 163 | def set_loglevel(level): | ||
| 164 | global LOG_LEVEL | ||
| 165 | if level not in LOG_LEVELS: | ||
| 166 | # no effect | ||
| 167 | return | ||
| 168 | |||
| 169 | LOG_LEVEL = LOG_LEVELS[level] | ||
| 170 | |||
| 171 | def set_interactive(mode=True): | ||
| 172 | global INTERACTIVE | ||
| 173 | if mode: | ||
| 174 | INTERACTIVE = True | ||
| 175 | else: | ||
| 176 | INTERACTIVE = False | ||
| 177 | |||
| 178 | def log(msg=''): | ||
| 179 | # log msg to LOG_CONTENT then save to logfile | ||
| 180 | global LOG_CONTENT | ||
| 181 | if msg: | ||
| 182 | LOG_CONTENT += msg | ||
| 183 | |||
| 184 | def raw(msg=''): | ||
| 185 | _general_print('', NO_COLOR, msg) | ||
| 186 | |||
| 187 | def info(msg): | ||
| 188 | head, msg = _split_msg('Info', msg) | ||
| 189 | _general_print(head, INFO_COLOR, msg) | ||
| 190 | |||
| 191 | def verbose(msg): | ||
| 192 | head, msg = _split_msg('Verbose', msg) | ||
| 193 | _general_print(head, INFO_COLOR, msg, level = 'verbose') | ||
| 194 | |||
| 195 | def warning(msg): | ||
| 196 | head, msg = _split_msg('Warning', msg) | ||
| 197 | _color_perror(head, WARN_COLOR, msg) | ||
| 198 | |||
| 199 | def debug(msg): | ||
| 200 | head, msg = _split_msg('Debug', msg) | ||
| 201 | _color_perror(head, ERR_COLOR, msg, level = 'debug') | ||
| 202 | |||
| 203 | def error(msg): | ||
| 204 | head, msg = _split_msg('Error', msg) | ||
| 205 | _color_perror(head, ERR_COLOR, msg) | ||
| 206 | sys.exit(1) | ||
| 207 | |||
| 208 | def ask(msg, default=True): | ||
| 209 | _general_print('\rQ', ASK_COLOR, '') | ||
| 210 | try: | ||
| 211 | if default: | ||
| 212 | msg += '(Y/n) ' | ||
| 213 | else: | ||
| 214 | msg += '(y/N) ' | ||
| 215 | if INTERACTIVE: | ||
| 216 | while True: | ||
| 217 | repl = raw_input(msg) | ||
| 218 | if repl.lower() == 'y': | ||
| 219 | return True | ||
| 220 | elif repl.lower() == 'n': | ||
| 221 | return False | ||
| 222 | elif not repl.strip(): | ||
| 223 | # <Enter> | ||
| 224 | return default | ||
| 225 | |||
| 226 | # else loop | ||
| 227 | else: | ||
| 228 | if default: | ||
| 229 | msg += ' Y' | ||
| 230 | else: | ||
| 231 | msg += ' N' | ||
| 232 | _general_print('', NO_COLOR, msg) | ||
| 233 | |||
| 234 | return default | ||
| 235 | except KeyboardInterrupt: | ||
| 236 | sys.stdout.write('\n') | ||
| 237 | sys.exit(2) | ||
| 238 | |||
| 239 | def choice(msg, choices, default=0): | ||
| 240 | if default >= len(choices): | ||
| 241 | return None | ||
| 242 | _general_print('\rQ', ASK_COLOR, '') | ||
| 243 | try: | ||
| 244 | msg += " [%s] " % '/'.join(choices) | ||
| 245 | if INTERACTIVE: | ||
| 246 | while True: | ||
| 247 | repl = raw_input(msg) | ||
| 248 | if repl in choices: | ||
| 249 | return repl | ||
| 250 | elif not repl.strip(): | ||
| 251 | return choices[default] | ||
| 252 | else: | ||
| 253 | msg += choices[default] | ||
| 254 | _general_print('', NO_COLOR, msg) | ||
| 255 | |||
| 256 | return choices[default] | ||
| 257 | except KeyboardInterrupt: | ||
| 258 | sys.stdout.write('\n') | ||
| 259 | sys.exit(2) | ||
| 260 | |||
| 261 | def pause(msg=None): | ||
| 262 | if INTERACTIVE: | ||
| 263 | _general_print('\rQ', ASK_COLOR, '') | ||
| 264 | if msg is None: | ||
| 265 | msg = 'press <ENTER> to continue ...' | ||
| 266 | raw_input(msg) | ||
| 267 | |||
| 268 | def set_logfile(fpath): | ||
| 269 | global LOG_FILE_FP | ||
| 270 | |||
| 271 | def _savelogf(): | ||
| 272 | if LOG_FILE_FP: | ||
| 273 | fp = open(LOG_FILE_FP, 'w') | ||
| 274 | fp.write(LOG_CONTENT) | ||
| 275 | fp.close() | ||
| 276 | |||
| 277 | if LOG_FILE_FP is not None: | ||
| 278 | warning('duplicate log file configuration') | ||
| 279 | |||
| 280 | LOG_FILE_FP = fpath | ||
| 281 | |||
| 282 | import atexit | ||
| 283 | atexit.register(_savelogf) | ||
| 284 | |||
| 285 | def enable_logstderr(fpath): | ||
| 286 | global CATCHERR_BUFFILE_FD | ||
| 287 | global CATCHERR_BUFFILE_PATH | ||
| 288 | global CATCHERR_SAVED_2 | ||
| 289 | |||
| 290 | if os.path.exists(fpath): | ||
| 291 | os.remove(fpath) | ||
| 292 | CATCHERR_BUFFILE_PATH = fpath | ||
| 293 | CATCHERR_BUFFILE_FD = os.open(CATCHERR_BUFFILE_PATH, os.O_RDWR|os.O_CREAT) | ||
| 294 | CATCHERR_SAVED_2 = os.dup(2) | ||
| 295 | os.dup2(CATCHERR_BUFFILE_FD, 2) | ||
| 296 | |||
| 297 | def disable_logstderr(): | ||
| 298 | global CATCHERR_BUFFILE_FD | ||
| 299 | global CATCHERR_BUFFILE_PATH | ||
| 300 | global CATCHERR_SAVED_2 | ||
| 301 | |||
| 302 | raw(msg = None) # flush message buffer and print it. | ||
| 303 | os.dup2(CATCHERR_SAVED_2, 2) | ||
| 304 | os.close(CATCHERR_SAVED_2) | ||
| 305 | os.close(CATCHERR_BUFFILE_FD) | ||
| 306 | os.unlink(CATCHERR_BUFFILE_PATH) | ||
| 307 | CATCHERR_BUFFILE_FD = -1 | ||
| 308 | CATCHERR_BUFFILE_PATH = None | ||
| 309 | CATCHERR_SAVED_2 = -1 | ||
diff --git a/scripts/lib/wic/plugin.py b/scripts/lib/wic/plugin.py new file mode 100644 index 0000000000..41a80175ca --- /dev/null +++ b/scripts/lib/wic/plugin.py | |||
| @@ -0,0 +1,156 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2011 Intel, Inc. | ||
| 4 | # | ||
| 5 | # This program is free software; you can redistribute it and/or modify it | ||
| 6 | # under the terms of the GNU General Public License as published by the Free | ||
| 7 | # Software Foundation; version 2 of the License | ||
| 8 | # | ||
| 9 | # This program is distributed in the hope that it will be useful, but | ||
| 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 12 | # for more details. | ||
| 13 | # | ||
| 14 | # You should have received a copy of the GNU General Public License along | ||
| 15 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 16 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 17 | |||
| 18 | import os, sys | ||
| 19 | |||
| 20 | from wic import msger | ||
| 21 | from wic import pluginbase | ||
| 22 | from wic.utils import errors | ||
| 23 | from wic.utils.oe.misc import * | ||
| 24 | |||
| 25 | __ALL__ = ['PluginMgr', 'pluginmgr'] | ||
| 26 | |||
| 27 | PLUGIN_TYPES = ["imager", "source"] | ||
| 28 | |||
| 29 | PLUGIN_DIR = "/lib/wic/plugins" # relative to scripts | ||
| 30 | SCRIPTS_PLUGIN_DIR = "scripts" + PLUGIN_DIR | ||
| 31 | |||
| 32 | class PluginMgr(object): | ||
| 33 | plugin_dirs = {} | ||
| 34 | |||
| 35 | # make the manager class as singleton | ||
| 36 | _instance = None | ||
| 37 | def __new__(cls, *args, **kwargs): | ||
| 38 | if not cls._instance: | ||
| 39 | cls._instance = super(PluginMgr, cls).__new__(cls, *args, **kwargs) | ||
| 40 | |||
| 41 | return cls._instance | ||
| 42 | |||
| 43 | def __init__(self): | ||
| 44 | wic_path = os.path.dirname(__file__) | ||
| 45 | eos = wic_path.find('scripts') + len('scripts') | ||
| 46 | scripts_path = wic_path[:eos] | ||
| 47 | self.scripts_path = scripts_path | ||
| 48 | self.plugin_dir = scripts_path + PLUGIN_DIR | ||
| 49 | self.layers_path = None | ||
| 50 | |||
| 51 | def _build_plugin_dir_list(self, dl, ptype): | ||
| 52 | if self.layers_path is None: | ||
| 53 | self.layers_path = get_bitbake_var("BBLAYERS") | ||
| 54 | layer_dirs = [] | ||
| 55 | |||
| 56 | if self.layers_path is not None: | ||
| 57 | for layer_path in self.layers_path.split(): | ||
| 58 | path = os.path.join(layer_path, SCRIPTS_PLUGIN_DIR, ptype) | ||
| 59 | layer_dirs.append(path) | ||
| 60 | |||
| 61 | path = os.path.join(dl, ptype) | ||
| 62 | layer_dirs.append(path) | ||
| 63 | |||
| 64 | return layer_dirs | ||
| 65 | |||
| 66 | def append_dirs(self, dirs): | ||
| 67 | for path in dirs: | ||
| 68 | self._add_plugindir(path) | ||
| 69 | |||
| 70 | # load all the plugins AGAIN | ||
| 71 | self._load_all() | ||
| 72 | |||
| 73 | def _add_plugindir(self, path): | ||
| 74 | path = os.path.abspath(os.path.expanduser(path)) | ||
| 75 | |||
| 76 | if not os.path.isdir(path): | ||
| 77 | msger.debug("Plugin dir is not a directory or does not exist: %s"\ | ||
| 78 | % path) | ||
| 79 | return | ||
| 80 | |||
| 81 | if path not in self.plugin_dirs: | ||
| 82 | self.plugin_dirs[path] = False | ||
| 83 | # the value True/False means "loaded" | ||
| 84 | |||
| 85 | def _load_all(self): | ||
| 86 | for (pdir, loaded) in self.plugin_dirs.iteritems(): | ||
| 87 | if loaded: continue | ||
| 88 | |||
| 89 | sys.path.insert(0, pdir) | ||
| 90 | for mod in [x[:-3] for x in os.listdir(pdir) if x.endswith(".py")]: | ||
| 91 | if mod and mod != '__init__': | ||
| 92 | if mod in sys.modules: | ||
| 93 | #self.plugin_dirs[pdir] = True | ||
| 94 | msger.warning("Module %s already exists, skip" % mod) | ||
| 95 | else: | ||
| 96 | try: | ||
| 97 | pymod = __import__(mod) | ||
| 98 | self.plugin_dirs[pdir] = True | ||
| 99 | msger.debug("Plugin module %s:%s imported"\ | ||
| 100 | % (mod, pymod.__file__)) | ||
| 101 | except ImportError, err: | ||
| 102 | msg = 'Failed to load plugin %s/%s: %s' \ | ||
| 103 | % (os.path.basename(pdir), mod, err) | ||
| 104 | msger.warning(msg) | ||
| 105 | |||
| 106 | del(sys.path[0]) | ||
| 107 | |||
| 108 | def get_plugins(self, ptype): | ||
| 109 | """ the return value is dict of name:class pairs """ | ||
| 110 | |||
| 111 | if ptype not in PLUGIN_TYPES: | ||
| 112 | raise errors.CreatorError('%s is not valid plugin type' % ptype) | ||
| 113 | |||
| 114 | plugins_dir = self._build_plugin_dir_list(self.plugin_dir, ptype) | ||
| 115 | |||
| 116 | self.append_dirs(plugins_dir) | ||
| 117 | |||
| 118 | return pluginbase.get_plugins(ptype) | ||
| 119 | |||
| 120 | def get_source_plugins(self): | ||
| 121 | """ | ||
| 122 | Return list of available source plugins. | ||
| 123 | """ | ||
| 124 | plugins_dir = self._build_plugin_dir_list(self.plugin_dir, 'source') | ||
| 125 | |||
| 126 | self.append_dirs(plugins_dir) | ||
| 127 | |||
| 128 | plugins = [] | ||
| 129 | |||
| 130 | for _source_name, klass in self.get_plugins('source').iteritems(): | ||
| 131 | plugins.append(_source_name) | ||
| 132 | |||
| 133 | return plugins | ||
| 134 | |||
| 135 | |||
| 136 | def get_source_plugin_methods(self, source_name, methods): | ||
| 137 | """ | ||
| 138 | The methods param is a dict with the method names to find. On | ||
| 139 | return, the dict values will be filled in with pointers to the | ||
| 140 | corresponding methods. If one or more methods are not found, | ||
| 141 | None is returned. | ||
| 142 | """ | ||
| 143 | return_methods = None | ||
| 144 | for _source_name, klass in self.get_plugins('source').iteritems(): | ||
| 145 | if _source_name == source_name: | ||
| 146 | for _method_name in methods.keys(): | ||
| 147 | if not hasattr(klass, _method_name): | ||
| 148 | msger.warning("Unimplemented %s source interface for: %s"\ | ||
| 149 | % (_method_name, _source_name)) | ||
| 150 | return None | ||
| 151 | func = getattr(klass, _method_name) | ||
| 152 | methods[_method_name] = func | ||
| 153 | return_methods = methods | ||
| 154 | return return_methods | ||
| 155 | |||
| 156 | pluginmgr = PluginMgr() | ||
diff --git a/scripts/lib/wic/pluginbase.py b/scripts/lib/wic/pluginbase.py new file mode 100644 index 0000000000..d63e34e089 --- /dev/null +++ b/scripts/lib/wic/pluginbase.py | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2011 Intel, Inc. | ||
| 4 | # | ||
| 5 | # This program is free software; you can redistribute it and/or modify it | ||
| 6 | # under the terms of the GNU General Public License as published by the Free | ||
| 7 | # Software Foundation; version 2 of the License | ||
| 8 | # | ||
| 9 | # This program is distributed in the hope that it will be useful, but | ||
| 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 12 | # for more details. | ||
| 13 | # | ||
| 14 | # You should have received a copy of the GNU General Public License along | ||
| 15 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 16 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 17 | |||
| 18 | import os | ||
| 19 | import shutil | ||
| 20 | from wic import msger | ||
| 21 | from wic.utils import errors | ||
| 22 | |||
| 23 | class _Plugin(object): | ||
| 24 | class __metaclass__(type): | ||
| 25 | def __init__(cls, name, bases, attrs): | ||
| 26 | if not hasattr(cls, 'plugins'): | ||
| 27 | cls.plugins = {} | ||
| 28 | |||
| 29 | elif 'wic_plugin_type' in attrs: | ||
| 30 | if attrs['wic_plugin_type'] not in cls.plugins: | ||
| 31 | cls.plugins[attrs['wic_plugin_type']] = {} | ||
| 32 | |||
| 33 | elif hasattr(cls, 'wic_plugin_type') and 'name' in attrs: | ||
| 34 | cls.plugins[cls.wic_plugin_type][attrs['name']] = cls | ||
| 35 | |||
| 36 | def show_plugins(cls): | ||
| 37 | for cls in cls.plugins[cls.wic_plugin_type]: | ||
| 38 | print cls | ||
| 39 | |||
| 40 | def get_plugins(cls): | ||
| 41 | return cls.plugins | ||
| 42 | |||
| 43 | |||
| 44 | class ImagerPlugin(_Plugin): | ||
| 45 | wic_plugin_type = "imager" | ||
| 46 | |||
| 47 | |||
| 48 | class SourcePlugin(_Plugin): | ||
| 49 | wic_plugin_type = "source" | ||
| 50 | """ | ||
| 51 | The methods that can be implemented by --source plugins. | ||
| 52 | |||
| 53 | Any methods not implemented in a subclass inherit these. | ||
| 54 | """ | ||
| 55 | |||
| 56 | @classmethod | ||
| 57 | def do_install_pkgs(self, part, creator, cr_workdir, oe_builddir, rootfs_dir, | ||
| 58 | bootimg_dir, kernel_dir, native_sysroot): | ||
| 59 | """ | ||
| 60 | Called before partitions have been prepared and assembled into a | ||
| 61 | disk image. Install packages into rootfs | ||
| 62 | """ | ||
| 63 | msger.debug("SourcePlugin: do_install_pkgs: part %s" % part) | ||
| 64 | |||
| 65 | @classmethod | ||
| 66 | def do_install_disk(self, disk, disk_name, cr, workdir, oe_builddir, | ||
| 67 | bootimg_dir, kernel_dir, native_sysroot): | ||
| 68 | """ | ||
| 69 | Called after all partitions have been prepared and assembled into a | ||
| 70 | disk image. This provides a hook to allow finalization of a | ||
| 71 | disk image e.g. to write an MBR to it. | ||
| 72 | """ | ||
| 73 | msger.debug("SourcePlugin: do_install_disk: disk: %s" % disk_name) | ||
| 74 | |||
| 75 | @classmethod | ||
| 76 | def do_stage_partition(self, part, source_params, cr, cr_workdir, | ||
| 77 | oe_builddir, bootimg_dir, kernel_dir, | ||
| 78 | native_sysroot): | ||
| 79 | """ | ||
| 80 | Special content staging hook called before do_prepare_partition(), | ||
| 81 | normally empty. | ||
| 82 | |||
| 83 | Typically, a partition will just use the passed-in parame e.g | ||
| 84 | straight bootimg_dir, etc, but in some cases, things need to | ||
| 85 | be more tailored e.g. to use a deploy dir + /boot, etc. This | ||
| 86 | hook allows those files to be staged in a customized fashion. | ||
| 87 | Not that get_bitbake_var() allows you to acces non-standard | ||
| 88 | variables that you might want to use for this. | ||
| 89 | """ | ||
| 90 | msger.debug("SourcePlugin: do_stage_partition: part: %s" % part) | ||
| 91 | |||
| 92 | @classmethod | ||
| 93 | def do_configure_partition(self, part, source_params, cr, cr_workdir, | ||
| 94 | oe_builddir, bootimg_dir, kernel_dir, | ||
| 95 | native_sysroot): | ||
| 96 | """ | ||
| 97 | Called before do_prepare_partition(), typically used to create | ||
| 98 | custom configuration files for a partition, for example | ||
| 99 | syslinux or grub config files. | ||
| 100 | """ | ||
| 101 | msger.debug("SourcePlugin: do_configure_partition: part: %s" % part) | ||
| 102 | |||
| 103 | @classmethod | ||
| 104 | def do_prepare_partition(self, part, source_params, cr, cr_workdir, | ||
| 105 | oe_builddir, bootimg_dir, kernel_dir, rootfs_dir, | ||
| 106 | native_sysroot): | ||
| 107 | """ | ||
| 108 | Called to do the actual content population for a partition i.e. it | ||
| 109 | 'prepares' the partition to be incorporated into the image. | ||
| 110 | """ | ||
| 111 | msger.debug("SourcePlugin: do_prepare_partition: part: %s" % part) | ||
| 112 | |||
| 113 | def get_plugins(typen): | ||
| 114 | ps = ImagerPlugin.get_plugins() | ||
| 115 | if typen in ps: | ||
| 116 | return ps[typen] | ||
| 117 | else: | ||
| 118 | return None | ||
| 119 | |||
| 120 | __all__ = ['ImagerPlugin', 'SourcePlugin', 'get_plugins'] | ||
diff --git a/scripts/lib/wic/plugins/imager/direct_plugin.py b/scripts/lib/wic/plugins/imager/direct_plugin.py new file mode 100644 index 0000000000..5601c3f1c9 --- /dev/null +++ b/scripts/lib/wic/plugins/imager/direct_plugin.py | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2013, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This implements the 'direct' imager plugin class for 'wic' | ||
| 22 | # | ||
| 23 | # AUTHORS | ||
| 24 | # Tom Zanussi <tom.zanussi (at] linux.intel.com> | ||
| 25 | # | ||
| 26 | |||
| 27 | import os | ||
| 28 | import shutil | ||
| 29 | import re | ||
| 30 | import tempfile | ||
| 31 | |||
| 32 | from wic import msger | ||
| 33 | from wic.utils import misc, fs_related, errors, runner, cmdln | ||
| 34 | from wic.conf import configmgr | ||
| 35 | from wic.plugin import pluginmgr | ||
| 36 | |||
| 37 | import wic.imager.direct as direct | ||
| 38 | from wic.pluginbase import ImagerPlugin | ||
| 39 | |||
| 40 | class DirectPlugin(ImagerPlugin): | ||
| 41 | name = 'direct' | ||
| 42 | |||
| 43 | @classmethod | ||
| 44 | def __rootfs_dir_to_dict(self, rootfs_dirs): | ||
| 45 | """ | ||
| 46 | Gets a string that contain 'connection=dir' splitted by | ||
| 47 | space and return a dict | ||
| 48 | """ | ||
| 49 | krootfs_dir = {} | ||
| 50 | for rootfs_dir in rootfs_dirs.split(' '): | ||
| 51 | k, v = rootfs_dir.split('=') | ||
| 52 | krootfs_dir[k] = v | ||
| 53 | |||
| 54 | return krootfs_dir | ||
| 55 | |||
| 56 | @classmethod | ||
| 57 | def do_create(self, subcmd, opts, *args): | ||
| 58 | """ | ||
| 59 | Create direct image, called from creator as 'direct' cmd | ||
| 60 | """ | ||
| 61 | if len(args) != 7: | ||
| 62 | raise errors.Usage("Extra arguments given") | ||
| 63 | |||
| 64 | native_sysroot = args[0] | ||
| 65 | kernel_dir = args[1] | ||
| 66 | bootimg_dir = args[2] | ||
| 67 | rootfs_dir = args[3] | ||
| 68 | |||
| 69 | creatoropts = configmgr.create | ||
| 70 | ksconf = args[4] | ||
| 71 | |||
| 72 | image_output_dir = args[5] | ||
| 73 | oe_builddir = args[6] | ||
| 74 | |||
| 75 | krootfs_dir = self.__rootfs_dir_to_dict(rootfs_dir) | ||
| 76 | |||
| 77 | configmgr._ksconf = ksconf | ||
| 78 | |||
| 79 | creator = direct.DirectImageCreator(oe_builddir, | ||
| 80 | image_output_dir, | ||
| 81 | krootfs_dir, | ||
| 82 | bootimg_dir, | ||
| 83 | kernel_dir, | ||
| 84 | native_sysroot, | ||
| 85 | creatoropts) | ||
| 86 | |||
| 87 | try: | ||
| 88 | creator.create() | ||
| 89 | creator.assemble() | ||
| 90 | creator.finalize() | ||
| 91 | creator.print_outimage_info() | ||
| 92 | |||
| 93 | except errors.CreatorError: | ||
| 94 | raise | ||
| 95 | finally: | ||
| 96 | creator.cleanup() | ||
| 97 | |||
| 98 | return 0 | ||
diff --git a/scripts/lib/wic/plugins/source/bootimg-efi.py b/scripts/lib/wic/plugins/source/bootimg-efi.py new file mode 100644 index 0000000000..e4067b6dbf --- /dev/null +++ b/scripts/lib/wic/plugins/source/bootimg-efi.py | |||
| @@ -0,0 +1,236 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2014, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This implements the 'bootimg-efi' source plugin class for 'wic' | ||
| 22 | # | ||
| 23 | # AUTHORS | ||
| 24 | # Tom Zanussi <tom.zanussi (at] linux.intel.com> | ||
| 25 | # | ||
| 26 | |||
| 27 | import os | ||
| 28 | import shutil | ||
| 29 | import re | ||
| 30 | import tempfile | ||
| 31 | |||
| 32 | from wic import kickstart, msger | ||
| 33 | from wic.utils import misc, fs_related, errors, runner, cmdln | ||
| 34 | from wic.conf import configmgr | ||
| 35 | from wic.plugin import pluginmgr | ||
| 36 | import wic.imager.direct as direct | ||
| 37 | from wic.pluginbase import SourcePlugin | ||
| 38 | from wic.utils.oe.misc import * | ||
| 39 | from wic.imager.direct import DirectImageCreator | ||
| 40 | |||
| 41 | class BootimgEFIPlugin(SourcePlugin): | ||
| 42 | name = 'bootimg-efi' | ||
| 43 | |||
| 44 | @classmethod | ||
| 45 | def do_configure_grubefi(self, hdddir, cr, cr_workdir): | ||
| 46 | """ | ||
| 47 | Create loader-specific (grub-efi) config | ||
| 48 | """ | ||
| 49 | splash = os.path.join(cr_workdir, "/EFI/boot/splash.jpg") | ||
| 50 | if os.path.exists(splash): | ||
| 51 | splashline = "menu background splash.jpg" | ||
| 52 | else: | ||
| 53 | splashline = "" | ||
| 54 | |||
| 55 | (rootdev, root_part_uuid) = cr._get_boot_config() | ||
| 56 | options = cr.ks.handler.bootloader.appendLine | ||
| 57 | |||
| 58 | grubefi_conf = "" | ||
| 59 | grubefi_conf += "serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1\n" | ||
| 60 | grubefi_conf += "default=boot\n" | ||
| 61 | timeout = kickstart.get_timeout(cr.ks) | ||
| 62 | if not timeout: | ||
| 63 | timeout = 0 | ||
| 64 | grubefi_conf += "timeout=%s\n" % timeout | ||
| 65 | grubefi_conf += "menuentry 'boot'{\n" | ||
| 66 | |||
| 67 | kernel = "/bzImage" | ||
| 68 | |||
| 69 | if cr._ptable_format == 'msdos': | ||
| 70 | rootstr = rootdev | ||
| 71 | else: | ||
| 72 | raise ImageError("Unsupported partition table format found") | ||
| 73 | |||
| 74 | grubefi_conf += "linux %s root=%s rootwait %s\n" \ | ||
| 75 | % (kernel, rootstr, options) | ||
| 76 | grubefi_conf += "}\n" | ||
| 77 | if splashline: | ||
| 78 | syslinux_conf += "%s\n" % splashline | ||
| 79 | |||
| 80 | msger.debug("Writing grubefi config %s/hdd/boot/EFI/BOOT/grub.cfg" \ | ||
| 81 | % cr_workdir) | ||
| 82 | cfg = open("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir, "w") | ||
| 83 | cfg.write(grubefi_conf) | ||
| 84 | cfg.close() | ||
| 85 | |||
| 86 | @classmethod | ||
| 87 | def do_configure_gummiboot(self, hdddir, cr, cr_workdir): | ||
| 88 | """ | ||
| 89 | Create loader-specific (gummiboot) config | ||
| 90 | """ | ||
| 91 | install_cmd = "install -d %s/loader" % hdddir | ||
| 92 | exec_cmd(install_cmd) | ||
| 93 | |||
| 94 | install_cmd = "install -d %s/loader/entries" % hdddir | ||
| 95 | exec_cmd(install_cmd) | ||
| 96 | |||
| 97 | (rootdev, root_part_uuid) = cr._get_boot_config() | ||
| 98 | options = cr.ks.handler.bootloader.appendLine | ||
| 99 | |||
| 100 | timeout = kickstart.get_timeout(cr.ks) | ||
| 101 | if not timeout: | ||
| 102 | timeout = 0 | ||
| 103 | |||
| 104 | loader_conf = "" | ||
| 105 | loader_conf += "default boot\n" | ||
| 106 | loader_conf += "timeout %d\n" % timeout | ||
| 107 | |||
| 108 | msger.debug("Writing gummiboot config %s/hdd/boot/loader/loader.conf" \ | ||
| 109 | % cr_workdir) | ||
| 110 | cfg = open("%s/hdd/boot/loader/loader.conf" % cr_workdir, "w") | ||
| 111 | cfg.write(loader_conf) | ||
| 112 | cfg.close() | ||
| 113 | |||
| 114 | kernel = "/bzImage" | ||
| 115 | |||
| 116 | if cr._ptable_format == 'msdos': | ||
| 117 | rootstr = rootdev | ||
| 118 | else: | ||
| 119 | raise ImageError("Unsupported partition table format found") | ||
| 120 | |||
| 121 | boot_conf = "" | ||
| 122 | boot_conf += "title boot\n" | ||
| 123 | boot_conf += "linux %s\n" % kernel | ||
| 124 | boot_conf += "options LABEL=Boot root=%s %s\n" \ | ||
| 125 | % (rootstr, options) | ||
| 126 | |||
| 127 | msger.debug("Writing gummiboot config %s/hdd/boot/loader/entries/boot.conf" \ | ||
| 128 | % cr_workdir) | ||
| 129 | cfg = open("%s/hdd/boot/loader/entries/boot.conf" % cr_workdir, "w") | ||
| 130 | cfg.write(boot_conf) | ||
| 131 | cfg.close() | ||
| 132 | |||
| 133 | |||
| 134 | @classmethod | ||
| 135 | def do_configure_partition(self, part, source_params, cr, cr_workdir, | ||
| 136 | oe_builddir, bootimg_dir, kernel_dir, | ||
| 137 | native_sysroot): | ||
| 138 | """ | ||
| 139 | Called before do_prepare_partition(), creates loader-specific config | ||
| 140 | """ | ||
| 141 | hdddir = "%s/hdd/boot" % cr_workdir | ||
| 142 | rm_cmd = "rm -rf %s" % cr_workdir | ||
| 143 | exec_cmd(rm_cmd) | ||
| 144 | |||
| 145 | install_cmd = "install -d %s/EFI/BOOT" % hdddir | ||
| 146 | exec_cmd(install_cmd) | ||
| 147 | |||
| 148 | try: | ||
| 149 | if source_params['loader'] == 'grub-efi': | ||
| 150 | self.do_configure_grubefi(hdddir, cr, cr_workdir) | ||
| 151 | elif source_params['loader'] == 'gummiboot': | ||
| 152 | self.do_configure_gummiboot(hdddir, cr, cr_workdir) | ||
| 153 | else: | ||
| 154 | msger.error("unrecognized bootimg-efi loader: %s" % source_params['loader']) | ||
| 155 | except KeyError: | ||
| 156 | msger.error("bootimg-efi requires a loader, none specified") | ||
| 157 | |||
| 158 | |||
| 159 | @classmethod | ||
| 160 | def do_prepare_partition(self, part, source_params, cr, cr_workdir, | ||
| 161 | oe_builddir, bootimg_dir, kernel_dir, | ||
| 162 | rootfs_dir, native_sysroot): | ||
| 163 | """ | ||
| 164 | Called to do the actual content population for a partition i.e. it | ||
| 165 | 'prepares' the partition to be incorporated into the image. | ||
| 166 | In this case, prepare content for an EFI (grub) boot partition. | ||
| 167 | """ | ||
| 168 | if not bootimg_dir: | ||
| 169 | bootimg_dir = get_bitbake_var("HDDDIR") | ||
| 170 | if not bootimg_dir: | ||
| 171 | msger.error("Couldn't find HDDDIR, exiting\n") | ||
| 172 | # just so the result notes display it | ||
| 173 | cr.set_bootimg_dir(bootimg_dir) | ||
| 174 | |||
| 175 | staging_kernel_dir = kernel_dir | ||
| 176 | |||
| 177 | hdddir = "%s/hdd/boot" % cr_workdir | ||
| 178 | |||
| 179 | install_cmd = "install -m 0644 %s/bzImage %s/bzImage" % \ | ||
| 180 | (staging_kernel_dir, hdddir) | ||
| 181 | exec_cmd(install_cmd) | ||
| 182 | |||
| 183 | try: | ||
| 184 | if source_params['loader'] == 'grub-efi': | ||
| 185 | shutil.copyfile("%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir, | ||
| 186 | "%s/grub.cfg" % cr_workdir) | ||
| 187 | cp_cmd = "cp %s/EFI/BOOT/* %s/EFI/BOOT" % (bootimg_dir, hdddir) | ||
| 188 | exec_cmd(cp_cmd, True) | ||
| 189 | shutil.move("%s/grub.cfg" % cr_workdir, | ||
| 190 | "%s/hdd/boot/EFI/BOOT/grub.cfg" % cr_workdir) | ||
| 191 | elif source_params['loader'] == 'gummiboot': | ||
| 192 | cp_cmd = "cp %s/EFI/BOOT/* %s/EFI/BOOT" % (bootimg_dir, hdddir) | ||
| 193 | exec_cmd(cp_cmd, True) | ||
| 194 | else: | ||
| 195 | msger.error("unrecognized bootimg-efi loader: %s" % source_params['loader']) | ||
| 196 | except KeyError: | ||
| 197 | msger.error("bootimg-efi requires a loader, none specified") | ||
| 198 | |||
| 199 | du_cmd = "du -bks %s" % hdddir | ||
| 200 | out = exec_cmd(du_cmd) | ||
| 201 | blocks = int(out.split()[0]) | ||
| 202 | |||
| 203 | extra_blocks = part.get_extra_block_count(blocks) | ||
| 204 | |||
| 205 | if extra_blocks < BOOTDD_EXTRA_SPACE: | ||
| 206 | extra_blocks = BOOTDD_EXTRA_SPACE | ||
| 207 | |||
| 208 | blocks += extra_blocks | ||
| 209 | |||
| 210 | msger.debug("Added %d extra blocks to %s to get to %d total blocks" % \ | ||
| 211 | (extra_blocks, part.mountpoint, blocks)) | ||
| 212 | |||
| 213 | # Ensure total sectors is an integral number of sectors per | ||
| 214 | # track or mcopy will complain. Sectors are 512 bytes, and we | ||
| 215 | # generate images with 32 sectors per track. This calculation is | ||
| 216 | # done in blocks, thus the mod by 16 instead of 32. | ||
| 217 | blocks += (16 - (blocks % 16)) | ||
| 218 | |||
| 219 | # dosfs image, created by mkdosfs | ||
| 220 | bootimg = "%s/boot.img" % cr_workdir | ||
| 221 | |||
| 222 | dosfs_cmd = "mkdosfs -n efi -C %s %d" % (bootimg, blocks) | ||
| 223 | exec_native_cmd(dosfs_cmd, native_sysroot) | ||
| 224 | |||
| 225 | mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir) | ||
| 226 | exec_native_cmd(mcopy_cmd, native_sysroot) | ||
| 227 | |||
| 228 | chmod_cmd = "chmod 644 %s" % bootimg | ||
| 229 | exec_cmd(chmod_cmd) | ||
| 230 | |||
| 231 | du_cmd = "du -Lbms %s" % bootimg | ||
| 232 | out = exec_cmd(du_cmd) | ||
| 233 | bootimg_size = out.split()[0] | ||
| 234 | |||
| 235 | part.set_size(bootimg_size) | ||
| 236 | part.set_source_file(bootimg) | ||
diff --git a/scripts/lib/wic/plugins/source/bootimg-partition.py b/scripts/lib/wic/plugins/source/bootimg-partition.py new file mode 100644 index 0000000000..564118ad8b --- /dev/null +++ b/scripts/lib/wic/plugins/source/bootimg-partition.py | |||
| @@ -0,0 +1,115 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # This program is free software; you can redistribute it and/or modify | ||
| 5 | # it under the terms of the GNU General Public License version 2 as | ||
| 6 | # published by the Free Software Foundation. | ||
| 7 | # | ||
| 8 | # This program is distributed in the hope that it will be useful, | ||
| 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | # GNU General Public License for more details. | ||
| 12 | # | ||
| 13 | # You should have received a copy of the GNU General Public License along | ||
| 14 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 15 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 16 | # | ||
| 17 | # DESCRIPTION | ||
| 18 | # This implements the 'bootimg-partition' source plugin class for | ||
| 19 | # 'wic'. The plugin creates an image of boot partition, copying over | ||
| 20 | # files listed in IMAGE_BOOT_FILES bitbake variable. | ||
| 21 | # | ||
| 22 | # AUTHORS | ||
| 23 | # Maciej Borzecki <maciej.borzecki (at] open-rnd.pl> | ||
| 24 | # | ||
| 25 | |||
| 26 | import os | ||
| 27 | import re | ||
| 28 | |||
| 29 | from wic import msger | ||
| 30 | from wic.pluginbase import SourcePlugin | ||
| 31 | from wic.utils.oe.misc import * | ||
| 32 | |||
| 33 | class BootimgPartitionPlugin(SourcePlugin): | ||
| 34 | name = 'bootimg-partition' | ||
| 35 | |||
| 36 | @classmethod | ||
| 37 | def do_install_disk(self, disk, disk_name, cr, workdir, oe_builddir, | ||
| 38 | bootimg_dir, kernel_dir, native_sysroot): | ||
| 39 | """ | ||
| 40 | Called after all partitions have been prepared and assembled into a | ||
| 41 | disk image. Do nothing. | ||
| 42 | """ | ||
| 43 | pass | ||
| 44 | |||
| 45 | @classmethod | ||
| 46 | def do_configure_partition(self, part, source_params, cr, cr_workdir, | ||
| 47 | oe_builddir, bootimg_dir, kernel_dir, | ||
| 48 | native_sysroot): | ||
| 49 | """ | ||
| 50 | Called before do_prepare_partition(). Possibly prepare | ||
| 51 | configuration files of some sort. | ||
| 52 | |||
| 53 | """ | ||
| 54 | pass | ||
| 55 | |||
| 56 | @classmethod | ||
| 57 | def do_prepare_partition(self, part, source_params, cr, cr_workdir, | ||
| 58 | oe_builddir, bootimg_dir, kernel_dir, | ||
| 59 | rootfs_dir, native_sysroot): | ||
| 60 | """ | ||
| 61 | Called to do the actual content population for a partition i.e. it | ||
| 62 | 'prepares' the partition to be incorporated into the image. | ||
| 63 | In this case, does the following: | ||
| 64 | - sets up a vfat partition | ||
| 65 | - copies all files listed in IMAGE_BOOT_FILES variable | ||
| 66 | """ | ||
| 67 | hdddir = "%s/boot" % cr_workdir | ||
| 68 | rm_cmd = "rm -rf %s" % cr_workdir | ||
| 69 | exec_cmd(rm_cmd) | ||
| 70 | |||
| 71 | install_cmd = "install -d %s" % hdddir | ||
| 72 | exec_cmd(install_cmd) | ||
| 73 | |||
| 74 | if not bootimg_dir: | ||
| 75 | bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") | ||
| 76 | if not bootimg_dir: | ||
| 77 | msger.error("Couldn't find DEPLOY_DIR_IMAGE, exiting\n") | ||
| 78 | |||
| 79 | msger.debug('Bootimg dir: %s' % bootimg_dir) | ||
| 80 | |||
| 81 | boot_files = get_bitbake_var("IMAGE_BOOT_FILES") | ||
| 82 | |||
| 83 | if not boot_files: | ||
| 84 | msger.error('No boot files defined, IMAGE_BOOT_FILES unset') | ||
| 85 | |||
| 86 | msger.debug('Boot files: %s' % boot_files) | ||
| 87 | |||
| 88 | # list of tuples (src_name, dst_name) | ||
| 89 | deploy_files = [] | ||
| 90 | for src_entry in re.findall(r'[\w;\-\./]+', boot_files): | ||
| 91 | if ';' in src_entry: | ||
| 92 | dst_entry = tuple(src_entry.split(';')) | ||
| 93 | if not dst_entry[0] or not dst_entry[1]: | ||
| 94 | msger.error('Malformed boot file entry: %s' % (src_entry)) | ||
| 95 | else: | ||
| 96 | dst_entry = (src_entry, src_entry) | ||
| 97 | |||
| 98 | msger.debug('Destination entry: %r' % (dst_entry,)) | ||
| 99 | deploy_files.append(dst_entry) | ||
| 100 | |||
| 101 | for deploy_entry in deploy_files: | ||
| 102 | src, dst = deploy_entry | ||
| 103 | src_path = os.path.join(bootimg_dir, src) | ||
| 104 | dst_path = os.path.join(hdddir, dst) | ||
| 105 | |||
| 106 | msger.debug('Install %s as %s' % (os.path.basename(src_path), | ||
| 107 | dst_path)) | ||
| 108 | install_cmd = "install -m 0644 -D %s %s" \ | ||
| 109 | % (src_path, dst_path) | ||
| 110 | exec_cmd(install_cmd) | ||
| 111 | |||
| 112 | msger.debug('Prepare boot partition using rootfs in %s' % (hdddir)) | ||
| 113 | part.prepare_rootfs(cr_workdir, oe_builddir, hdddir, | ||
| 114 | native_sysroot) | ||
| 115 | |||
diff --git a/scripts/lib/wic/plugins/source/bootimg-pcbios.py b/scripts/lib/wic/plugins/source/bootimg-pcbios.py new file mode 100644 index 0000000000..8a1aca1ad1 --- /dev/null +++ b/scripts/lib/wic/plugins/source/bootimg-pcbios.py | |||
| @@ -0,0 +1,200 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2014, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This implements the 'bootimg-pcbios' source plugin class for 'wic' | ||
| 22 | # | ||
| 23 | # AUTHORS | ||
| 24 | # Tom Zanussi <tom.zanussi (at] linux.intel.com> | ||
| 25 | # | ||
| 26 | |||
| 27 | import os | ||
| 28 | import shutil | ||
| 29 | import re | ||
| 30 | import tempfile | ||
| 31 | |||
| 32 | from wic import kickstart, msger | ||
| 33 | from wic.utils import misc, fs_related, errors, runner, cmdln | ||
| 34 | from wic.conf import configmgr | ||
| 35 | from wic.plugin import pluginmgr | ||
| 36 | import wic.imager.direct as direct | ||
| 37 | from wic.pluginbase import SourcePlugin | ||
| 38 | from wic.utils.oe.misc import * | ||
| 39 | from wic.imager.direct import DirectImageCreator | ||
| 40 | |||
| 41 | class BootimgPcbiosPlugin(SourcePlugin): | ||
| 42 | name = 'bootimg-pcbios' | ||
| 43 | |||
| 44 | @classmethod | ||
| 45 | def do_install_disk(self, disk, disk_name, cr, workdir, oe_builddir, | ||
| 46 | bootimg_dir, kernel_dir, native_sysroot): | ||
| 47 | """ | ||
| 48 | Called after all partitions have been prepared and assembled into a | ||
| 49 | disk image. In this case, we install the MBR. | ||
| 50 | """ | ||
| 51 | mbrfile = "%s/syslinux/" % bootimg_dir | ||
| 52 | if cr._ptable_format == 'msdos': | ||
| 53 | mbrfile += "mbr.bin" | ||
| 54 | |||
| 55 | if not os.path.exists(mbrfile): | ||
| 56 | msger.error("Couldn't find %s. If using the -e option, do you have the right MACHINE set in local.conf? If not, is the bootimg_dir path correct?" % mbrfile) | ||
| 57 | |||
| 58 | full_path = cr._full_path(workdir, disk_name, "direct") | ||
| 59 | msger.debug("Installing MBR on disk %s as %s with size %s bytes" \ | ||
| 60 | % (disk_name, full_path, disk['min_size'])) | ||
| 61 | |||
| 62 | rc = runner.show(['dd', 'if=%s' % mbrfile, | ||
| 63 | 'of=%s' % full_path, 'conv=notrunc']) | ||
| 64 | if rc != 0: | ||
| 65 | raise ImageError("Unable to set MBR to %s" % full_path) | ||
| 66 | |||
| 67 | @classmethod | ||
| 68 | def do_configure_partition(self, part, source_params, cr, cr_workdir, | ||
| 69 | oe_builddir, bootimg_dir, kernel_dir, | ||
| 70 | native_sysroot): | ||
| 71 | """ | ||
| 72 | Called before do_prepare_partition(), creates syslinux config | ||
| 73 | """ | ||
| 74 | hdddir = "%s/hdd/boot" % cr_workdir | ||
| 75 | rm_cmd = "rm -rf " + cr_workdir | ||
| 76 | exec_cmd(rm_cmd) | ||
| 77 | |||
| 78 | install_cmd = "install -d %s" % hdddir | ||
| 79 | exec_cmd(install_cmd) | ||
| 80 | |||
| 81 | splash = os.path.join(cr_workdir, "/hdd/boot/splash.jpg") | ||
| 82 | if os.path.exists(splash): | ||
| 83 | splashline = "menu background splash.jpg" | ||
| 84 | else: | ||
| 85 | splashline = "" | ||
| 86 | |||
| 87 | (rootdev, root_part_uuid) = cr._get_boot_config() | ||
| 88 | options = cr.ks.handler.bootloader.appendLine | ||
| 89 | |||
| 90 | syslinux_conf = "" | ||
| 91 | syslinux_conf += "PROMPT 0\n" | ||
| 92 | timeout = kickstart.get_timeout(cr.ks) | ||
| 93 | if not timeout: | ||
| 94 | timeout = 0 | ||
| 95 | syslinux_conf += "TIMEOUT " + str(timeout) + "\n" | ||
| 96 | syslinux_conf += "\n" | ||
| 97 | syslinux_conf += "ALLOWOPTIONS 1\n" | ||
| 98 | syslinux_conf += "SERIAL 0 115200\n" | ||
| 99 | syslinux_conf += "\n" | ||
| 100 | if splashline: | ||
| 101 | syslinux_conf += "%s\n" % splashline | ||
| 102 | syslinux_conf += "DEFAULT boot\n" | ||
| 103 | syslinux_conf += "LABEL boot\n" | ||
| 104 | |||
| 105 | kernel = "/vmlinuz" | ||
| 106 | syslinux_conf += "KERNEL " + kernel + "\n" | ||
| 107 | |||
| 108 | if cr._ptable_format == 'msdos': | ||
| 109 | rootstr = rootdev | ||
| 110 | else: | ||
| 111 | raise ImageError("Unsupported partition table format found") | ||
| 112 | |||
| 113 | syslinux_conf += "APPEND label=boot root=%s %s\n" % (rootstr, options) | ||
| 114 | |||
| 115 | msger.debug("Writing syslinux config %s/hdd/boot/syslinux.cfg" \ | ||
| 116 | % cr_workdir) | ||
| 117 | cfg = open("%s/hdd/boot/syslinux.cfg" % cr_workdir, "w") | ||
| 118 | cfg.write(syslinux_conf) | ||
| 119 | cfg.close() | ||
| 120 | |||
| 121 | @classmethod | ||
| 122 | def do_prepare_partition(self, part, source_params, cr, cr_workdir, | ||
| 123 | oe_builddir, bootimg_dir, kernel_dir, | ||
| 124 | rootfs_dir, native_sysroot): | ||
| 125 | """ | ||
| 126 | Called to do the actual content population for a partition i.e. it | ||
| 127 | 'prepares' the partition to be incorporated into the image. | ||
| 128 | In this case, prepare content for legacy bios boot partition. | ||
| 129 | """ | ||
| 130 | def _has_syslinux(dir): | ||
| 131 | if dir: | ||
| 132 | syslinux = "%s/syslinux" % dir | ||
| 133 | if os.path.exists(syslinux): | ||
| 134 | return True | ||
| 135 | return False | ||
| 136 | |||
| 137 | if not _has_syslinux(bootimg_dir): | ||
| 138 | bootimg_dir = get_bitbake_var("STAGING_DATADIR") | ||
| 139 | if not bootimg_dir: | ||
| 140 | msger.error("Couldn't find STAGING_DATADIR, exiting\n") | ||
| 141 | if not _has_syslinux(bootimg_dir): | ||
| 142 | msger.error("Please build syslinux first\n") | ||
| 143 | # just so the result notes display it | ||
| 144 | cr.set_bootimg_dir(bootimg_dir) | ||
| 145 | |||
| 146 | staging_kernel_dir = kernel_dir | ||
| 147 | |||
| 148 | hdddir = "%s/hdd/boot" % cr_workdir | ||
| 149 | |||
| 150 | install_cmd = "install -m 0644 %s/bzImage %s/vmlinuz" \ | ||
| 151 | % (staging_kernel_dir, hdddir) | ||
| 152 | exec_cmd(install_cmd) | ||
| 153 | |||
| 154 | install_cmd = "install -m 444 %s/syslinux/ldlinux.sys %s/ldlinux.sys" \ | ||
| 155 | % (bootimg_dir, hdddir) | ||
| 156 | exec_cmd(install_cmd) | ||
| 157 | |||
| 158 | du_cmd = "du -bks %s" % hdddir | ||
| 159 | out = exec_cmd(du_cmd) | ||
| 160 | blocks = int(out.split()[0]) | ||
| 161 | |||
| 162 | extra_blocks = part.get_extra_block_count(blocks) | ||
| 163 | |||
| 164 | if extra_blocks < BOOTDD_EXTRA_SPACE: | ||
| 165 | extra_blocks = BOOTDD_EXTRA_SPACE | ||
| 166 | |||
| 167 | blocks += extra_blocks | ||
| 168 | |||
| 169 | msger.debug("Added %d extra blocks to %s to get to %d total blocks" % \ | ||
| 170 | (extra_blocks, part.mountpoint, blocks)) | ||
| 171 | |||
| 172 | # Ensure total sectors is an integral number of sectors per | ||
| 173 | # track or mcopy will complain. Sectors are 512 bytes, and we | ||
| 174 | # generate images with 32 sectors per track. This calculation is | ||
| 175 | # done in blocks, thus the mod by 16 instead of 32. | ||
| 176 | blocks += (16 - (blocks % 16)) | ||
| 177 | |||
| 178 | # dosfs image, created by mkdosfs | ||
| 179 | bootimg = "%s/boot.img" % cr_workdir | ||
| 180 | |||
| 181 | dosfs_cmd = "mkdosfs -n boot -S 512 -C %s %d" % (bootimg, blocks) | ||
| 182 | exec_native_cmd(dosfs_cmd, native_sysroot) | ||
| 183 | |||
| 184 | mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir) | ||
| 185 | exec_native_cmd(mcopy_cmd, native_sysroot) | ||
| 186 | |||
| 187 | syslinux_cmd = "syslinux %s" % bootimg | ||
| 188 | exec_native_cmd(syslinux_cmd, native_sysroot) | ||
| 189 | |||
| 190 | chmod_cmd = "chmod 644 %s" % bootimg | ||
| 191 | exec_cmd(chmod_cmd) | ||
| 192 | |||
| 193 | du_cmd = "du -Lbms %s" % bootimg | ||
| 194 | out = exec_cmd(du_cmd) | ||
| 195 | bootimg_size = out.split()[0] | ||
| 196 | |||
| 197 | part.set_size(bootimg_size) | ||
| 198 | part.set_source_file(bootimg) | ||
| 199 | |||
| 200 | |||
diff --git a/scripts/lib/wic/plugins/source/rootfs.py b/scripts/lib/wic/plugins/source/rootfs.py new file mode 100644 index 0000000000..a432a18705 --- /dev/null +++ b/scripts/lib/wic/plugins/source/rootfs.py | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2014, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This implements the 'rootfs' source plugin class for 'wic' | ||
| 22 | # | ||
| 23 | # AUTHORS | ||
| 24 | # Tom Zanussi <tom.zanussi (at] linux.intel.com> | ||
| 25 | # Joao Henrique Ferreira de Freitas <joaohf (at] gmail.com> | ||
| 26 | # | ||
| 27 | |||
| 28 | import os | ||
| 29 | import shutil | ||
| 30 | import re | ||
| 31 | import tempfile | ||
| 32 | |||
| 33 | from wic import kickstart, msger | ||
| 34 | from wic.utils import misc, fs_related, errors, runner, cmdln | ||
| 35 | from wic.conf import configmgr | ||
| 36 | from wic.plugin import pluginmgr | ||
| 37 | import wic.imager.direct as direct | ||
| 38 | from wic.pluginbase import SourcePlugin | ||
| 39 | from wic.utils.oe.misc import * | ||
| 40 | from wic.imager.direct import DirectImageCreator | ||
| 41 | |||
| 42 | class RootfsPlugin(SourcePlugin): | ||
| 43 | name = 'rootfs' | ||
| 44 | |||
| 45 | @staticmethod | ||
| 46 | def __get_rootfs_dir(rootfs_dir): | ||
| 47 | if os.path.isdir(rootfs_dir): | ||
| 48 | return rootfs_dir | ||
| 49 | |||
| 50 | bitbake_env_lines = find_bitbake_env_lines(rootfs_dir) | ||
| 51 | if not bitbake_env_lines: | ||
| 52 | msg = "Couldn't get bitbake environment, exiting." | ||
| 53 | msger.error(msg) | ||
| 54 | |||
| 55 | image_rootfs_dir = find_artifact(bitbake_env_lines, "IMAGE_ROOTFS") | ||
| 56 | if not os.path.isdir(image_rootfs_dir): | ||
| 57 | msg = "No valid artifact IMAGE_ROOTFS from image named" | ||
| 58 | msg += " %s has been found at %s, exiting.\n" % \ | ||
| 59 | (rootfs_dir, image_rootfs_dir) | ||
| 60 | msger.error(msg) | ||
| 61 | |||
| 62 | return image_rootfs_dir | ||
| 63 | |||
| 64 | @classmethod | ||
| 65 | def do_prepare_partition(self, part, source_params, cr, cr_workdir, | ||
| 66 | oe_builddir, bootimg_dir, kernel_dir, | ||
| 67 | krootfs_dir, native_sysroot): | ||
| 68 | """ | ||
| 69 | Called to do the actual content population for a partition i.e. it | ||
| 70 | 'prepares' the partition to be incorporated into the image. | ||
| 71 | In this case, prepare content for legacy bios boot partition. | ||
| 72 | """ | ||
| 73 | if part.rootfs is None: | ||
| 74 | if not 'ROOTFS_DIR' in krootfs_dir: | ||
| 75 | msg = "Couldn't find --rootfs-dir, exiting" | ||
| 76 | msger.error(msg) | ||
| 77 | rootfs_dir = krootfs_dir['ROOTFS_DIR'] | ||
| 78 | else: | ||
| 79 | if part.rootfs in krootfs_dir: | ||
| 80 | rootfs_dir = krootfs_dir[part.rootfs] | ||
| 81 | elif part.rootfs: | ||
| 82 | rootfs_dir = part.rootfs | ||
| 83 | else: | ||
| 84 | msg = "Couldn't find --rootfs-dir=%s connection" | ||
| 85 | msg += " or it is not a valid path, exiting" | ||
| 86 | msger.error(msg % part.rootfs) | ||
| 87 | |||
| 88 | real_rootfs_dir = self.__get_rootfs_dir(rootfs_dir) | ||
| 89 | |||
| 90 | part.set_rootfs(real_rootfs_dir) | ||
| 91 | part.prepare_rootfs(cr_workdir, oe_builddir, real_rootfs_dir, native_sysroot) | ||
| 92 | |||
diff --git a/scripts/lib/wic/plugins/source/uboot.py b/scripts/lib/wic/plugins/source/uboot.py new file mode 100644 index 0000000000..57cb3cf8fe --- /dev/null +++ b/scripts/lib/wic/plugins/source/uboot.py | |||
| @@ -0,0 +1,173 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2014, Enea AB. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This implements the 'uboot' source plugin class for 'wic' | ||
| 22 | # | ||
| 23 | # AUTHORS | ||
| 24 | # Adrian Calianu <adrian.calianu (at] enea.com> | ||
| 25 | # | ||
| 26 | |||
| 27 | import os | ||
| 28 | import shutil | ||
| 29 | import re | ||
| 30 | import tempfile | ||
| 31 | |||
| 32 | from mic import kickstart, chroot, msger | ||
| 33 | from mic.utils import misc, fs_related, errors, runner, cmdln | ||
| 34 | from mic.conf import configmgr | ||
| 35 | from mic.plugin import pluginmgr | ||
| 36 | from mic.utils.partitionedfs import PartitionedMount | ||
| 37 | import mic.imager.direct as direct | ||
| 38 | from mic.pluginbase import SourcePlugin | ||
| 39 | from mic.utils.oe.misc import * | ||
| 40 | from mic.imager.direct import DirectImageCreator | ||
| 41 | |||
| 42 | def create_local_rootfs(part, creator, cr_workdir, krootfs_dir, native_sysroot): | ||
| 43 | # In order to have a full control over rootfs we will make a local copy under workdir | ||
| 44 | # and change rootfs_dir to new location. | ||
| 45 | # In this way we can install more than one ROOTFS_DIRs and/or use | ||
| 46 | # an empty rootfs to install packages, so a rootfs could be generated only from pkgs | ||
| 47 | # TBD: create workdir/rootfs ; copy rootfs-> workdir/rootfs; set rootfs=workdir/rootfs | ||
| 48 | |||
| 49 | cr_workdir = os.path.abspath(cr_workdir) | ||
| 50 | new_rootfs_dir = "%s/rootfs_%s" % (cr_workdir, creator.name) | ||
| 51 | |||
| 52 | rootfs_exists = 1 | ||
| 53 | if part.rootfs is None: | ||
| 54 | if not 'ROOTFS_DIR' in krootfs_dir: | ||
| 55 | msg = "Couldn't find --rootfs-dir, exiting, " | ||
| 56 | msger.info(msg) | ||
| 57 | rootfs_exists = 0 | ||
| 58 | rootfs_dir = krootfs_dir['ROOTFS_DIR'] | ||
| 59 | creator.rootfs_dir['ROOTFS_DIR'] = new_rootfs_dir | ||
| 60 | else: | ||
| 61 | if part.rootfs in krootfs_dir: | ||
| 62 | rootfs_dir = krootfs_dir[part.rootfs] | ||
| 63 | creator.rootfs_dir[part.rootfs] = new_rootfs_dir | ||
| 64 | elif os.path.isdir(part.rootfs): | ||
| 65 | rootfs_dir = part.rootfs | ||
| 66 | part.rootfs = new_rootfs_dir | ||
| 67 | else: | ||
| 68 | msg = "Couldn't find --rootfs-dir=%s connection" | ||
| 69 | msg += " or it is not a valid path, exiting" | ||
| 70 | msger.info(msg % part.rootfs) | ||
| 71 | rootfs_exists = 0 | ||
| 72 | creator.rootfs_dir['ROOTFS_DIR'] = new_rootfs_dir | ||
| 73 | |||
| 74 | pseudox = "export PSEUDO_PREFIX=%s/usr;" % native_sysroot | ||
| 75 | pseudox += "export PSEUDO_LOCALSTATEDIR=%s/../pseudo;" % new_rootfs_dir | ||
| 76 | pseudox += "export PSEUDO_PASSWD=%s;" % new_rootfs_dir | ||
| 77 | pseudox += "export PSEUDO_NOSYMLINKEXP=1;" | ||
| 78 | pseudox += "%s/usr/bin/pseudo " % native_sysroot | ||
| 79 | |||
| 80 | mkdir_cmd = "mkdir %s" % (new_rootfs_dir) | ||
| 81 | # rc, out = exec_native_cmd(pseudox + mkdir_cmd, native_sysroot) | ||
| 82 | rc, out = exec_cmd(mkdir_cmd, True) | ||
| 83 | |||
| 84 | if rootfs_exists == 1 and os.path.isdir(rootfs_dir): | ||
| 85 | defpath = os.environ['PATH'] | ||
| 86 | os.environ['PATH'] = native_sysroot + "/usr/bin/" + ":/bin:/usr/bin:" | ||
| 87 | |||
| 88 | rootfs_dir = os.path.abspath(rootfs_dir) | ||
| 89 | |||
| 90 | pseudoc = "export PSEUDO_PREFIX=%s/usr;" % native_sysroot | ||
| 91 | pseudoc += "export PSEUDO_LOCALSTATEDIR=%s/../pseudo;" % rootfs_dir | ||
| 92 | pseudoc += "export PSEUDO_PASSWD=%s;" % rootfs_dir | ||
| 93 | pseudoc += "export PSEUDO_NOSYMLINKEXP=1;" | ||
| 94 | pseudoc += "%s/usr/bin/pseudo " % native_sysroot | ||
| 95 | |||
| 96 | tarc_cmd = "tar cvpf %s/rootfs.tar -C %s ." % (cr_workdir, rootfs_dir) | ||
| 97 | rc, out = exec_native_cmd(pseudoc + tarc_cmd, native_sysroot) | ||
| 98 | |||
| 99 | tarx_cmd = "tar xpvf %s/rootfs.tar -C %s" % (cr_workdir, new_rootfs_dir) | ||
| 100 | rc, out = exec_native_cmd(pseudox + tarx_cmd, native_sysroot) | ||
| 101 | |||
| 102 | rm_cmd = "rm %s/rootfs.tar" % cr_workdir | ||
| 103 | rc, out = exec_cmd(rm_cmd, True) | ||
| 104 | |||
| 105 | os.environ['PATH'] += defpath + ":" + native_sysroot + "/usr/bin/" | ||
| 106 | |||
| 107 | return new_rootfs_dir | ||
| 108 | |||
| 109 | class UBootPlugin(SourcePlugin): | ||
| 110 | name = 'uboot' | ||
| 111 | |||
| 112 | @classmethod | ||
| 113 | def do_install_pkgs(self, part, creator, cr_workdir, oe_builddir, krootfs_dir, | ||
| 114 | bootimg_dir, kernel_dir, native_sysroot): | ||
| 115 | """ | ||
| 116 | Called before all partitions have been prepared and assembled into a | ||
| 117 | disk image. Intall packages based on wic configuration. | ||
| 118 | """ | ||
| 119 | |||
| 120 | # set new rootfs_dir | ||
| 121 | rootfs_dir = create_local_rootfs(part, creator, cr_workdir, krootfs_dir, native_sysroot) | ||
| 122 | |||
| 123 | # wks file parsing | ||
| 124 | packages = kickstart.get_packages(creator.ks) | ||
| 125 | |||
| 126 | # wic.conf file parsing = found under 'creator' | ||
| 127 | local_pkgs_path = creator._local_pkgs_path | ||
| 128 | repourl = creator.repourl | ||
| 129 | pkgmgr = creator.pkgmgr_name | ||
| 130 | |||
| 131 | # install packages | ||
| 132 | if packages and pkgmgr in ["opkg"]: | ||
| 133 | if len(repourl) > 0 : | ||
| 134 | part.install_pkgs_ipk(cr_workdir, oe_builddir, rootfs_dir, native_sysroot, | ||
| 135 | packages, repourl) | ||
| 136 | else: | ||
| 137 | msger.error("No packages repository provided in wic.conf") | ||
| 138 | |||
| 139 | @classmethod | ||
| 140 | def do_prepare_partition(self, part, cr, cr_workdir, oe_builddir, bootimg_dir, | ||
| 141 | kernel_dir, krootfs_dir, native_sysroot): | ||
| 142 | """ | ||
| 143 | Called to do the actual content population for a partition i.e. it | ||
| 144 | 'prepares' the partition to be incorporated into the image. | ||
| 145 | In this case, prepare content for legacy bios boot partition. | ||
| 146 | """ | ||
| 147 | if part.rootfs is None: | ||
| 148 | if not 'ROOTFS_DIR' in krootfs_dir: | ||
| 149 | msg = "Couldn't find --rootfs-dir, exiting" | ||
| 150 | msger.error(msg) | ||
| 151 | rootfs_dir = krootfs_dir['ROOTFS_DIR'] | ||
| 152 | else: | ||
| 153 | if part.rootfs in krootfs_dir: | ||
| 154 | rootfs_dir = krootfs_dir[part.rootfs] | ||
| 155 | elif os.path.isdir(part.rootfs): | ||
| 156 | rootfs_dir = part.rootfs | ||
| 157 | else: | ||
| 158 | msg = "Couldn't find --rootfs-dir=%s connection" | ||
| 159 | msg += " or it is not a valid path, exiting" | ||
| 160 | msger.error(msg % part.rootfs) | ||
| 161 | |||
| 162 | part.set_rootfs(rootfs_dir) | ||
| 163 | |||
| 164 | # change partition label wich will reflect into the final rootfs image name | ||
| 165 | part.label = "%s_%s" % (part.label, cr.name) | ||
| 166 | |||
| 167 | defpath = os.environ['PATH'] | ||
| 168 | os.environ['PATH'] = native_sysroot + "/usr/bin/" + ":/bin:/usr/bin:" | ||
| 169 | |||
| 170 | part.prepare_rootfs(cr_workdir, oe_builddir, rootfs_dir, native_sysroot) | ||
| 171 | part.prepare_for_uboot(cr.target_arch,cr_workdir, oe_builddir, rootfs_dir, native_sysroot) | ||
| 172 | |||
| 173 | os.environ['PATH'] += defpath + ":" + native_sysroot + "/usr/bin/" | ||
diff --git a/scripts/lib/wic/test b/scripts/lib/wic/test new file mode 100644 index 0000000000..9daeafb986 --- /dev/null +++ b/scripts/lib/wic/test | |||
| @@ -0,0 +1 @@ | |||
| test | |||
diff --git a/scripts/lib/wic/utils/__init__.py b/scripts/lib/wic/utils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/scripts/lib/wic/utils/__init__.py | |||
diff --git a/scripts/lib/wic/utils/cmdln.py b/scripts/lib/wic/utils/cmdln.py new file mode 100644 index 0000000000..b099473ee4 --- /dev/null +++ b/scripts/lib/wic/utils/cmdln.py | |||
| @@ -0,0 +1,1586 @@ | |||
| 1 | #!/usr/bin/env python | ||
| 2 | # Copyright (c) 2002-2007 ActiveState Software Inc. | ||
| 3 | # License: MIT (see LICENSE.txt for license details) | ||
| 4 | # Author: Trent Mick | ||
| 5 | # Home: http://trentm.com/projects/cmdln/ | ||
| 6 | |||
| 7 | """An improvement on Python's standard cmd.py module. | ||
| 8 | |||
| 9 | As with cmd.py, this module provides "a simple framework for writing | ||
| 10 | line-oriented command intepreters." This module provides a 'RawCmdln' | ||
| 11 | class that fixes some design flaws in cmd.Cmd, making it more scalable | ||
| 12 | and nicer to use for good 'cvs'- or 'svn'-style command line interfaces | ||
| 13 | or simple shells. And it provides a 'Cmdln' class that add | ||
| 14 | optparse-based option processing. Basically you use it like this: | ||
| 15 | |||
| 16 | import cmdln | ||
| 17 | |||
| 18 | class MySVN(cmdln.Cmdln): | ||
| 19 | name = "svn" | ||
| 20 | |||
| 21 | @cmdln.alias('stat', 'st') | ||
| 22 | @cmdln.option('-v', '--verbose', action='store_true' | ||
| 23 | help='print verbose information') | ||
| 24 | def do_status(self, subcmd, opts, *paths): | ||
| 25 | print "handle 'svn status' command" | ||
| 26 | |||
| 27 | #... | ||
| 28 | |||
| 29 | if __name__ == "__main__": | ||
| 30 | shell = MySVN() | ||
| 31 | retval = shell.main() | ||
| 32 | sys.exit(retval) | ||
| 33 | |||
| 34 | See the README.txt or <http://trentm.com/projects/cmdln/> for more | ||
| 35 | details. | ||
| 36 | """ | ||
| 37 | |||
| 38 | __version_info__ = (1, 1, 2) | ||
| 39 | __version__ = '.'.join(map(str, __version_info__)) | ||
| 40 | |||
| 41 | import os | ||
| 42 | import sys | ||
| 43 | import re | ||
| 44 | import cmd | ||
| 45 | import optparse | ||
| 46 | from pprint import pprint | ||
| 47 | import sys | ||
| 48 | |||
| 49 | |||
| 50 | |||
| 51 | |||
| 52 | #---- globals | ||
| 53 | |||
| 54 | LOOP_ALWAYS, LOOP_NEVER, LOOP_IF_EMPTY = range(3) | ||
| 55 | |||
| 56 | # An unspecified optional argument when None is a meaningful value. | ||
| 57 | _NOT_SPECIFIED = ("Not", "Specified") | ||
| 58 | |||
| 59 | # Pattern to match a TypeError message from a call that | ||
| 60 | # failed because of incorrect number of arguments (see | ||
| 61 | # Python/getargs.c). | ||
| 62 | _INCORRECT_NUM_ARGS_RE = re.compile( | ||
| 63 | r"(takes [\w ]+ )(\d+)( arguments? \()(\d+)( given\))") | ||
| 64 | |||
| 65 | |||
| 66 | |||
| 67 | #---- exceptions | ||
| 68 | |||
| 69 | class CmdlnError(Exception): | ||
| 70 | """A cmdln.py usage error.""" | ||
| 71 | def __init__(self, msg): | ||
| 72 | self.msg = msg | ||
| 73 | def __str__(self): | ||
| 74 | return self.msg | ||
| 75 | |||
| 76 | class CmdlnUserError(Exception): | ||
| 77 | """An error by a user of a cmdln-based tool/shell.""" | ||
| 78 | pass | ||
| 79 | |||
| 80 | |||
| 81 | |||
| 82 | #---- public methods and classes | ||
| 83 | |||
| 84 | def alias(*aliases): | ||
| 85 | """Decorator to add aliases for Cmdln.do_* command handlers. | ||
| 86 | |||
| 87 | Example: | ||
| 88 | class MyShell(cmdln.Cmdln): | ||
| 89 | @cmdln.alias("!", "sh") | ||
| 90 | def do_shell(self, argv): | ||
| 91 | #...implement 'shell' command | ||
| 92 | """ | ||
| 93 | def decorate(f): | ||
| 94 | if not hasattr(f, "aliases"): | ||
| 95 | f.aliases = [] | ||
| 96 | f.aliases += aliases | ||
| 97 | return f | ||
| 98 | return decorate | ||
| 99 | |||
| 100 | |||
| 101 | class RawCmdln(cmd.Cmd): | ||
| 102 | """An improved (on cmd.Cmd) framework for building multi-subcommand | ||
| 103 | scripts (think "svn" & "cvs") and simple shells (think "pdb" and | ||
| 104 | "gdb"). | ||
| 105 | |||
| 106 | A simple example: | ||
| 107 | |||
| 108 | import cmdln | ||
| 109 | |||
| 110 | class MySVN(cmdln.RawCmdln): | ||
| 111 | name = "svn" | ||
| 112 | |||
| 113 | @cmdln.aliases('stat', 'st') | ||
| 114 | def do_status(self, argv): | ||
| 115 | print "handle 'svn status' command" | ||
| 116 | |||
| 117 | if __name__ == "__main__": | ||
| 118 | shell = MySVN() | ||
| 119 | retval = shell.main() | ||
| 120 | sys.exit(retval) | ||
| 121 | |||
| 122 | See <http://trentm.com/projects/cmdln> for more information. | ||
| 123 | """ | ||
| 124 | name = None # if unset, defaults basename(sys.argv[0]) | ||
| 125 | prompt = None # if unset, defaults to self.name+"> " | ||
| 126 | version = None # if set, default top-level options include --version | ||
| 127 | |||
| 128 | # Default messages for some 'help' command error cases. | ||
| 129 | # They are interpolated with one arg: the command. | ||
| 130 | nohelp = "no help on '%s'" | ||
| 131 | unknowncmd = "unknown command: '%s'" | ||
| 132 | |||
| 133 | helpindent = '' # string with which to indent help output | ||
| 134 | |||
| 135 | def __init__(self, completekey='tab', | ||
| 136 | stdin=None, stdout=None, stderr=None): | ||
| 137 | """Cmdln(completekey='tab', stdin=None, stdout=None, stderr=None) | ||
| 138 | |||
| 139 | The optional argument 'completekey' is the readline name of a | ||
| 140 | completion key; it defaults to the Tab key. If completekey is | ||
| 141 | not None and the readline module is available, command completion | ||
| 142 | is done automatically. | ||
| 143 | |||
| 144 | The optional arguments 'stdin', 'stdout' and 'stderr' specify | ||
| 145 | alternate input, output and error output file objects; if not | ||
| 146 | specified, sys.* are used. | ||
| 147 | |||
| 148 | If 'stdout' but not 'stderr' is specified, stdout is used for | ||
| 149 | error output. This is to provide least surprise for users used | ||
| 150 | to only the 'stdin' and 'stdout' options with cmd.Cmd. | ||
| 151 | """ | ||
| 152 | import sys | ||
| 153 | if self.name is None: | ||
| 154 | self.name = os.path.basename(sys.argv[0]) | ||
| 155 | if self.prompt is None: | ||
| 156 | self.prompt = self.name+"> " | ||
| 157 | self._name_str = self._str(self.name) | ||
| 158 | self._prompt_str = self._str(self.prompt) | ||
| 159 | if stdin is not None: | ||
| 160 | self.stdin = stdin | ||
| 161 | else: | ||
| 162 | self.stdin = sys.stdin | ||
| 163 | if stdout is not None: | ||
| 164 | self.stdout = stdout | ||
| 165 | else: | ||
| 166 | self.stdout = sys.stdout | ||
| 167 | if stderr is not None: | ||
| 168 | self.stderr = stderr | ||
| 169 | elif stdout is not None: | ||
| 170 | self.stderr = stdout | ||
| 171 | else: | ||
| 172 | self.stderr = sys.stderr | ||
| 173 | self.cmdqueue = [] | ||
| 174 | self.completekey = completekey | ||
| 175 | self.cmdlooping = False | ||
| 176 | |||
| 177 | def get_optparser(self): | ||
| 178 | """Hook for subclasses to set the option parser for the | ||
| 179 | top-level command/shell. | ||
| 180 | |||
| 181 | This option parser is used retrieved and used by `.main()' to | ||
| 182 | handle top-level options. | ||
| 183 | |||
| 184 | The default implements a single '-h|--help' option. Sub-classes | ||
| 185 | can return None to have no options at the top-level. Typically | ||
| 186 | an instance of CmdlnOptionParser should be returned. | ||
| 187 | """ | ||
| 188 | version = (self.version is not None | ||
| 189 | and "%s %s" % (self._name_str, self.version) | ||
| 190 | or None) | ||
| 191 | return CmdlnOptionParser(self, version=version) | ||
| 192 | |||
| 193 | def postoptparse(self): | ||
| 194 | """Hook method executed just after `.main()' parses top-level | ||
| 195 | options. | ||
| 196 | |||
| 197 | When called `self.options' holds the results of the option parse. | ||
| 198 | """ | ||
| 199 | pass | ||
| 200 | |||
| 201 | def main(self, argv=None, loop=LOOP_NEVER): | ||
| 202 | """A possible mainline handler for a script, like so: | ||
| 203 | |||
| 204 | import cmdln | ||
| 205 | class MyCmd(cmdln.Cmdln): | ||
| 206 | name = "mycmd" | ||
| 207 | ... | ||
| 208 | |||
| 209 | if __name__ == "__main__": | ||
| 210 | MyCmd().main() | ||
| 211 | |||
| 212 | By default this will use sys.argv to issue a single command to | ||
| 213 | 'MyCmd', then exit. The 'loop' argument can be use to control | ||
| 214 | interactive shell behaviour. | ||
| 215 | |||
| 216 | Arguments: | ||
| 217 | "argv" (optional, default sys.argv) is the command to run. | ||
| 218 | It must be a sequence, where the first element is the | ||
| 219 | command name and subsequent elements the args for that | ||
| 220 | command. | ||
| 221 | "loop" (optional, default LOOP_NEVER) is a constant | ||
| 222 | indicating if a command loop should be started (i.e. an | ||
| 223 | interactive shell). Valid values (constants on this module): | ||
| 224 | LOOP_ALWAYS start loop and run "argv", if any | ||
| 225 | LOOP_NEVER run "argv" (or .emptyline()) and exit | ||
| 226 | LOOP_IF_EMPTY run "argv", if given, and exit; | ||
| 227 | otherwise, start loop | ||
| 228 | """ | ||
| 229 | if argv is None: | ||
| 230 | import sys | ||
| 231 | argv = sys.argv | ||
| 232 | else: | ||
| 233 | argv = argv[:] # don't modify caller's list | ||
| 234 | |||
| 235 | self.optparser = self.get_optparser() | ||
| 236 | if self.optparser: # i.e. optparser=None means don't process for opts | ||
| 237 | try: | ||
| 238 | self.options, args = self.optparser.parse_args(argv[1:]) | ||
| 239 | except CmdlnUserError, ex: | ||
| 240 | msg = "%s: %s\nTry '%s help' for info.\n"\ | ||
| 241 | % (self.name, ex, self.name) | ||
| 242 | self.stderr.write(self._str(msg)) | ||
| 243 | self.stderr.flush() | ||
| 244 | return 1 | ||
| 245 | except StopOptionProcessing, ex: | ||
| 246 | return 0 | ||
| 247 | else: | ||
| 248 | self.options, args = None, argv[1:] | ||
| 249 | self.postoptparse() | ||
| 250 | |||
| 251 | if loop == LOOP_ALWAYS: | ||
| 252 | if args: | ||
| 253 | self.cmdqueue.append(args) | ||
| 254 | return self.cmdloop() | ||
| 255 | elif loop == LOOP_NEVER: | ||
| 256 | if args: | ||
| 257 | return self.cmd(args) | ||
| 258 | else: | ||
| 259 | return self.emptyline() | ||
| 260 | elif loop == LOOP_IF_EMPTY: | ||
| 261 | if args: | ||
| 262 | return self.cmd(args) | ||
| 263 | else: | ||
| 264 | return self.cmdloop() | ||
| 265 | |||
| 266 | def cmd(self, argv): | ||
| 267 | """Run one command and exit. | ||
| 268 | |||
| 269 | "argv" is the arglist for the command to run. argv[0] is the | ||
| 270 | command to run. If argv is an empty list then the | ||
| 271 | 'emptyline' handler is run. | ||
| 272 | |||
| 273 | Returns the return value from the command handler. | ||
| 274 | """ | ||
| 275 | assert isinstance(argv, (list, tuple)), \ | ||
| 276 | "'argv' is not a sequence: %r" % argv | ||
| 277 | retval = None | ||
| 278 | try: | ||
| 279 | argv = self.precmd(argv) | ||
| 280 | retval = self.onecmd(argv) | ||
| 281 | self.postcmd(argv) | ||
| 282 | except: | ||
| 283 | if not self.cmdexc(argv): | ||
| 284 | raise | ||
| 285 | retval = 1 | ||
| 286 | return retval | ||
| 287 | |||
| 288 | def _str(self, s): | ||
| 289 | """Safely convert the given str/unicode to a string for printing.""" | ||
| 290 | try: | ||
| 291 | return str(s) | ||
| 292 | except UnicodeError: | ||
| 293 | #XXX What is the proper encoding to use here? 'utf-8' seems | ||
| 294 | # to work better than "getdefaultencoding" (usually | ||
| 295 | # 'ascii'), on OS X at least. | ||
| 296 | #import sys | ||
| 297 | #return s.encode(sys.getdefaultencoding(), "replace") | ||
| 298 | return s.encode("utf-8", "replace") | ||
| 299 | |||
| 300 | def cmdloop(self, intro=None): | ||
| 301 | """Repeatedly issue a prompt, accept input, parse into an argv, and | ||
| 302 | dispatch (via .precmd(), .onecmd() and .postcmd()), passing them | ||
| 303 | the argv. In other words, start a shell. | ||
| 304 | |||
| 305 | "intro" (optional) is a introductory message to print when | ||
| 306 | starting the command loop. This overrides the class | ||
| 307 | "intro" attribute, if any. | ||
| 308 | """ | ||
| 309 | self.cmdlooping = True | ||
| 310 | self.preloop() | ||
| 311 | if self.use_rawinput and self.completekey: | ||
| 312 | try: | ||
| 313 | import readline | ||
| 314 | self.old_completer = readline.get_completer() | ||
| 315 | readline.set_completer(self.complete) | ||
| 316 | readline.parse_and_bind(self.completekey+": complete") | ||
| 317 | except ImportError: | ||
| 318 | pass | ||
| 319 | try: | ||
| 320 | if intro is None: | ||
| 321 | intro = self.intro | ||
| 322 | if intro: | ||
| 323 | intro_str = self._str(intro) | ||
| 324 | self.stdout.write(intro_str+'\n') | ||
| 325 | self.stop = False | ||
| 326 | retval = None | ||
| 327 | while not self.stop: | ||
| 328 | if self.cmdqueue: | ||
| 329 | argv = self.cmdqueue.pop(0) | ||
| 330 | assert isinstance(argv, (list, tuple)), \ | ||
| 331 | "item on 'cmdqueue' is not a sequence: %r" % argv | ||
| 332 | else: | ||
| 333 | if self.use_rawinput: | ||
| 334 | try: | ||
| 335 | line = raw_input(self._prompt_str) | ||
| 336 | except EOFError: | ||
| 337 | line = 'EOF' | ||
| 338 | else: | ||
| 339 | self.stdout.write(self._prompt_str) | ||
| 340 | self.stdout.flush() | ||
| 341 | line = self.stdin.readline() | ||
| 342 | if not len(line): | ||
| 343 | line = 'EOF' | ||
| 344 | else: | ||
| 345 | line = line[:-1] # chop '\n' | ||
| 346 | argv = line2argv(line) | ||
| 347 | try: | ||
| 348 | argv = self.precmd(argv) | ||
| 349 | retval = self.onecmd(argv) | ||
| 350 | self.postcmd(argv) | ||
| 351 | except: | ||
| 352 | if not self.cmdexc(argv): | ||
| 353 | raise | ||
| 354 | retval = 1 | ||
| 355 | self.lastretval = retval | ||
| 356 | self.postloop() | ||
| 357 | finally: | ||
| 358 | if self.use_rawinput and self.completekey: | ||
| 359 | try: | ||
| 360 | import readline | ||
| 361 | readline.set_completer(self.old_completer) | ||
| 362 | except ImportError: | ||
| 363 | pass | ||
| 364 | self.cmdlooping = False | ||
| 365 | return retval | ||
| 366 | |||
| 367 | def precmd(self, argv): | ||
| 368 | """Hook method executed just before the command argv is | ||
| 369 | interpreted, but after the input prompt is generated and issued. | ||
| 370 | |||
| 371 | "argv" is the cmd to run. | ||
| 372 | |||
| 373 | Returns an argv to run (i.e. this method can modify the command | ||
| 374 | to run). | ||
| 375 | """ | ||
| 376 | return argv | ||
| 377 | |||
| 378 | def postcmd(self, argv): | ||
| 379 | """Hook method executed just after a command dispatch is finished. | ||
| 380 | |||
| 381 | "argv" is the command that was run. | ||
| 382 | """ | ||
| 383 | pass | ||
| 384 | |||
| 385 | def cmdexc(self, argv): | ||
| 386 | """Called if an exception is raised in any of precmd(), onecmd(), | ||
| 387 | or postcmd(). If True is returned, the exception is deemed to have | ||
| 388 | been dealt with. Otherwise, the exception is re-raised. | ||
| 389 | |||
| 390 | The default implementation handles CmdlnUserError's, which | ||
| 391 | typically correspond to user error in calling commands (as | ||
| 392 | opposed to programmer error in the design of the script using | ||
| 393 | cmdln.py). | ||
| 394 | """ | ||
| 395 | import sys | ||
| 396 | type, exc, traceback = sys.exc_info() | ||
| 397 | if isinstance(exc, CmdlnUserError): | ||
| 398 | msg = "%s %s: %s\nTry '%s help %s' for info.\n"\ | ||
| 399 | % (self.name, argv[0], exc, self.name, argv[0]) | ||
| 400 | self.stderr.write(self._str(msg)) | ||
| 401 | self.stderr.flush() | ||
| 402 | return True | ||
| 403 | |||
| 404 | def onecmd(self, argv): | ||
| 405 | if not argv: | ||
| 406 | return self.emptyline() | ||
| 407 | self.lastcmd = argv | ||
| 408 | cmdname = self._get_canonical_cmd_name(argv[0]) | ||
| 409 | if cmdname: | ||
| 410 | handler = self._get_cmd_handler(cmdname) | ||
| 411 | if handler: | ||
| 412 | return self._dispatch_cmd(handler, argv) | ||
| 413 | return self.default(argv) | ||
| 414 | |||
| 415 | def _dispatch_cmd(self, handler, argv): | ||
| 416 | return handler(argv) | ||
| 417 | |||
| 418 | def default(self, argv): | ||
| 419 | """Hook called to handle a command for which there is no handler. | ||
| 420 | |||
| 421 | "argv" is the command and arguments to run. | ||
| 422 | |||
| 423 | The default implementation writes and error message to stderr | ||
| 424 | and returns an error exit status. | ||
| 425 | |||
| 426 | Returns a numeric command exit status. | ||
| 427 | """ | ||
| 428 | errmsg = self._str(self.unknowncmd % (argv[0],)) | ||
| 429 | if self.cmdlooping: | ||
| 430 | self.stderr.write(errmsg+"\n") | ||
| 431 | else: | ||
| 432 | self.stderr.write("%s: %s\nTry '%s help' for info.\n" | ||
| 433 | % (self._name_str, errmsg, self._name_str)) | ||
| 434 | self.stderr.flush() | ||
| 435 | return 1 | ||
| 436 | |||
| 437 | def parseline(self, line): | ||
| 438 | # This is used by Cmd.complete (readline completer function) to | ||
| 439 | # massage the current line buffer before completion processing. | ||
| 440 | # We override to drop special '!' handling. | ||
| 441 | line = line.strip() | ||
| 442 | if not line: | ||
| 443 | return None, None, line | ||
| 444 | elif line[0] == '?': | ||
| 445 | line = 'help ' + line[1:] | ||
| 446 | i, n = 0, len(line) | ||
| 447 | while i < n and line[i] in self.identchars: i = i+1 | ||
| 448 | cmd, arg = line[:i], line[i:].strip() | ||
| 449 | return cmd, arg, line | ||
| 450 | |||
| 451 | def helpdefault(self, cmd, known): | ||
| 452 | """Hook called to handle help on a command for which there is no | ||
| 453 | help handler. | ||
| 454 | |||
| 455 | "cmd" is the command name on which help was requested. | ||
| 456 | "known" is a boolean indicating if this command is known | ||
| 457 | (i.e. if there is a handler for it). | ||
| 458 | |||
| 459 | Returns a return code. | ||
| 460 | """ | ||
| 461 | if known: | ||
| 462 | msg = self._str(self.nohelp % (cmd,)) | ||
| 463 | if self.cmdlooping: | ||
| 464 | self.stderr.write(msg + '\n') | ||
| 465 | else: | ||
| 466 | self.stderr.write("%s: %s\n" % (self.name, msg)) | ||
| 467 | else: | ||
| 468 | msg = self.unknowncmd % (cmd,) | ||
| 469 | if self.cmdlooping: | ||
| 470 | self.stderr.write(msg + '\n') | ||
| 471 | else: | ||
| 472 | self.stderr.write("%s: %s\n" | ||
| 473 | "Try '%s help' for info.\n" | ||
| 474 | % (self.name, msg, self.name)) | ||
| 475 | self.stderr.flush() | ||
| 476 | return 1 | ||
| 477 | |||
| 478 | def do_help(self, argv): | ||
| 479 | """${cmd_name}: give detailed help on a specific sub-command | ||
| 480 | |||
| 481 | Usage: | ||
| 482 | ${name} help [COMMAND] | ||
| 483 | """ | ||
| 484 | if len(argv) > 1: # asking for help on a particular command | ||
| 485 | doc = None | ||
| 486 | cmdname = self._get_canonical_cmd_name(argv[1]) or argv[1] | ||
| 487 | if not cmdname: | ||
| 488 | return self.helpdefault(argv[1], False) | ||
| 489 | else: | ||
| 490 | helpfunc = getattr(self, "help_"+cmdname, None) | ||
| 491 | if helpfunc: | ||
| 492 | doc = helpfunc() | ||
| 493 | else: | ||
| 494 | handler = self._get_cmd_handler(cmdname) | ||
| 495 | if handler: | ||
| 496 | doc = handler.__doc__ | ||
| 497 | if doc is None: | ||
| 498 | return self.helpdefault(argv[1], handler != None) | ||
| 499 | else: # bare "help" command | ||
| 500 | doc = self.__class__.__doc__ # try class docstring | ||
| 501 | if doc is None: | ||
| 502 | # Try to provide some reasonable useful default help. | ||
| 503 | if self.cmdlooping: prefix = "" | ||
| 504 | else: prefix = self.name+' ' | ||
| 505 | doc = """Usage: | ||
| 506 | %sCOMMAND [ARGS...] | ||
| 507 | %shelp [COMMAND] | ||
| 508 | |||
| 509 | ${option_list} | ||
| 510 | ${command_list} | ||
| 511 | ${help_list} | ||
| 512 | """ % (prefix, prefix) | ||
| 513 | cmdname = None | ||
| 514 | |||
| 515 | if doc: # *do* have help content, massage and print that | ||
| 516 | doc = self._help_reindent(doc) | ||
| 517 | doc = self._help_preprocess(doc, cmdname) | ||
| 518 | doc = doc.rstrip() + '\n' # trim down trailing space | ||
| 519 | self.stdout.write(self._str(doc)) | ||
| 520 | self.stdout.flush() | ||
| 521 | do_help.aliases = ["?"] | ||
| 522 | |||
| 523 | def _help_reindent(self, help, indent=None): | ||
| 524 | """Hook to re-indent help strings before writing to stdout. | ||
| 525 | |||
| 526 | "help" is the help content to re-indent | ||
| 527 | "indent" is a string with which to indent each line of the | ||
| 528 | help content after normalizing. If unspecified or None | ||
| 529 | then the default is use: the 'self.helpindent' class | ||
| 530 | attribute. By default this is the empty string, i.e. | ||
| 531 | no indentation. | ||
| 532 | |||
| 533 | By default, all common leading whitespace is removed and then | ||
| 534 | the lot is indented by 'self.helpindent'. When calculating the | ||
| 535 | common leading whitespace the first line is ignored -- hence | ||
| 536 | help content for Conan can be written as follows and have the | ||
| 537 | expected indentation: | ||
| 538 | |||
| 539 | def do_crush(self, ...): | ||
| 540 | '''${cmd_name}: crush your enemies, see them driven before you... | ||
| 541 | |||
| 542 | c.f. Conan the Barbarian''' | ||
| 543 | """ | ||
| 544 | if indent is None: | ||
| 545 | indent = self.helpindent | ||
| 546 | lines = help.splitlines(0) | ||
| 547 | _dedentlines(lines, skip_first_line=True) | ||
| 548 | lines = [(indent+line).rstrip() for line in lines] | ||
| 549 | return '\n'.join(lines) | ||
| 550 | |||
| 551 | def _help_preprocess(self, help, cmdname): | ||
| 552 | """Hook to preprocess a help string before writing to stdout. | ||
| 553 | |||
| 554 | "help" is the help string to process. | ||
| 555 | "cmdname" is the canonical sub-command name for which help | ||
| 556 | is being given, or None if the help is not specific to a | ||
| 557 | command. | ||
| 558 | |||
| 559 | By default the following template variables are interpolated in | ||
| 560 | help content. (Note: these are similar to Python 2.4's | ||
| 561 | string.Template interpolation but not quite.) | ||
| 562 | |||
| 563 | ${name} | ||
| 564 | The tool's/shell's name, i.e. 'self.name'. | ||
| 565 | ${option_list} | ||
| 566 | A formatted table of options for this shell/tool. | ||
| 567 | ${command_list} | ||
| 568 | A formatted table of available sub-commands. | ||
| 569 | ${help_list} | ||
| 570 | A formatted table of additional help topics (i.e. 'help_*' | ||
| 571 | methods with no matching 'do_*' method). | ||
| 572 | ${cmd_name} | ||
| 573 | The name (and aliases) for this sub-command formatted as: | ||
| 574 | "NAME (ALIAS1, ALIAS2, ...)". | ||
| 575 | ${cmd_usage} | ||
| 576 | A formatted usage block inferred from the command function | ||
| 577 | signature. | ||
| 578 | ${cmd_option_list} | ||
| 579 | A formatted table of options for this sub-command. (This is | ||
| 580 | only available for commands using the optparse integration, | ||
| 581 | i.e. using @cmdln.option decorators or manually setting the | ||
| 582 | 'optparser' attribute on the 'do_*' method.) | ||
| 583 | |||
| 584 | Returns the processed help. | ||
| 585 | """ | ||
| 586 | preprocessors = { | ||
| 587 | "${name}": self._help_preprocess_name, | ||
| 588 | "${option_list}": self._help_preprocess_option_list, | ||
| 589 | "${command_list}": self._help_preprocess_command_list, | ||
| 590 | "${help_list}": self._help_preprocess_help_list, | ||
| 591 | "${cmd_name}": self._help_preprocess_cmd_name, | ||
| 592 | "${cmd_usage}": self._help_preprocess_cmd_usage, | ||
| 593 | "${cmd_option_list}": self._help_preprocess_cmd_option_list, | ||
| 594 | } | ||
| 595 | |||
| 596 | for marker, preprocessor in preprocessors.items(): | ||
| 597 | if marker in help: | ||
| 598 | help = preprocessor(help, cmdname) | ||
| 599 | return help | ||
| 600 | |||
| 601 | def _help_preprocess_name(self, help, cmdname=None): | ||
| 602 | return help.replace("${name}", self.name) | ||
| 603 | |||
| 604 | def _help_preprocess_option_list(self, help, cmdname=None): | ||
| 605 | marker = "${option_list}" | ||
| 606 | indent, indent_width = _get_indent(marker, help) | ||
| 607 | suffix = _get_trailing_whitespace(marker, help) | ||
| 608 | |||
| 609 | if self.optparser: | ||
| 610 | # Setup formatting options and format. | ||
| 611 | # - Indentation of 4 is better than optparse default of 2. | ||
| 612 | # C.f. Damian Conway's discussion of this in Perl Best | ||
| 613 | # Practices. | ||
| 614 | self.optparser.formatter.indent_increment = 4 | ||
| 615 | self.optparser.formatter.current_indent = indent_width | ||
| 616 | block = self.optparser.format_option_help() + '\n' | ||
| 617 | else: | ||
| 618 | block = "" | ||
| 619 | |||
| 620 | help = help.replace(indent+marker+suffix, block, 1) | ||
| 621 | return help | ||
| 622 | |||
| 623 | |||
| 624 | def _help_preprocess_command_list(self, help, cmdname=None): | ||
| 625 | marker = "${command_list}" | ||
| 626 | indent, indent_width = _get_indent(marker, help) | ||
| 627 | suffix = _get_trailing_whitespace(marker, help) | ||
| 628 | |||
| 629 | # Find any aliases for commands. | ||
| 630 | token2canonical = self._get_canonical_map() | ||
| 631 | aliases = {} | ||
| 632 | for token, cmdname in token2canonical.items(): | ||
| 633 | if token == cmdname: continue | ||
| 634 | aliases.setdefault(cmdname, []).append(token) | ||
| 635 | |||
| 636 | # Get the list of (non-hidden) commands and their | ||
| 637 | # documentation, if any. | ||
| 638 | cmdnames = {} # use a dict to strip duplicates | ||
| 639 | for attr in self.get_names(): | ||
| 640 | if attr.startswith("do_"): | ||
| 641 | cmdnames[attr[3:]] = True | ||
| 642 | cmdnames = cmdnames.keys() | ||
| 643 | cmdnames.sort() | ||
| 644 | linedata = [] | ||
| 645 | for cmdname in cmdnames: | ||
| 646 | if aliases.get(cmdname): | ||
| 647 | a = aliases[cmdname] | ||
| 648 | a.sort() | ||
| 649 | cmdstr = "%s (%s)" % (cmdname, ", ".join(a)) | ||
| 650 | else: | ||
| 651 | cmdstr = cmdname | ||
| 652 | doc = None | ||
| 653 | try: | ||
| 654 | helpfunc = getattr(self, 'help_'+cmdname) | ||
| 655 | except AttributeError: | ||
| 656 | handler = self._get_cmd_handler(cmdname) | ||
| 657 | if handler: | ||
| 658 | doc = handler.__doc__ | ||
| 659 | else: | ||
| 660 | doc = helpfunc() | ||
| 661 | |||
| 662 | # Strip "${cmd_name}: " from the start of a command's doc. Best | ||
| 663 | # practice dictates that command help strings begin with this, but | ||
| 664 | # it isn't at all wanted for the command list. | ||
| 665 | to_strip = "${cmd_name}:" | ||
| 666 | if doc and doc.startswith(to_strip): | ||
| 667 | #log.debug("stripping %r from start of %s's help string", | ||
| 668 | # to_strip, cmdname) | ||
| 669 | doc = doc[len(to_strip):].lstrip() | ||
| 670 | linedata.append( (cmdstr, doc) ) | ||
| 671 | |||
| 672 | if linedata: | ||
| 673 | subindent = indent + ' '*4 | ||
| 674 | lines = _format_linedata(linedata, subindent, indent_width+4) | ||
| 675 | block = indent + "Commands:\n" \ | ||
| 676 | + '\n'.join(lines) + "\n\n" | ||
| 677 | help = help.replace(indent+marker+suffix, block, 1) | ||
| 678 | return help | ||
| 679 | |||
| 680 | def _gen_names_and_attrs(self): | ||
| 681 | # Inheritance says we have to look in class and | ||
| 682 | # base classes; order is not important. | ||
| 683 | names = [] | ||
| 684 | classes = [self.__class__] | ||
| 685 | while classes: | ||
| 686 | aclass = classes.pop(0) | ||
| 687 | if aclass.__bases__: | ||
| 688 | classes = classes + list(aclass.__bases__) | ||
| 689 | for name in dir(aclass): | ||
| 690 | yield (name, getattr(aclass, name)) | ||
| 691 | |||
| 692 | def _help_preprocess_help_list(self, help, cmdname=None): | ||
| 693 | marker = "${help_list}" | ||
| 694 | indent, indent_width = _get_indent(marker, help) | ||
| 695 | suffix = _get_trailing_whitespace(marker, help) | ||
| 696 | |||
| 697 | # Determine the additional help topics, if any. | ||
| 698 | helpnames = {} | ||
| 699 | token2cmdname = self._get_canonical_map() | ||
| 700 | for attrname, attr in self._gen_names_and_attrs(): | ||
| 701 | if not attrname.startswith("help_"): continue | ||
| 702 | helpname = attrname[5:] | ||
| 703 | if helpname not in token2cmdname: | ||
| 704 | helpnames[helpname] = attr | ||
| 705 | |||
| 706 | if helpnames: | ||
| 707 | linedata = [(n, a.__doc__ or "") for n, a in helpnames.items()] | ||
| 708 | linedata.sort() | ||
| 709 | |||
| 710 | subindent = indent + ' '*4 | ||
| 711 | lines = _format_linedata(linedata, subindent, indent_width+4) | ||
| 712 | block = (indent | ||
| 713 | + "Additional help topics (run `%s help TOPIC'):\n" % self.name | ||
| 714 | + '\n'.join(lines) | ||
| 715 | + "\n\n") | ||
| 716 | else: | ||
| 717 | block = '' | ||
| 718 | help = help.replace(indent+marker+suffix, block, 1) | ||
| 719 | return help | ||
| 720 | |||
| 721 | def _help_preprocess_cmd_name(self, help, cmdname=None): | ||
| 722 | marker = "${cmd_name}" | ||
| 723 | handler = self._get_cmd_handler(cmdname) | ||
| 724 | if not handler: | ||
| 725 | raise CmdlnError("cannot preprocess '%s' into help string: " | ||
| 726 | "could not find command handler for %r" | ||
| 727 | % (marker, cmdname)) | ||
| 728 | s = cmdname | ||
| 729 | if hasattr(handler, "aliases"): | ||
| 730 | s += " (%s)" % (", ".join(handler.aliases)) | ||
| 731 | help = help.replace(marker, s) | ||
| 732 | return help | ||
| 733 | |||
| 734 | #TODO: this only makes sense as part of the Cmdln class. | ||
| 735 | # Add hooks to add help preprocessing template vars and put | ||
| 736 | # this one on that class. | ||
| 737 | def _help_preprocess_cmd_usage(self, help, cmdname=None): | ||
| 738 | marker = "${cmd_usage}" | ||
| 739 | handler = self._get_cmd_handler(cmdname) | ||
| 740 | if not handler: | ||
| 741 | raise CmdlnError("cannot preprocess '%s' into help string: " | ||
| 742 | "could not find command handler for %r" | ||
| 743 | % (marker, cmdname)) | ||
| 744 | indent, indent_width = _get_indent(marker, help) | ||
| 745 | suffix = _get_trailing_whitespace(marker, help) | ||
| 746 | |||
| 747 | # Extract the introspection bits we need. | ||
| 748 | func = handler.im_func | ||
| 749 | if func.func_defaults: | ||
| 750 | func_defaults = list(func.func_defaults) | ||
| 751 | else: | ||
| 752 | func_defaults = [] | ||
| 753 | co_argcount = func.func_code.co_argcount | ||
| 754 | co_varnames = func.func_code.co_varnames | ||
| 755 | co_flags = func.func_code.co_flags | ||
| 756 | CO_FLAGS_ARGS = 4 | ||
| 757 | CO_FLAGS_KWARGS = 8 | ||
| 758 | |||
| 759 | # Adjust argcount for possible *args and **kwargs arguments. | ||
| 760 | argcount = co_argcount | ||
| 761 | if co_flags & CO_FLAGS_ARGS: argcount += 1 | ||
| 762 | if co_flags & CO_FLAGS_KWARGS: argcount += 1 | ||
| 763 | |||
| 764 | # Determine the usage string. | ||
| 765 | usage = "%s %s" % (self.name, cmdname) | ||
| 766 | if argcount <= 2: # handler ::= do_FOO(self, argv) | ||
| 767 | usage += " [ARGS...]" | ||
| 768 | elif argcount >= 3: # handler ::= do_FOO(self, subcmd, opts, ...) | ||
| 769 | argnames = list(co_varnames[3:argcount]) | ||
| 770 | tail = "" | ||
| 771 | if co_flags & CO_FLAGS_KWARGS: | ||
| 772 | name = argnames.pop(-1) | ||
| 773 | import warnings | ||
| 774 | # There is no generally accepted mechanism for passing | ||
| 775 | # keyword arguments from the command line. Could | ||
| 776 | # *perhaps* consider: arg=value arg2=value2 ... | ||
| 777 | warnings.warn("argument '**%s' on '%s.%s' command " | ||
| 778 | "handler will never get values" | ||
| 779 | % (name, self.__class__.__name__, | ||
| 780 | func.func_name)) | ||
| 781 | if co_flags & CO_FLAGS_ARGS: | ||
| 782 | name = argnames.pop(-1) | ||
| 783 | tail = "[%s...]" % name.upper() | ||
| 784 | while func_defaults: | ||
| 785 | func_defaults.pop(-1) | ||
| 786 | name = argnames.pop(-1) | ||
| 787 | tail = "[%s%s%s]" % (name.upper(), (tail and ' ' or ''), tail) | ||
| 788 | while argnames: | ||
| 789 | name = argnames.pop(-1) | ||
| 790 | tail = "%s %s" % (name.upper(), tail) | ||
| 791 | usage += ' ' + tail | ||
| 792 | |||
| 793 | block_lines = [ | ||
| 794 | self.helpindent + "Usage:", | ||
| 795 | self.helpindent + ' '*4 + usage | ||
| 796 | ] | ||
| 797 | block = '\n'.join(block_lines) + '\n\n' | ||
| 798 | |||
| 799 | help = help.replace(indent+marker+suffix, block, 1) | ||
| 800 | return help | ||
| 801 | |||
| 802 | #TODO: this only makes sense as part of the Cmdln class. | ||
| 803 | # Add hooks to add help preprocessing template vars and put | ||
| 804 | # this one on that class. | ||
| 805 | def _help_preprocess_cmd_option_list(self, help, cmdname=None): | ||
| 806 | marker = "${cmd_option_list}" | ||
| 807 | handler = self._get_cmd_handler(cmdname) | ||
| 808 | if not handler: | ||
| 809 | raise CmdlnError("cannot preprocess '%s' into help string: " | ||
| 810 | "could not find command handler for %r" | ||
| 811 | % (marker, cmdname)) | ||
| 812 | indent, indent_width = _get_indent(marker, help) | ||
| 813 | suffix = _get_trailing_whitespace(marker, help) | ||
| 814 | if hasattr(handler, "optparser"): | ||
| 815 | # Setup formatting options and format. | ||
| 816 | # - Indentation of 4 is better than optparse default of 2. | ||
| 817 | # C.f. Damian Conway's discussion of this in Perl Best | ||
| 818 | # Practices. | ||
| 819 | handler.optparser.formatter.indent_increment = 4 | ||
| 820 | handler.optparser.formatter.current_indent = indent_width | ||
| 821 | block = handler.optparser.format_option_help() + '\n' | ||
| 822 | else: | ||
| 823 | block = "" | ||
| 824 | |||
| 825 | help = help.replace(indent+marker+suffix, block, 1) | ||
| 826 | return help | ||
| 827 | |||
| 828 | def _get_canonical_cmd_name(self, token): | ||
| 829 | map = self._get_canonical_map() | ||
| 830 | return map.get(token, None) | ||
| 831 | |||
| 832 | def _get_canonical_map(self): | ||
| 833 | """Return a mapping of available command names and aliases to | ||
| 834 | their canonical command name. | ||
| 835 | """ | ||
| 836 | cacheattr = "_token2canonical" | ||
| 837 | if not hasattr(self, cacheattr): | ||
| 838 | # Get the list of commands and their aliases, if any. | ||
| 839 | token2canonical = {} | ||
| 840 | cmd2funcname = {} # use a dict to strip duplicates | ||
| 841 | for attr in self.get_names(): | ||
| 842 | if attr.startswith("do_"): cmdname = attr[3:] | ||
| 843 | elif attr.startswith("_do_"): cmdname = attr[4:] | ||
| 844 | else: | ||
| 845 | continue | ||
| 846 | cmd2funcname[cmdname] = attr | ||
| 847 | token2canonical[cmdname] = cmdname | ||
| 848 | for cmdname, funcname in cmd2funcname.items(): # add aliases | ||
| 849 | func = getattr(self, funcname) | ||
| 850 | aliases = getattr(func, "aliases", []) | ||
| 851 | for alias in aliases: | ||
| 852 | if alias in cmd2funcname: | ||
| 853 | import warnings | ||
| 854 | warnings.warn("'%s' alias for '%s' command conflicts " | ||
| 855 | "with '%s' handler" | ||
| 856 | % (alias, cmdname, cmd2funcname[alias])) | ||
| 857 | continue | ||
| 858 | token2canonical[alias] = cmdname | ||
| 859 | setattr(self, cacheattr, token2canonical) | ||
| 860 | return getattr(self, cacheattr) | ||
| 861 | |||
| 862 | def _get_cmd_handler(self, cmdname): | ||
| 863 | handler = None | ||
| 864 | try: | ||
| 865 | handler = getattr(self, 'do_' + cmdname) | ||
| 866 | except AttributeError: | ||
| 867 | try: | ||
| 868 | # Private command handlers begin with "_do_". | ||
| 869 | handler = getattr(self, '_do_' + cmdname) | ||
| 870 | except AttributeError: | ||
| 871 | pass | ||
| 872 | return handler | ||
| 873 | |||
| 874 | def _do_EOF(self, argv): | ||
| 875 | # Default EOF handler | ||
| 876 | # Note: an actual EOF is redirected to this command. | ||
| 877 | #TODO: separate name for this. Currently it is available from | ||
| 878 | # command-line. Is that okay? | ||
| 879 | self.stdout.write('\n') | ||
| 880 | self.stdout.flush() | ||
| 881 | self.stop = True | ||
| 882 | |||
| 883 | def emptyline(self): | ||
| 884 | # Different from cmd.Cmd: don't repeat the last command for an | ||
| 885 | # emptyline. | ||
| 886 | if self.cmdlooping: | ||
| 887 | pass | ||
| 888 | else: | ||
| 889 | return self.do_help(["help"]) | ||
| 890 | |||
| 891 | |||
| 892 | #---- optparse.py extension to fix (IMO) some deficiencies | ||
| 893 | # | ||
| 894 | # See the class _OptionParserEx docstring for details. | ||
| 895 | # | ||
| 896 | |||
| 897 | class StopOptionProcessing(Exception): | ||
| 898 | """Indicate that option *and argument* processing should stop | ||
| 899 | cleanly. This is not an error condition. It is similar in spirit to | ||
| 900 | StopIteration. This is raised by _OptionParserEx's default "help" | ||
| 901 | and "version" option actions and can be raised by custom option | ||
| 902 | callbacks too. | ||
| 903 | |||
| 904 | Hence the typical CmdlnOptionParser (a subclass of _OptionParserEx) | ||
| 905 | usage is: | ||
| 906 | |||
| 907 | parser = CmdlnOptionParser(mycmd) | ||
| 908 | parser.add_option("-f", "--force", dest="force") | ||
| 909 | ... | ||
| 910 | try: | ||
| 911 | opts, args = parser.parse_args() | ||
| 912 | except StopOptionProcessing: | ||
| 913 | # normal termination, "--help" was probably given | ||
| 914 | sys.exit(0) | ||
| 915 | """ | ||
| 916 | |||
| 917 | class _OptionParserEx(optparse.OptionParser): | ||
| 918 | """An optparse.OptionParser that uses exceptions instead of sys.exit. | ||
| 919 | |||
| 920 | This class is an extension of optparse.OptionParser that differs | ||
| 921 | as follows: | ||
| 922 | - Correct (IMO) the default OptionParser error handling to never | ||
| 923 | sys.exit(). Instead OptParseError exceptions are passed through. | ||
| 924 | - Add the StopOptionProcessing exception (a la StopIteration) to | ||
| 925 | indicate normal termination of option processing. | ||
| 926 | See StopOptionProcessing's docstring for details. | ||
| 927 | |||
| 928 | I'd also like to see the following in the core optparse.py, perhaps | ||
| 929 | as a RawOptionParser which would serve as a base class for the more | ||
| 930 | generally used OptionParser (that works as current): | ||
| 931 | - Remove the implicit addition of the -h|--help and --version | ||
| 932 | options. They can get in the way (e.g. if want '-?' and '-V' for | ||
| 933 | these as well) and it is not hard to do: | ||
| 934 | optparser.add_option("-h", "--help", action="help") | ||
| 935 | optparser.add_option("--version", action="version") | ||
| 936 | These are good practices, just not valid defaults if they can | ||
| 937 | get in the way. | ||
| 938 | """ | ||
| 939 | def error(self, msg): | ||
| 940 | raise optparse.OptParseError(msg) | ||
| 941 | |||
| 942 | def exit(self, status=0, msg=None): | ||
| 943 | if status == 0: | ||
| 944 | raise StopOptionProcessing(msg) | ||
| 945 | else: | ||
| 946 | #TODO: don't lose status info here | ||
| 947 | raise optparse.OptParseError(msg) | ||
| 948 | |||
| 949 | |||
| 950 | |||
| 951 | #---- optparse.py-based option processing support | ||
| 952 | |||
| 953 | class CmdlnOptionParser(_OptionParserEx): | ||
| 954 | """An optparse.OptionParser class more appropriate for top-level | ||
| 955 | Cmdln options. For parsing of sub-command options, see | ||
| 956 | SubCmdOptionParser. | ||
| 957 | |||
| 958 | Changes: | ||
| 959 | - disable_interspersed_args() by default, because a Cmdln instance | ||
| 960 | has sub-commands which may themselves have options. | ||
| 961 | - Redirect print_help() to the Cmdln.do_help() which is better | ||
| 962 | equiped to handle the "help" action. | ||
| 963 | - error() will raise a CmdlnUserError: OptionParse.error() is meant | ||
| 964 | to be called for user errors. Raising a well-known error here can | ||
| 965 | make error handling clearer. | ||
| 966 | - Also see the changes in _OptionParserEx. | ||
| 967 | """ | ||
| 968 | def __init__(self, cmdln, **kwargs): | ||
| 969 | self.cmdln = cmdln | ||
| 970 | kwargs["prog"] = self.cmdln.name | ||
| 971 | _OptionParserEx.__init__(self, **kwargs) | ||
| 972 | self.disable_interspersed_args() | ||
| 973 | |||
| 974 | def print_help(self, file=None): | ||
| 975 | self.cmdln.onecmd(["help"]) | ||
| 976 | |||
| 977 | def error(self, msg): | ||
| 978 | raise CmdlnUserError(msg) | ||
| 979 | |||
| 980 | |||
| 981 | class SubCmdOptionParser(_OptionParserEx): | ||
| 982 | def set_cmdln_info(self, cmdln, subcmd): | ||
| 983 | """Called by Cmdln to pass relevant info about itself needed | ||
| 984 | for print_help(). | ||
| 985 | """ | ||
| 986 | self.cmdln = cmdln | ||
| 987 | self.subcmd = subcmd | ||
| 988 | |||
| 989 | def print_help(self, file=None): | ||
| 990 | self.cmdln.onecmd(["help", self.subcmd]) | ||
| 991 | |||
| 992 | def error(self, msg): | ||
| 993 | raise CmdlnUserError(msg) | ||
| 994 | |||
| 995 | |||
| 996 | def option(*args, **kwargs): | ||
| 997 | """Decorator to add an option to the optparser argument of a Cmdln | ||
| 998 | subcommand. | ||
| 999 | |||
| 1000 | Example: | ||
| 1001 | class MyShell(cmdln.Cmdln): | ||
| 1002 | @cmdln.option("-f", "--force", help="force removal") | ||
| 1003 | def do_remove(self, subcmd, opts, *args): | ||
| 1004 | #... | ||
| 1005 | """ | ||
| 1006 | #XXX Is there a possible optimization for many options to not have a | ||
| 1007 | # large stack depth here? | ||
| 1008 | def decorate(f): | ||
| 1009 | if not hasattr(f, "optparser"): | ||
| 1010 | f.optparser = SubCmdOptionParser() | ||
| 1011 | f.optparser.add_option(*args, **kwargs) | ||
| 1012 | return f | ||
| 1013 | return decorate | ||
| 1014 | |||
| 1015 | |||
| 1016 | class Cmdln(RawCmdln): | ||
| 1017 | """An improved (on cmd.Cmd) framework for building multi-subcommand | ||
| 1018 | scripts (think "svn" & "cvs") and simple shells (think "pdb" and | ||
| 1019 | "gdb"). | ||
| 1020 | |||
| 1021 | A simple example: | ||
| 1022 | |||
| 1023 | import cmdln | ||
| 1024 | |||
| 1025 | class MySVN(cmdln.Cmdln): | ||
| 1026 | name = "svn" | ||
| 1027 | |||
| 1028 | @cmdln.aliases('stat', 'st') | ||
| 1029 | @cmdln.option('-v', '--verbose', action='store_true' | ||
| 1030 | help='print verbose information') | ||
| 1031 | def do_status(self, subcmd, opts, *paths): | ||
| 1032 | print "handle 'svn status' command" | ||
| 1033 | |||
| 1034 | #... | ||
| 1035 | |||
| 1036 | if __name__ == "__main__": | ||
| 1037 | shell = MySVN() | ||
| 1038 | retval = shell.main() | ||
| 1039 | sys.exit(retval) | ||
| 1040 | |||
| 1041 | 'Cmdln' extends 'RawCmdln' by providing optparse option processing | ||
| 1042 | integration. See this class' _dispatch_cmd() docstring and | ||
| 1043 | <http://trentm.com/projects/cmdln> for more information. | ||
| 1044 | """ | ||
| 1045 | def _dispatch_cmd(self, handler, argv): | ||
| 1046 | """Introspect sub-command handler signature to determine how to | ||
| 1047 | dispatch the command. The raw handler provided by the base | ||
| 1048 | 'RawCmdln' class is still supported: | ||
| 1049 | |||
| 1050 | def do_foo(self, argv): | ||
| 1051 | # 'argv' is the vector of command line args, argv[0] is | ||
| 1052 | # the command name itself (i.e. "foo" or an alias) | ||
| 1053 | pass | ||
| 1054 | |||
| 1055 | In addition, if the handler has more than 2 arguments option | ||
| 1056 | processing is automatically done (using optparse): | ||
| 1057 | |||
| 1058 | @cmdln.option('-v', '--verbose', action='store_true') | ||
| 1059 | def do_bar(self, subcmd, opts, *args): | ||
| 1060 | # subcmd = <"bar" or an alias> | ||
| 1061 | # opts = <an optparse.Values instance> | ||
| 1062 | if opts.verbose: | ||
| 1063 | print "lots of debugging output..." | ||
| 1064 | # args = <tuple of arguments> | ||
| 1065 | for arg in args: | ||
| 1066 | bar(arg) | ||
| 1067 | |||
| 1068 | TODO: explain that "*args" can be other signatures as well. | ||
| 1069 | |||
| 1070 | The `cmdln.option` decorator corresponds to an `add_option()` | ||
| 1071 | method call on an `optparse.OptionParser` instance. | ||
| 1072 | |||
| 1073 | You can declare a specific number of arguments: | ||
| 1074 | |||
| 1075 | @cmdln.option('-v', '--verbose', action='store_true') | ||
| 1076 | def do_bar2(self, subcmd, opts, bar_one, bar_two): | ||
| 1077 | #... | ||
| 1078 | |||
| 1079 | and an appropriate error message will be raised/printed if the | ||
| 1080 | command is called with a different number of args. | ||
| 1081 | """ | ||
| 1082 | co_argcount = handler.im_func.func_code.co_argcount | ||
| 1083 | if co_argcount == 2: # handler ::= do_foo(self, argv) | ||
| 1084 | return handler(argv) | ||
| 1085 | elif co_argcount >= 3: # handler ::= do_foo(self, subcmd, opts, ...) | ||
| 1086 | try: | ||
| 1087 | optparser = handler.optparser | ||
| 1088 | except AttributeError: | ||
| 1089 | optparser = handler.im_func.optparser = SubCmdOptionParser() | ||
| 1090 | assert isinstance(optparser, SubCmdOptionParser) | ||
| 1091 | optparser.set_cmdln_info(self, argv[0]) | ||
| 1092 | try: | ||
| 1093 | opts, args = optparser.parse_args(argv[1:]) | ||
| 1094 | except StopOptionProcessing: | ||
| 1095 | #TODO: this doesn't really fly for a replacement of | ||
| 1096 | # optparse.py behaviour, does it? | ||
| 1097 | return 0 # Normal command termination | ||
| 1098 | |||
| 1099 | try: | ||
| 1100 | return handler(argv[0], opts, *args) | ||
| 1101 | except TypeError, ex: | ||
| 1102 | # Some TypeError's are user errors: | ||
| 1103 | # do_foo() takes at least 4 arguments (3 given) | ||
| 1104 | # do_foo() takes at most 5 arguments (6 given) | ||
| 1105 | # do_foo() takes exactly 5 arguments (6 given) | ||
| 1106 | # Raise CmdlnUserError for these with a suitably | ||
| 1107 | # massaged error message. | ||
| 1108 | import sys | ||
| 1109 | tb = sys.exc_info()[2] # the traceback object | ||
| 1110 | if tb.tb_next is not None: | ||
| 1111 | # If the traceback is more than one level deep, then the | ||
| 1112 | # TypeError do *not* happen on the "handler(...)" call | ||
| 1113 | # above. In that we don't want to handle it specially | ||
| 1114 | # here: it would falsely mask deeper code errors. | ||
| 1115 | raise | ||
| 1116 | msg = ex.args[0] | ||
| 1117 | match = _INCORRECT_NUM_ARGS_RE.search(msg) | ||
| 1118 | if match: | ||
| 1119 | msg = list(match.groups()) | ||
| 1120 | msg[1] = int(msg[1]) - 3 | ||
| 1121 | if msg[1] == 1: | ||
| 1122 | msg[2] = msg[2].replace("arguments", "argument") | ||
| 1123 | msg[3] = int(msg[3]) - 3 | ||
| 1124 | msg = ''.join(map(str, msg)) | ||
| 1125 | raise CmdlnUserError(msg) | ||
| 1126 | else: | ||
| 1127 | raise | ||
| 1128 | else: | ||
| 1129 | raise CmdlnError("incorrect argcount for %s(): takes %d, must " | ||
| 1130 | "take 2 for 'argv' signature or 3+ for 'opts' " | ||
| 1131 | "signature" % (handler.__name__, co_argcount)) | ||
| 1132 | |||
| 1133 | |||
| 1134 | |||
| 1135 | #---- internal support functions | ||
| 1136 | |||
| 1137 | def _format_linedata(linedata, indent, indent_width): | ||
| 1138 | """Format specific linedata into a pleasant layout. | ||
| 1139 | |||
| 1140 | "linedata" is a list of 2-tuples of the form: | ||
| 1141 | (<item-display-string>, <item-docstring>) | ||
| 1142 | "indent" is a string to use for one level of indentation | ||
| 1143 | "indent_width" is a number of columns by which the | ||
| 1144 | formatted data will be indented when printed. | ||
| 1145 | |||
| 1146 | The <item-display-string> column is held to 15 columns. | ||
| 1147 | """ | ||
| 1148 | lines = [] | ||
| 1149 | WIDTH = 78 - indent_width | ||
| 1150 | SPACING = 2 | ||
| 1151 | NAME_WIDTH_LOWER_BOUND = 13 | ||
| 1152 | NAME_WIDTH_UPPER_BOUND = 16 | ||
| 1153 | NAME_WIDTH = max([len(s) for s,d in linedata]) | ||
| 1154 | if NAME_WIDTH < NAME_WIDTH_LOWER_BOUND: | ||
| 1155 | NAME_WIDTH = NAME_WIDTH_LOWER_BOUND | ||
| 1156 | else: | ||
| 1157 | NAME_WIDTH = NAME_WIDTH_UPPER_BOUND | ||
| 1158 | |||
| 1159 | DOC_WIDTH = WIDTH - NAME_WIDTH - SPACING | ||
| 1160 | for namestr, doc in linedata: | ||
| 1161 | line = indent + namestr | ||
| 1162 | if len(namestr) <= NAME_WIDTH: | ||
| 1163 | line += ' ' * (NAME_WIDTH + SPACING - len(namestr)) | ||
| 1164 | else: | ||
| 1165 | lines.append(line) | ||
| 1166 | line = indent + ' ' * (NAME_WIDTH + SPACING) | ||
| 1167 | line += _summarize_doc(doc, DOC_WIDTH) | ||
| 1168 | lines.append(line.rstrip()) | ||
| 1169 | return lines | ||
| 1170 | |||
| 1171 | def _summarize_doc(doc, length=60): | ||
| 1172 | r"""Parse out a short one line summary from the given doclines. | ||
| 1173 | |||
| 1174 | "doc" is the doc string to summarize. | ||
| 1175 | "length" is the max length for the summary | ||
| 1176 | |||
| 1177 | >>> _summarize_doc("this function does this") | ||
| 1178 | 'this function does this' | ||
| 1179 | >>> _summarize_doc("this function does this", 10) | ||
| 1180 | 'this fu...' | ||
| 1181 | >>> _summarize_doc("this function does this\nand that") | ||
| 1182 | 'this function does this and that' | ||
| 1183 | >>> _summarize_doc("this function does this\n\nand that") | ||
| 1184 | 'this function does this' | ||
| 1185 | """ | ||
| 1186 | import re | ||
| 1187 | if doc is None: | ||
| 1188 | return "" | ||
| 1189 | assert length > 3, "length <= 3 is absurdly short for a doc summary" | ||
| 1190 | doclines = doc.strip().splitlines(0) | ||
| 1191 | if not doclines: | ||
| 1192 | return "" | ||
| 1193 | |||
| 1194 | summlines = [] | ||
| 1195 | for i, line in enumerate(doclines): | ||
| 1196 | stripped = line.strip() | ||
| 1197 | if not stripped: | ||
| 1198 | break | ||
| 1199 | summlines.append(stripped) | ||
| 1200 | if len(''.join(summlines)) >= length: | ||
| 1201 | break | ||
| 1202 | |||
| 1203 | summary = ' '.join(summlines) | ||
| 1204 | if len(summary) > length: | ||
| 1205 | summary = summary[:length-3] + "..." | ||
| 1206 | return summary | ||
| 1207 | |||
| 1208 | |||
| 1209 | def line2argv(line): | ||
| 1210 | r"""Parse the given line into an argument vector. | ||
| 1211 | |||
| 1212 | "line" is the line of input to parse. | ||
| 1213 | |||
| 1214 | This may get niggly when dealing with quoting and escaping. The | ||
| 1215 | current state of this parsing may not be completely thorough/correct | ||
| 1216 | in this respect. | ||
| 1217 | |||
| 1218 | >>> from cmdln import line2argv | ||
| 1219 | >>> line2argv("foo") | ||
| 1220 | ['foo'] | ||
| 1221 | >>> line2argv("foo bar") | ||
| 1222 | ['foo', 'bar'] | ||
| 1223 | >>> line2argv("foo bar ") | ||
| 1224 | ['foo', 'bar'] | ||
| 1225 | >>> line2argv(" foo bar") | ||
| 1226 | ['foo', 'bar'] | ||
| 1227 | |||
| 1228 | Quote handling: | ||
| 1229 | |||
| 1230 | >>> line2argv("'foo bar'") | ||
| 1231 | ['foo bar'] | ||
| 1232 | >>> line2argv('"foo bar"') | ||
| 1233 | ['foo bar'] | ||
| 1234 | >>> line2argv(r'"foo\"bar"') | ||
| 1235 | ['foo"bar'] | ||
| 1236 | >>> line2argv("'foo bar' spam") | ||
| 1237 | ['foo bar', 'spam'] | ||
| 1238 | >>> line2argv("'foo 'bar spam") | ||
| 1239 | ['foo bar', 'spam'] | ||
| 1240 | |||
| 1241 | >>> line2argv('some\tsimple\ttests') | ||
| 1242 | ['some', 'simple', 'tests'] | ||
| 1243 | >>> line2argv('a "more complex" test') | ||
| 1244 | ['a', 'more complex', 'test'] | ||
| 1245 | >>> line2argv('a more="complex test of " quotes') | ||
| 1246 | ['a', 'more=complex test of ', 'quotes'] | ||
| 1247 | >>> line2argv('a more" complex test of " quotes') | ||
| 1248 | ['a', 'more complex test of ', 'quotes'] | ||
| 1249 | >>> line2argv('an "embedded \\"quote\\""') | ||
| 1250 | ['an', 'embedded "quote"'] | ||
| 1251 | |||
| 1252 | # Komodo bug 48027 | ||
| 1253 | >>> line2argv('foo bar C:\\') | ||
| 1254 | ['foo', 'bar', 'C:\\'] | ||
| 1255 | |||
| 1256 | # Komodo change 127581 | ||
| 1257 | >>> line2argv(r'"\test\slash" "foo bar" "foo\"bar"') | ||
| 1258 | ['\\test\\slash', 'foo bar', 'foo"bar'] | ||
| 1259 | |||
| 1260 | # Komodo change 127629 | ||
| 1261 | >>> if sys.platform == "win32": | ||
| 1262 | ... line2argv(r'\foo\bar') == ['\\foo\\bar'] | ||
| 1263 | ... line2argv(r'\\foo\\bar') == ['\\\\foo\\\\bar'] | ||
| 1264 | ... line2argv('"foo') == ['foo'] | ||
| 1265 | ... else: | ||
| 1266 | ... line2argv(r'\foo\bar') == ['foobar'] | ||
| 1267 | ... line2argv(r'\\foo\\bar') == ['\\foo\\bar'] | ||
| 1268 | ... try: | ||
| 1269 | ... line2argv('"foo') | ||
| 1270 | ... except ValueError, ex: | ||
| 1271 | ... "not terminated" in str(ex) | ||
| 1272 | True | ||
| 1273 | True | ||
| 1274 | True | ||
| 1275 | """ | ||
| 1276 | import string | ||
| 1277 | line = line.strip() | ||
| 1278 | argv = [] | ||
| 1279 | state = "default" | ||
| 1280 | arg = None # the current argument being parsed | ||
| 1281 | i = -1 | ||
| 1282 | while 1: | ||
| 1283 | i += 1 | ||
| 1284 | if i >= len(line): break | ||
| 1285 | ch = line[i] | ||
| 1286 | |||
| 1287 | if ch == "\\" and i+1 < len(line): | ||
| 1288 | # escaped char always added to arg, regardless of state | ||
| 1289 | if arg is None: arg = "" | ||
| 1290 | if (sys.platform == "win32" | ||
| 1291 | or state in ("double-quoted", "single-quoted") | ||
| 1292 | ) and line[i+1] not in tuple('"\''): | ||
| 1293 | arg += ch | ||
| 1294 | i += 1 | ||
| 1295 | arg += line[i] | ||
| 1296 | continue | ||
| 1297 | |||
| 1298 | if state == "single-quoted": | ||
| 1299 | if ch == "'": | ||
| 1300 | state = "default" | ||
| 1301 | else: | ||
| 1302 | arg += ch | ||
| 1303 | elif state == "double-quoted": | ||
| 1304 | if ch == '"': | ||
| 1305 | state = "default" | ||
| 1306 | else: | ||
| 1307 | arg += ch | ||
| 1308 | elif state == "default": | ||
| 1309 | if ch == '"': | ||
| 1310 | if arg is None: arg = "" | ||
| 1311 | state = "double-quoted" | ||
| 1312 | elif ch == "'": | ||
| 1313 | if arg is None: arg = "" | ||
| 1314 | state = "single-quoted" | ||
| 1315 | elif ch in string.whitespace: | ||
| 1316 | if arg is not None: | ||
| 1317 | argv.append(arg) | ||
| 1318 | arg = None | ||
| 1319 | else: | ||
| 1320 | if arg is None: arg = "" | ||
| 1321 | arg += ch | ||
| 1322 | if arg is not None: | ||
| 1323 | argv.append(arg) | ||
| 1324 | if not sys.platform == "win32" and state != "default": | ||
| 1325 | raise ValueError("command line is not terminated: unfinished %s " | ||
| 1326 | "segment" % state) | ||
| 1327 | return argv | ||
| 1328 | |||
| 1329 | |||
| 1330 | def argv2line(argv): | ||
| 1331 | r"""Put together the given argument vector into a command line. | ||
| 1332 | |||
| 1333 | "argv" is the argument vector to process. | ||
| 1334 | |||
| 1335 | >>> from cmdln import argv2line | ||
| 1336 | >>> argv2line(['foo']) | ||
| 1337 | 'foo' | ||
| 1338 | >>> argv2line(['foo', 'bar']) | ||
| 1339 | 'foo bar' | ||
| 1340 | >>> argv2line(['foo', 'bar baz']) | ||
| 1341 | 'foo "bar baz"' | ||
| 1342 | >>> argv2line(['foo"bar']) | ||
| 1343 | 'foo"bar' | ||
| 1344 | >>> print argv2line(['foo" bar']) | ||
| 1345 | 'foo" bar' | ||
| 1346 | >>> print argv2line(["foo' bar"]) | ||
| 1347 | "foo' bar" | ||
| 1348 | >>> argv2line(["foo'bar"]) | ||
| 1349 | "foo'bar" | ||
| 1350 | """ | ||
| 1351 | escapedArgs = [] | ||
| 1352 | for arg in argv: | ||
| 1353 | if ' ' in arg and '"' not in arg: | ||
| 1354 | arg = '"'+arg+'"' | ||
| 1355 | elif ' ' in arg and "'" not in arg: | ||
| 1356 | arg = "'"+arg+"'" | ||
| 1357 | elif ' ' in arg: | ||
| 1358 | arg = arg.replace('"', r'\"') | ||
| 1359 | arg = '"'+arg+'"' | ||
| 1360 | escapedArgs.append(arg) | ||
| 1361 | return ' '.join(escapedArgs) | ||
| 1362 | |||
| 1363 | |||
| 1364 | # Recipe: dedent (0.1) in /Users/trentm/tm/recipes/cookbook | ||
| 1365 | def _dedentlines(lines, tabsize=8, skip_first_line=False): | ||
| 1366 | """_dedentlines(lines, tabsize=8, skip_first_line=False) -> dedented lines | ||
| 1367 | |||
| 1368 | "lines" is a list of lines to dedent. | ||
| 1369 | "tabsize" is the tab width to use for indent width calculations. | ||
| 1370 | "skip_first_line" is a boolean indicating if the first line should | ||
| 1371 | be skipped for calculating the indent width and for dedenting. | ||
| 1372 | This is sometimes useful for docstrings and similar. | ||
| 1373 | |||
| 1374 | Same as dedent() except operates on a sequence of lines. Note: the | ||
| 1375 | lines list is modified **in-place**. | ||
| 1376 | """ | ||
| 1377 | DEBUG = False | ||
| 1378 | if DEBUG: | ||
| 1379 | print "dedent: dedent(..., tabsize=%d, skip_first_line=%r)"\ | ||
| 1380 | % (tabsize, skip_first_line) | ||
| 1381 | indents = [] | ||
| 1382 | margin = None | ||
| 1383 | for i, line in enumerate(lines): | ||
| 1384 | if i == 0 and skip_first_line: continue | ||
| 1385 | indent = 0 | ||
| 1386 | for ch in line: | ||
| 1387 | if ch == ' ': | ||
| 1388 | indent += 1 | ||
| 1389 | elif ch == '\t': | ||
| 1390 | indent += tabsize - (indent % tabsize) | ||
| 1391 | elif ch in '\r\n': | ||
| 1392 | continue # skip all-whitespace lines | ||
| 1393 | else: | ||
| 1394 | break | ||
| 1395 | else: | ||
| 1396 | continue # skip all-whitespace lines | ||
| 1397 | if DEBUG: print "dedent: indent=%d: %r" % (indent, line) | ||
| 1398 | if margin is None: | ||
| 1399 | margin = indent | ||
| 1400 | else: | ||
| 1401 | margin = min(margin, indent) | ||
| 1402 | if DEBUG: print "dedent: margin=%r" % margin | ||
| 1403 | |||
| 1404 | if margin is not None and margin > 0: | ||
| 1405 | for i, line in enumerate(lines): | ||
| 1406 | if i == 0 and skip_first_line: continue | ||
| 1407 | removed = 0 | ||
| 1408 | for j, ch in enumerate(line): | ||
| 1409 | if ch == ' ': | ||
| 1410 | removed += 1 | ||
| 1411 | elif ch == '\t': | ||
| 1412 | removed += tabsize - (removed % tabsize) | ||
| 1413 | elif ch in '\r\n': | ||
| 1414 | if DEBUG: print "dedent: %r: EOL -> strip up to EOL" % line | ||
| 1415 | lines[i] = lines[i][j:] | ||
| 1416 | break | ||
| 1417 | else: | ||
| 1418 | raise ValueError("unexpected non-whitespace char %r in " | ||
| 1419 | "line %r while removing %d-space margin" | ||
| 1420 | % (ch, line, margin)) | ||
| 1421 | if DEBUG: | ||
| 1422 | print "dedent: %r: %r -> removed %d/%d"\ | ||
| 1423 | % (line, ch, removed, margin) | ||
| 1424 | if removed == margin: | ||
| 1425 | lines[i] = lines[i][j+1:] | ||
| 1426 | break | ||
| 1427 | elif removed > margin: | ||
| 1428 | lines[i] = ' '*(removed-margin) + lines[i][j+1:] | ||
| 1429 | break | ||
| 1430 | return lines | ||
| 1431 | |||
| 1432 | def _dedent(text, tabsize=8, skip_first_line=False): | ||
| 1433 | """_dedent(text, tabsize=8, skip_first_line=False) -> dedented text | ||
| 1434 | |||
| 1435 | "text" is the text to dedent. | ||
| 1436 | "tabsize" is the tab width to use for indent width calculations. | ||
| 1437 | "skip_first_line" is a boolean indicating if the first line should | ||
| 1438 | be skipped for calculating the indent width and for dedenting. | ||
| 1439 | This is sometimes useful for docstrings and similar. | ||
| 1440 | |||
| 1441 | textwrap.dedent(s), but don't expand tabs to spaces | ||
| 1442 | """ | ||
| 1443 | lines = text.splitlines(1) | ||
| 1444 | _dedentlines(lines, tabsize=tabsize, skip_first_line=skip_first_line) | ||
| 1445 | return ''.join(lines) | ||
| 1446 | |||
| 1447 | |||
| 1448 | def _get_indent(marker, s, tab_width=8): | ||
| 1449 | """_get_indent(marker, s, tab_width=8) -> | ||
| 1450 | (<indentation-of-'marker'>, <indentation-width>)""" | ||
| 1451 | # Figure out how much the marker is indented. | ||
| 1452 | INDENT_CHARS = tuple(' \t') | ||
| 1453 | start = s.index(marker) | ||
| 1454 | i = start | ||
| 1455 | while i > 0: | ||
| 1456 | if s[i-1] not in INDENT_CHARS: | ||
| 1457 | break | ||
| 1458 | i -= 1 | ||
| 1459 | indent = s[i:start] | ||
| 1460 | indent_width = 0 | ||
| 1461 | for ch in indent: | ||
| 1462 | if ch == ' ': | ||
| 1463 | indent_width += 1 | ||
| 1464 | elif ch == '\t': | ||
| 1465 | indent_width += tab_width - (indent_width % tab_width) | ||
| 1466 | return indent, indent_width | ||
| 1467 | |||
| 1468 | def _get_trailing_whitespace(marker, s): | ||
| 1469 | """Return the whitespace content trailing the given 'marker' in string 's', | ||
| 1470 | up to and including a newline. | ||
| 1471 | """ | ||
| 1472 | suffix = '' | ||
| 1473 | start = s.index(marker) + len(marker) | ||
| 1474 | i = start | ||
| 1475 | while i < len(s): | ||
| 1476 | if s[i] in ' \t': | ||
| 1477 | suffix += s[i] | ||
| 1478 | elif s[i] in '\r\n': | ||
| 1479 | suffix += s[i] | ||
| 1480 | if s[i] == '\r' and i+1 < len(s) and s[i+1] == '\n': | ||
| 1481 | suffix += s[i+1] | ||
| 1482 | break | ||
| 1483 | else: | ||
| 1484 | break | ||
| 1485 | i += 1 | ||
| 1486 | return suffix | ||
| 1487 | |||
| 1488 | |||
| 1489 | |||
| 1490 | #---- bash completion support | ||
| 1491 | # Note: This is still experimental. I expect to change this | ||
| 1492 | # significantly. | ||
| 1493 | # | ||
| 1494 | # To get Bash completion for a cmdln.Cmdln class, run the following | ||
| 1495 | # bash command: | ||
| 1496 | # $ complete -C 'python -m cmdln /path/to/script.py CmdlnClass' cmdname | ||
| 1497 | # For example: | ||
| 1498 | # $ complete -C 'python -m cmdln ~/bin/svn.py SVN' svn | ||
| 1499 | # | ||
| 1500 | #TODO: Simplify the above so don't have to given path to script (try to | ||
| 1501 | # find it on PATH, if possible). Could also make class name | ||
| 1502 | # optional if there is only one in the module (common case). | ||
| 1503 | |||
| 1504 | if __name__ == "__main__" and len(sys.argv) == 6: | ||
| 1505 | def _log(s): | ||
| 1506 | return # no-op, comment out for debugging | ||
| 1507 | from os.path import expanduser | ||
| 1508 | fout = open(expanduser("~/tmp/bashcpln.log"), 'a') | ||
| 1509 | fout.write(str(s) + '\n') | ||
| 1510 | fout.close() | ||
| 1511 | |||
| 1512 | # Recipe: module_from_path (1.0.1+) | ||
| 1513 | def _module_from_path(path): | ||
| 1514 | import imp, os, sys | ||
| 1515 | path = os.path.expanduser(path) | ||
| 1516 | dir = os.path.dirname(path) or os.curdir | ||
| 1517 | name = os.path.splitext(os.path.basename(path))[0] | ||
| 1518 | sys.path.insert(0, dir) | ||
| 1519 | try: | ||
| 1520 | iinfo = imp.find_module(name, [dir]) | ||
| 1521 | return imp.load_module(name, *iinfo) | ||
| 1522 | finally: | ||
| 1523 | sys.path.remove(dir) | ||
| 1524 | |||
| 1525 | def _get_bash_cplns(script_path, class_name, cmd_name, | ||
| 1526 | token, preceding_token): | ||
| 1527 | _log('--') | ||
| 1528 | _log('get_cplns(%r, %r, %r, %r, %r)' | ||
| 1529 | % (script_path, class_name, cmd_name, token, preceding_token)) | ||
| 1530 | comp_line = os.environ["COMP_LINE"] | ||
| 1531 | comp_point = int(os.environ["COMP_POINT"]) | ||
| 1532 | _log("COMP_LINE: %r" % comp_line) | ||
| 1533 | _log("COMP_POINT: %r" % comp_point) | ||
| 1534 | |||
| 1535 | try: | ||
| 1536 | script = _module_from_path(script_path) | ||
| 1537 | except ImportError, ex: | ||
| 1538 | _log("error importing `%s': %s" % (script_path, ex)) | ||
| 1539 | return [] | ||
| 1540 | shell = getattr(script, class_name)() | ||
| 1541 | cmd_map = shell._get_canonical_map() | ||
| 1542 | del cmd_map["EOF"] | ||
| 1543 | |||
| 1544 | # Determine if completing the sub-command name. | ||
| 1545 | parts = comp_line[:comp_point].split(None, 1) | ||
| 1546 | _log(parts) | ||
| 1547 | if len(parts) == 1 or not (' ' in parts[1] or '\t' in parts[1]): | ||
| 1548 | #TODO: if parts[1].startswith('-'): handle top-level opts | ||
| 1549 | _log("complete sub-command names") | ||
| 1550 | matches = {} | ||
| 1551 | for name, canon_name in cmd_map.items(): | ||
| 1552 | if name.startswith(token): | ||
| 1553 | matches[name] = canon_name | ||
| 1554 | if not matches: | ||
| 1555 | return [] | ||
| 1556 | elif len(matches) == 1: | ||
| 1557 | return matches.keys() | ||
| 1558 | elif len(set(matches.values())) == 1: | ||
| 1559 | return [matches.values()[0]] | ||
| 1560 | else: | ||
| 1561 | return matches.keys() | ||
| 1562 | |||
| 1563 | # Otherwise, complete options for the given sub-command. | ||
| 1564 | #TODO: refine this so it does the right thing with option args | ||
| 1565 | if token.startswith('-'): | ||
| 1566 | cmd_name = comp_line.split(None, 2)[1] | ||
| 1567 | try: | ||
| 1568 | cmd_canon_name = cmd_map[cmd_name] | ||
| 1569 | except KeyError: | ||
| 1570 | return [] | ||
| 1571 | handler = shell._get_cmd_handler(cmd_canon_name) | ||
| 1572 | optparser = getattr(handler, "optparser", None) | ||
| 1573 | if optparser is None: | ||
| 1574 | optparser = SubCmdOptionParser() | ||
| 1575 | opt_strs = [] | ||
| 1576 | for option in optparser.option_list: | ||
| 1577 | for opt_str in option._short_opts + option._long_opts: | ||
| 1578 | if opt_str.startswith(token): | ||
| 1579 | opt_strs.append(opt_str) | ||
| 1580 | return opt_strs | ||
| 1581 | |||
| 1582 | return [] | ||
| 1583 | |||
| 1584 | for cpln in _get_bash_cplns(*sys.argv[1:]): | ||
| 1585 | print cpln | ||
| 1586 | |||
diff --git a/scripts/lib/wic/utils/errors.py b/scripts/lib/wic/utils/errors.py new file mode 100644 index 0000000000..9410311875 --- /dev/null +++ b/scripts/lib/wic/utils/errors.py | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2007 Red Hat, Inc. | ||
| 4 | # Copyright (c) 2011 Intel, Inc. | ||
| 5 | # | ||
| 6 | # This program is free software; you can redistribute it and/or modify it | ||
| 7 | # under the terms of the GNU General Public License as published by the Free | ||
| 8 | # Software Foundation; version 2 of the License | ||
| 9 | # | ||
| 10 | # This program is distributed in the hope that it will be useful, but | ||
| 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 12 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 13 | # for more details. | ||
| 14 | # | ||
| 15 | # You should have received a copy of the GNU General Public License along | ||
| 16 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 17 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 18 | |||
| 19 | class CreatorError(Exception): | ||
| 20 | """An exception base class for all imgcreate errors.""" | ||
| 21 | keyword = '<creator>' | ||
| 22 | |||
| 23 | def __init__(self, msg): | ||
| 24 | self.msg = msg | ||
| 25 | |||
| 26 | def __str__(self): | ||
| 27 | if isinstance(self.msg, unicode): | ||
| 28 | self.msg = self.msg.encode('utf-8', 'ignore') | ||
| 29 | else: | ||
| 30 | self.msg = str(self.msg) | ||
| 31 | return self.keyword + self.msg | ||
| 32 | |||
| 33 | class Usage(CreatorError): | ||
| 34 | keyword = '<usage>' | ||
| 35 | |||
| 36 | def __str__(self): | ||
| 37 | if isinstance(self.msg, unicode): | ||
| 38 | self.msg = self.msg.encode('utf-8', 'ignore') | ||
| 39 | else: | ||
| 40 | self.msg = str(self.msg) | ||
| 41 | return self.keyword + self.msg + ', please use "--help" for more info' | ||
| 42 | |||
| 43 | class KsError(CreatorError): | ||
| 44 | keyword = '<kickstart>' | ||
| 45 | |||
| 46 | class ImageError(CreatorError): | ||
| 47 | keyword = '<mount>' | ||
diff --git a/scripts/lib/wic/utils/fs_related.py b/scripts/lib/wic/utils/fs_related.py new file mode 100644 index 0000000000..ea9f85c60f --- /dev/null +++ b/scripts/lib/wic/utils/fs_related.py | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2007, Red Hat, Inc. | ||
| 4 | # Copyright (c) 2009, 2010, 2011 Intel, Inc. | ||
| 5 | # | ||
| 6 | # This program is free software; you can redistribute it and/or modify it | ||
| 7 | # under the terms of the GNU General Public License as published by the Free | ||
| 8 | # Software Foundation; version 2 of the License | ||
| 9 | # | ||
| 10 | # This program is distributed in the hope that it will be useful, but | ||
| 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 12 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 13 | # for more details. | ||
| 14 | # | ||
| 15 | # You should have received a copy of the GNU General Public License along | ||
| 16 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 17 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 18 | |||
| 19 | from __future__ import with_statement | ||
| 20 | import os | ||
| 21 | import sys | ||
| 22 | import errno | ||
| 23 | import stat | ||
| 24 | import random | ||
| 25 | import string | ||
| 26 | import time | ||
| 27 | import uuid | ||
| 28 | |||
| 29 | from wic import msger | ||
| 30 | from wic.utils import runner | ||
| 31 | from wic.utils.errors import * | ||
| 32 | from wic.utils.oe.misc import * | ||
| 33 | |||
| 34 | def find_binary_path(binary): | ||
| 35 | if os.environ.has_key("PATH"): | ||
| 36 | paths = os.environ["PATH"].split(":") | ||
| 37 | else: | ||
| 38 | paths = [] | ||
| 39 | if os.environ.has_key("HOME"): | ||
| 40 | paths += [os.environ["HOME"] + "/bin"] | ||
| 41 | paths += ["/usr/local/sbin", "/usr/local/bin", "/usr/sbin", "/usr/bin", "/sbin", "/bin"] | ||
| 42 | |||
| 43 | for path in paths: | ||
| 44 | bin_path = "%s/%s" % (path, binary) | ||
| 45 | if os.path.exists(bin_path): | ||
| 46 | return bin_path | ||
| 47 | |||
| 48 | print "External command '%s' not found, exiting." % binary | ||
| 49 | print " (Please install '%s' on your host system)" % binary | ||
| 50 | sys.exit(1) | ||
| 51 | |||
| 52 | def makedirs(dirname): | ||
| 53 | """A version of os.makedirs() that doesn't throw an | ||
| 54 | exception if the leaf directory already exists. | ||
| 55 | """ | ||
| 56 | try: | ||
| 57 | os.makedirs(dirname) | ||
| 58 | except OSError, err: | ||
| 59 | if err.errno != errno.EEXIST: | ||
| 60 | raise | ||
| 61 | |||
| 62 | class Disk: | ||
| 63 | """ | ||
| 64 | Generic base object for a disk. | ||
| 65 | """ | ||
| 66 | def __init__(self, size, device = None): | ||
| 67 | self._device = device | ||
| 68 | self._size = size | ||
| 69 | |||
| 70 | def create(self): | ||
| 71 | pass | ||
| 72 | |||
| 73 | def cleanup(self): | ||
| 74 | pass | ||
| 75 | |||
| 76 | def get_device(self): | ||
| 77 | return self._device | ||
| 78 | def set_device(self, path): | ||
| 79 | self._device = path | ||
| 80 | device = property(get_device, set_device) | ||
| 81 | |||
| 82 | def get_size(self): | ||
| 83 | return self._size | ||
| 84 | size = property(get_size) | ||
| 85 | |||
| 86 | |||
| 87 | class DiskImage(Disk): | ||
| 88 | """ | ||
| 89 | A Disk backed by a file. | ||
| 90 | """ | ||
| 91 | def __init__(self, image_file, size): | ||
| 92 | Disk.__init__(self, size) | ||
| 93 | self.image_file = image_file | ||
| 94 | |||
| 95 | def exists(self): | ||
| 96 | return os.path.exists(self.image_file) | ||
| 97 | |||
| 98 | def create(self): | ||
| 99 | if self.device is not None: | ||
| 100 | return | ||
| 101 | |||
| 102 | blocks = self.size / 1024 | ||
| 103 | if self.size - blocks * 1024: | ||
| 104 | blocks += 1 | ||
| 105 | |||
| 106 | # create disk image | ||
| 107 | dd_cmd = "dd if=/dev/zero of=%s bs=1024 seek=%d count=1" % \ | ||
| 108 | (self.image_file, blocks) | ||
| 109 | exec_cmd(dd_cmd) | ||
| 110 | |||
| 111 | self.device = self.image_file | ||
diff --git a/scripts/lib/wic/utils/misc.py b/scripts/lib/wic/utils/misc.py new file mode 100644 index 0000000000..6e56316608 --- /dev/null +++ b/scripts/lib/wic/utils/misc.py | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2010, 2011 Intel Inc. | ||
| 4 | # | ||
| 5 | # This program is free software; you can redistribute it and/or modify it | ||
| 6 | # under the terms of the GNU General Public License as published by the Free | ||
| 7 | # Software Foundation; version 2 of the License | ||
| 8 | # | ||
| 9 | # This program is distributed in the hope that it will be useful, but | ||
| 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 12 | # for more details. | ||
| 13 | # | ||
| 14 | # You should have received a copy of the GNU General Public License along | ||
| 15 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 16 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 17 | |||
| 18 | import os | ||
| 19 | import sys | ||
| 20 | import time | ||
| 21 | |||
| 22 | def build_name(kscfg, release=None, prefix = None, suffix = None): | ||
| 23 | """Construct and return an image name string. | ||
| 24 | |||
| 25 | This is a utility function to help create sensible name and fslabel | ||
| 26 | strings. The name is constructed using the sans-prefix-and-extension | ||
| 27 | kickstart filename and the supplied prefix and suffix. | ||
| 28 | |||
| 29 | kscfg -- a path to a kickstart file | ||
| 30 | release -- a replacement to suffix for image release | ||
| 31 | prefix -- a prefix to prepend to the name; defaults to None, which causes | ||
| 32 | no prefix to be used | ||
| 33 | suffix -- a suffix to append to the name; defaults to None, which causes | ||
| 34 | a YYYYMMDDHHMM suffix to be used | ||
| 35 | |||
| 36 | Note, if maxlen is less then the len(suffix), you get to keep both pieces. | ||
| 37 | |||
| 38 | """ | ||
| 39 | name = os.path.basename(kscfg) | ||
| 40 | idx = name.rfind('.') | ||
| 41 | if idx >= 0: | ||
| 42 | name = name[:idx] | ||
| 43 | |||
| 44 | if release is not None: | ||
| 45 | suffix = "" | ||
| 46 | if prefix is None: | ||
| 47 | prefix = "" | ||
| 48 | if suffix is None: | ||
| 49 | suffix = time.strftime("%Y%m%d%H%M") | ||
| 50 | |||
| 51 | if name.startswith(prefix): | ||
| 52 | name = name[len(prefix):] | ||
| 53 | |||
| 54 | prefix = "%s-" % prefix if prefix else "" | ||
| 55 | suffix = "-%s" % suffix if suffix else "" | ||
| 56 | |||
| 57 | ret = prefix + name + suffix | ||
| 58 | |||
| 59 | return ret | ||
diff --git a/scripts/lib/wic/utils/oe/__init__.py b/scripts/lib/wic/utils/oe/__init__.py new file mode 100644 index 0000000000..0a81575a74 --- /dev/null +++ b/scripts/lib/wic/utils/oe/__init__.py | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | # | ||
| 2 | # OpenEmbedded wic utils library | ||
| 3 | # | ||
| 4 | # Copyright (c) 2013, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # AUTHORS | ||
| 21 | # Tom Zanussi <tom.zanussi (at] linux.intel.com> | ||
| 22 | # | ||
diff --git a/scripts/lib/wic/utils/oe/misc.py b/scripts/lib/wic/utils/oe/misc.py new file mode 100644 index 0000000000..b0b5baab73 --- /dev/null +++ b/scripts/lib/wic/utils/oe/misc.py | |||
| @@ -0,0 +1,205 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2013, Intel Corporation. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This module provides a place to collect various wic-related utils | ||
| 22 | # for the OpenEmbedded Image Tools. | ||
| 23 | # | ||
| 24 | # AUTHORS | ||
| 25 | # Tom Zanussi <tom.zanussi (at] linux.intel.com> | ||
| 26 | # | ||
| 27 | |||
| 28 | from wic import msger | ||
| 29 | from wic.utils import runner | ||
| 30 | |||
| 31 | def __exec_cmd(cmd_and_args, as_shell = False, catch = 3): | ||
| 32 | """ | ||
| 33 | Execute command, catching stderr, stdout | ||
| 34 | |||
| 35 | Need to execute as_shell if the command uses wildcards | ||
| 36 | """ | ||
| 37 | msger.debug("__exec_cmd: %s" % cmd_and_args) | ||
| 38 | args = cmd_and_args.split() | ||
| 39 | msger.debug(args) | ||
| 40 | |||
| 41 | if (as_shell): | ||
| 42 | rc, out = runner.runtool(cmd_and_args, catch) | ||
| 43 | else: | ||
| 44 | rc, out = runner.runtool(args, catch) | ||
| 45 | out = out.strip() | ||
| 46 | msger.debug("__exec_cmd: output for %s (rc = %d): %s" % \ | ||
| 47 | (cmd_and_args, rc, out)) | ||
| 48 | |||
| 49 | return (rc, out) | ||
| 50 | |||
| 51 | |||
| 52 | def exec_cmd(cmd_and_args, as_shell = False, catch = 3): | ||
| 53 | """ | ||
| 54 | Execute command, catching stderr, stdout | ||
| 55 | |||
| 56 | Exits if rc non-zero | ||
| 57 | """ | ||
| 58 | rc, out = __exec_cmd(cmd_and_args, as_shell, catch) | ||
| 59 | |||
| 60 | if rc != 0: | ||
| 61 | msger.error("exec_cmd: %s returned '%s' instead of 0" % (cmd_and_args, rc)) | ||
| 62 | |||
| 63 | return out | ||
| 64 | |||
| 65 | |||
| 66 | def exec_cmd_quiet(cmd_and_args, as_shell = False): | ||
| 67 | """ | ||
| 68 | Execute command, catching nothing in the output | ||
| 69 | |||
| 70 | Exits if rc non-zero | ||
| 71 | """ | ||
| 72 | return exec_cmd(cmd_and_args, as_shell, 0) | ||
| 73 | |||
| 74 | |||
| 75 | def exec_native_cmd(cmd_and_args, native_sysroot, catch = 3): | ||
| 76 | """ | ||
| 77 | Execute native command, catching stderr, stdout | ||
| 78 | |||
| 79 | Need to execute as_shell if the command uses wildcards | ||
| 80 | |||
| 81 | Always need to execute native commands as_shell | ||
| 82 | """ | ||
| 83 | native_paths = \ | ||
| 84 | "export PATH=%s/sbin:%s/usr/sbin:%s/usr/bin:$PATH" % \ | ||
| 85 | (native_sysroot, native_sysroot, native_sysroot) | ||
| 86 | native_cmd_and_args = "%s;%s" % (native_paths, cmd_and_args) | ||
| 87 | msger.debug("exec_native_cmd: %s" % cmd_and_args) | ||
| 88 | |||
| 89 | args = cmd_and_args.split() | ||
| 90 | msger.debug(args) | ||
| 91 | |||
| 92 | rc, out = __exec_cmd(native_cmd_and_args, True, catch) | ||
| 93 | |||
| 94 | if rc == 127: # shell command-not-found | ||
| 95 | msger.error("A native (host) program required to build the image " | ||
| 96 | "was not found (see details above). Please make sure " | ||
| 97 | "it's installed and try again.") | ||
| 98 | |||
| 99 | return (rc, out) | ||
| 100 | |||
| 101 | |||
| 102 | def exec_native_cmd_quiet(cmd_and_args, native_sysroot): | ||
| 103 | """ | ||
| 104 | Execute native command, catching nothing in the output | ||
| 105 | |||
| 106 | Need to execute as_shell if the command uses wildcards | ||
| 107 | |||
| 108 | Always need to execute native commands as_shell | ||
| 109 | """ | ||
| 110 | return exec_native_cmd(cmd_and_args, native_sysroot, 0) | ||
| 111 | |||
| 112 | |||
| 113 | # kickstart doesn't support variable substution in commands, so this | ||
| 114 | # is our current simplistic scheme for supporting that | ||
| 115 | |||
| 116 | wks_vars = dict() | ||
| 117 | |||
| 118 | def get_wks_var(key): | ||
| 119 | return wks_vars[key] | ||
| 120 | |||
| 121 | def add_wks_var(key, val): | ||
| 122 | wks_vars[key] = val | ||
| 123 | |||
| 124 | BOOTDD_EXTRA_SPACE = 16384 | ||
| 125 | IMAGE_EXTRA_SPACE = 10240 | ||
| 126 | IMAGE_OVERHEAD_FACTOR = 1.3 | ||
| 127 | |||
| 128 | __bitbake_env_lines = "" | ||
| 129 | |||
| 130 | def set_bitbake_env_lines(bitbake_env_lines): | ||
| 131 | global __bitbake_env_lines | ||
| 132 | __bitbake_env_lines = bitbake_env_lines | ||
| 133 | |||
| 134 | def get_bitbake_env_lines(): | ||
| 135 | return __bitbake_env_lines | ||
| 136 | |||
| 137 | def find_bitbake_env_lines(image_name): | ||
| 138 | """ | ||
| 139 | If image_name is empty, plugins might still be able to use the | ||
| 140 | environment, so set it regardless. | ||
| 141 | """ | ||
| 142 | if image_name: | ||
| 143 | bitbake_env_cmd = "bitbake -e %s" % image_name | ||
| 144 | else: | ||
| 145 | bitbake_env_cmd = "bitbake -e" | ||
| 146 | rc, bitbake_env_lines = __exec_cmd(bitbake_env_cmd) | ||
| 147 | if rc != 0: | ||
| 148 | print "Couldn't get '%s' output." % bitbake_env_cmd | ||
| 149 | return None | ||
| 150 | |||
| 151 | return bitbake_env_lines | ||
| 152 | |||
| 153 | def find_artifact(bitbake_env_lines, variable): | ||
| 154 | """ | ||
| 155 | Gather the build artifact for the current image (the image_name | ||
| 156 | e.g. core-image-minimal) for the current MACHINE set in local.conf | ||
| 157 | """ | ||
| 158 | retval = "" | ||
| 159 | |||
| 160 | for line in bitbake_env_lines.split('\n'): | ||
| 161 | if (get_line_val(line, variable)): | ||
| 162 | retval = get_line_val(line, variable) | ||
| 163 | break | ||
| 164 | |||
| 165 | return retval | ||
| 166 | |||
| 167 | def get_line_val(line, key): | ||
| 168 | """ | ||
| 169 | Extract the value from the VAR="val" string | ||
| 170 | """ | ||
| 171 | if line.startswith(key + "="): | ||
| 172 | stripped_line = line.split('=')[1] | ||
| 173 | stripped_line = stripped_line.replace('\"', '') | ||
| 174 | return stripped_line | ||
| 175 | return None | ||
| 176 | |||
| 177 | def get_bitbake_var(key): | ||
| 178 | for line in __bitbake_env_lines.split('\n'): | ||
| 179 | if (get_line_val(line, key)): | ||
| 180 | val = get_line_val(line, key) | ||
| 181 | return val | ||
| 182 | return None | ||
| 183 | |||
| 184 | def parse_sourceparams(sourceparams): | ||
| 185 | """ | ||
| 186 | Split sourceparams string of the form key1=val1[,key2=val2,...] | ||
| 187 | into a dict. Also accepts valueless keys i.e. without =. | ||
| 188 | |||
| 189 | Returns dict of param key/val pairs (note that val may be None). | ||
| 190 | """ | ||
| 191 | params_dict = {} | ||
| 192 | |||
| 193 | params = sourceparams.split(',') | ||
| 194 | if params: | ||
| 195 | for p in params: | ||
| 196 | if not p: | ||
| 197 | continue | ||
| 198 | if not '=' in p: | ||
| 199 | key = p | ||
| 200 | val = None | ||
| 201 | else: | ||
| 202 | key, val = p.split('=') | ||
| 203 | params_dict[key] = val | ||
| 204 | |||
| 205 | return params_dict | ||
diff --git a/scripts/lib/wic/utils/oe/package_manager.py b/scripts/lib/wic/utils/oe/package_manager.py new file mode 100644 index 0000000000..92ce98e2ce --- /dev/null +++ b/scripts/lib/wic/utils/oe/package_manager.py | |||
| @@ -0,0 +1,810 @@ | |||
| 1 | # ex:ts=4:sw=4:sts=4:et | ||
| 2 | # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- | ||
| 3 | # | ||
| 4 | # Copyright (c) 2014, Enea AB. | ||
| 5 | # All rights reserved. | ||
| 6 | # | ||
| 7 | # This program is free software; you can redistribute it and/or modify | ||
| 8 | # it under the terms of the GNU General Public License version 2 as | ||
| 9 | # published by the Free Software Foundation. | ||
| 10 | # | ||
| 11 | # This program is distributed in the hope that it will be useful, | ||
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | # GNU General Public License for more details. | ||
| 15 | # | ||
| 16 | # You should have received a copy of the GNU General Public License along | ||
| 17 | # with this program; if not, write to the Free Software Foundation, Inc., | ||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 19 | # | ||
| 20 | # DESCRIPTION | ||
| 21 | # This implements the opkg package manager wrapper as a combination of | ||
| 22 | # meta/lib/oe/package_manager.py and bitbake/lib/bb/utils.py files and | ||
| 23 | # adaptation of those files to 'wic'. | ||
| 24 | # | ||
| 25 | # AUTHORS | ||
| 26 | # Adrian Calianu <adrian.calianu (at] enea.com> | ||
| 27 | # | ||
| 28 | # This file incorporates work covered by the following copyright and | ||
| 29 | # permission notice: | ||
| 30 | # | ||
| 31 | # meta/COPYING.GPLv2 (GPLv2) | ||
| 32 | # meta/COPYING.MIT (MIT) | ||
| 33 | # | ||
| 34 | # Copyright (C) 2004 Michael Lauer | ||
| 35 | # | ||
| 36 | # Permission to use, copy, modify, and/or distribute this software | ||
| 37 | # for any purpose with or without fee is hereby granted, provided | ||
| 38 | # that the above copyright notice and this permission notice appear | ||
| 39 | # in all copies. | ||
| 40 | # | ||
| 41 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | ||
| 42 | # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | ||
| 43 | # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE | ||
| 44 | # AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | ||
| 45 | # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS | ||
| 46 | # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | ||
| 47 | # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | ||
| 48 | # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
| 49 | |||
| 50 | |||
| 51 | from abc import ABCMeta, abstractmethod | ||
| 52 | import os | ||
| 53 | import glob | ||
| 54 | import subprocess | ||
| 55 | import shutil | ||
| 56 | import multiprocessing | ||
| 57 | import re | ||
| 58 | import errno | ||
| 59 | import fcntl | ||
| 60 | |||
| 61 | from mic.utils.oe.misc import * | ||
| 62 | from mic import msger | ||
| 63 | |||
| 64 | def mkdirhier(directory): | ||
| 65 | """Create a directory like 'mkdir -p', but does not complain if | ||
| 66 | directory already exists like os.makedirs | ||
| 67 | """ | ||
| 68 | |||
| 69 | try: | ||
| 70 | os.makedirs(directory) | ||
| 71 | except OSError as e: | ||
| 72 | if e.errno != errno.EEXIST: | ||
| 73 | raise e | ||
| 74 | |||
| 75 | def remove(path, recurse=False): | ||
| 76 | """Equivalent to rm -f or rm -rf""" | ||
| 77 | if not path: | ||
| 78 | return | ||
| 79 | if recurse: | ||
| 80 | # shutil.rmtree(name) would be ideal but its too slow | ||
| 81 | subprocess.call(['rm', '-rf'] + glob.glob(path)) | ||
| 82 | return | ||
| 83 | for name in glob.glob(path): | ||
| 84 | try: | ||
| 85 | os.unlink(name) | ||
| 86 | except OSError as exc: | ||
| 87 | if exc.errno != errno.ENOENT: | ||
| 88 | raise | ||
| 89 | |||
| 90 | def lockfile(name, shared=False, retry=True): | ||
| 91 | """ | ||
| 92 | Use the file fn as a lock file, return when the lock has been acquired. | ||
| 93 | Returns a variable to pass to unlockfile(). | ||
| 94 | """ | ||
| 95 | dirname = os.path.dirname(name) | ||
| 96 | mkdirhier(dirname) | ||
| 97 | |||
| 98 | if not os.access(dirname, os.W_OK): | ||
| 99 | logger.error("Unable to acquire lock '%s', directory is not writable", | ||
| 100 | name) | ||
| 101 | sys.exit(1) | ||
| 102 | |||
| 103 | op = fcntl.LOCK_EX | ||
| 104 | if shared: | ||
| 105 | op = fcntl.LOCK_SH | ||
| 106 | if not retry: | ||
| 107 | op = op | fcntl.LOCK_NB | ||
| 108 | |||
| 109 | while True: | ||
| 110 | # If we leave the lockfiles lying around there is no problem | ||
| 111 | # but we should clean up after ourselves. This gives potential | ||
| 112 | # for races though. To work around this, when we acquire the lock | ||
| 113 | # we check the file we locked was still the lock file on disk. | ||
| 114 | # by comparing inode numbers. If they don't match or the lockfile | ||
| 115 | # no longer exists, we start again. | ||
| 116 | |||
| 117 | # This implementation is unfair since the last person to request the | ||
| 118 | # lock is the most likely to win it. | ||
| 119 | |||
| 120 | try: | ||
| 121 | lf = open(name, 'a+') | ||
| 122 | fileno = lf.fileno() | ||
| 123 | fcntl.flock(fileno, op) | ||
| 124 | statinfo = os.fstat(fileno) | ||
| 125 | if os.path.exists(lf.name): | ||
| 126 | statinfo2 = os.stat(lf.name) | ||
| 127 | if statinfo.st_ino == statinfo2.st_ino: | ||
| 128 | return lf | ||
| 129 | lf.close() | ||
| 130 | except Exception: | ||
| 131 | try: | ||
| 132 | lf.close() | ||
| 133 | except Exception: | ||
| 134 | pass | ||
| 135 | pass | ||
| 136 | if not retry: | ||
| 137 | return None | ||
| 138 | |||
| 139 | def unlockfile(lf): | ||
| 140 | """ | ||
| 141 | Unlock a file locked using lockfile() | ||
| 142 | """ | ||
| 143 | try: | ||
| 144 | # If we had a shared lock, we need to promote to exclusive before | ||
| 145 | # removing the lockfile. Attempt this, ignore failures. | ||
| 146 | fcntl.flock(lf.fileno(), fcntl.LOCK_EX|fcntl.LOCK_NB) | ||
| 147 | os.unlink(lf.name) | ||
| 148 | except (IOError, OSError): | ||
| 149 | pass | ||
| 150 | fcntl.flock(lf.fileno(), fcntl.LOCK_UN) | ||
| 151 | lf.close() | ||
| 152 | |||
| 153 | def which(path, item, direction = 0, history = False): | ||
| 154 | """ | ||
| 155 | Locate a file in a PATH | ||
| 156 | """ | ||
| 157 | |||
| 158 | hist = [] | ||
| 159 | paths = (path or "").split(':') | ||
| 160 | if direction != 0: | ||
| 161 | paths.reverse() | ||
| 162 | |||
| 163 | for p in paths: | ||
| 164 | next = os.path.join(p, item) | ||
| 165 | hist.append(next) | ||
| 166 | if os.path.exists(next): | ||
| 167 | if not os.path.isabs(next): | ||
| 168 | next = os.path.abspath(next) | ||
| 169 | if history: | ||
| 170 | return next, hist | ||
| 171 | return next | ||
| 172 | |||
| 173 | if history: | ||
| 174 | return "", hist | ||
| 175 | return "" | ||
| 176 | |||
| 177 | |||
| 178 | |||
| 179 | # this can be used by all PM backends to create the index files in parallel | ||
| 180 | def wic_create_index(arg): | ||
| 181 | index_cmd = arg | ||
| 182 | |||
| 183 | try: | ||
| 184 | msger.info("Executing '%s' ..." % index_cmd) | ||
| 185 | subprocess.check_output(index_cmd, stderr=subprocess.STDOUT, shell=True) | ||
| 186 | except subprocess.CalledProcessError as e: | ||
| 187 | return("Index creation command '%s' failed with return code %d:\n%s" % | ||
| 188 | (e.cmd, e.returncode, e.output)) | ||
| 189 | |||
| 190 | return None | ||
| 191 | |||
| 192 | |||
| 193 | class WicIndexer(object): | ||
| 194 | __metaclass__ = ABCMeta | ||
| 195 | |||
| 196 | def __init__(self, d, deploy_dir): | ||
| 197 | self.d = d | ||
| 198 | self.deploy_dir = deploy_dir | ||
| 199 | |||
| 200 | @abstractmethod | ||
| 201 | def write_index(self): | ||
| 202 | pass | ||
| 203 | |||
| 204 | class WicOpkgIndexer(WicIndexer): | ||
| 205 | def write_index(self): | ||
| 206 | arch_vars = ["ALL_MULTILIB_PACKAGE_ARCHS", | ||
| 207 | "SDK_PACKAGE_ARCHS", | ||
| 208 | "MULTILIB_ARCHS"] | ||
| 209 | |||
| 210 | opkg_index_cmd = which(os.getenv('PATH'), "opkg-make-index") | ||
| 211 | |||
| 212 | if not os.path.exists(os.path.join(self.deploy_dir, "Packages")): | ||
| 213 | open(os.path.join(self.deploy_dir, "Packages"), "w").close() | ||
| 214 | |||
| 215 | index_cmds = [] | ||
| 216 | for arch_var in arch_vars: | ||
| 217 | if self.d.has_key(arch_var): | ||
| 218 | archs = self.d[arch_var] | ||
| 219 | else: | ||
| 220 | archs = None | ||
| 221 | |||
| 222 | if archs is None: | ||
| 223 | continue | ||
| 224 | |||
| 225 | for arch in archs.split(): | ||
| 226 | pkgs_dir = os.path.join(self.deploy_dir, arch) | ||
| 227 | pkgs_file = os.path.join(pkgs_dir, "Packages") | ||
| 228 | |||
| 229 | if not os.path.isdir(pkgs_dir): | ||
| 230 | continue | ||
| 231 | |||
| 232 | if not os.path.exists(pkgs_file): | ||
| 233 | open(pkgs_file, "w").close() | ||
| 234 | |||
| 235 | index_cmds.append('%s -r %s -p %s -m %s' % | ||
| 236 | (opkg_index_cmd, pkgs_file, pkgs_file, pkgs_dir)) | ||
| 237 | |||
| 238 | if len(index_cmds) == 0: | ||
| 239 | msger.info("There are no packages in %s!" % self.deploy_dir) | ||
| 240 | return | ||
| 241 | |||
| 242 | nproc = multiprocessing.cpu_count() | ||
| 243 | pool = multiprocessing.Pool(nproc) | ||
| 244 | results = list(pool.imap(wic_create_index, index_cmds)) | ||
| 245 | pool.close() | ||
| 246 | pool.join() | ||
| 247 | |||
| 248 | for result in results: | ||
| 249 | if result is not None: | ||
| 250 | return(result) | ||
| 251 | |||
| 252 | class WicPkgsList(object): | ||
| 253 | __metaclass__ = ABCMeta | ||
| 254 | |||
| 255 | def __init__(self, d, rootfs_dir): | ||
| 256 | self.d = d | ||
| 257 | self.rootfs_dir = rootfs_dir | ||
| 258 | |||
| 259 | @abstractmethod | ||
| 260 | def list(self, format=None): | ||
| 261 | pass | ||
| 262 | |||
| 263 | |||
| 264 | class WicOpkgPkgsList(WicPkgsList): | ||
| 265 | def __init__(self, d, rootfs_dir, config_file): | ||
| 266 | super(WicOpkgPkgsList, self).__init__(d, rootfs_dir) | ||
| 267 | |||
| 268 | self.opkg_cmd = which(os.getenv('PATH'), "opkg-cl") | ||
| 269 | self.opkg_args = "-f %s -o %s " % (config_file, rootfs_dir) | ||
| 270 | if self.d.has_key("OPKG_ARGS"): | ||
| 271 | self.opkg_args += self.d["OPKG_ARGS"] | ||
| 272 | |||
| 273 | def list(self, format=None): | ||
| 274 | opkg_query_cmd = which(os.getenv('PATH'), "opkg-query-helper.py") | ||
| 275 | |||
| 276 | if format == "arch": | ||
| 277 | cmd = "%s %s status | %s -a" % \ | ||
| 278 | (self.opkg_cmd, self.opkg_args, opkg_query_cmd) | ||
| 279 | elif format == "file": | ||
| 280 | cmd = "%s %s status | %s -f" % \ | ||
| 281 | (self.opkg_cmd, self.opkg_args, opkg_query_cmd) | ||
| 282 | elif format == "ver": | ||
| 283 | cmd = "%s %s status | %s -v" % \ | ||
| 284 | (self.opkg_cmd, self.opkg_args, opkg_query_cmd) | ||
| 285 | elif format == "deps": | ||
| 286 | cmd = "%s %s status | %s" % \ | ||
| 287 | (self.opkg_cmd, self.opkg_args, opkg_query_cmd) | ||
| 288 | else: | ||
| 289 | cmd = "%s %s list_installed | cut -d' ' -f1" % \ | ||
| 290 | (self.opkg_cmd, self.opkg_args) | ||
| 291 | |||
| 292 | try: | ||
| 293 | output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True).strip() | ||
| 294 | except subprocess.CalledProcessError as e: | ||
| 295 | msger.error("Cannot get the installed packages list. Command '%s' " | ||
| 296 | "returned %d:\n%s" % (cmd, e.returncode, e.output)) | ||
| 297 | |||
| 298 | if output and format == "file": | ||
| 299 | tmp_output = "" | ||
| 300 | for line in output.split('\n'): | ||
| 301 | pkg, pkg_file, pkg_arch = line.split() | ||
| 302 | full_path = os.path.join(self.rootfs_dir, pkg_arch, pkg_file) | ||
| 303 | if os.path.exists(full_path): | ||
| 304 | tmp_output += "%s %s %s\n" % (pkg, full_path, pkg_arch) | ||
| 305 | else: | ||
| 306 | tmp_output += "%s %s %s\n" % (pkg, pkg_file, pkg_arch) | ||
| 307 | |||
| 308 | output = tmp_output | ||
| 309 | |||
| 310 | return output | ||
| 311 | |||
| 312 | |||
| 313 | class WicPackageManager(object): | ||
| 314 | """ | ||
| 315 | This is an abstract class. Do not instantiate this directly. | ||
| 316 | """ | ||
| 317 | __metaclass__ = ABCMeta | ||
| 318 | |||
| 319 | def __init__(self, d, pseudo, native_sysroot): | ||
| 320 | self.d = d | ||
| 321 | self.deploy_dir = None | ||
| 322 | self.deploy_lock = None | ||
| 323 | if self.d.has_key('PACKAGE_FEED_URIS'): | ||
| 324 | self.feed_uris = self.d['PACKAGE_FEED_URIS'] | ||
| 325 | else: | ||
| 326 | self.feed_uris = "" | ||
| 327 | self.pseudo = pseudo | ||
| 328 | self.native_sysroot = native_sysroot | ||
| 329 | |||
| 330 | """ | ||
| 331 | Update the package manager package database. | ||
| 332 | """ | ||
| 333 | @abstractmethod | ||
| 334 | def update(self): | ||
| 335 | pass | ||
| 336 | |||
| 337 | """ | ||
| 338 | Install a list of packages. 'pkgs' is a list object. If 'attempt_only' is | ||
| 339 | True, installation failures are ignored. | ||
| 340 | """ | ||
| 341 | @abstractmethod | ||
| 342 | def install(self, pkgs, attempt_only=False): | ||
| 343 | pass | ||
| 344 | |||
| 345 | """ | ||
| 346 | Remove a list of packages. 'pkgs' is a list object. If 'with_dependencies' | ||
| 347 | is False, the any dependencies are left in place. | ||
| 348 | """ | ||
| 349 | @abstractmethod | ||
| 350 | def remove(self, pkgs, with_dependencies=True): | ||
| 351 | pass | ||
| 352 | |||
| 353 | """ | ||
| 354 | This function creates the index files | ||
| 355 | """ | ||
| 356 | @abstractmethod | ||
| 357 | def write_index(self): | ||
| 358 | pass | ||
| 359 | |||
| 360 | @abstractmethod | ||
| 361 | def remove_packaging_data(self): | ||
| 362 | pass | ||
| 363 | |||
| 364 | @abstractmethod | ||
| 365 | def list_installed(self, format=None): | ||
| 366 | pass | ||
| 367 | |||
| 368 | @abstractmethod | ||
| 369 | def insert_feeds_uris(self): | ||
| 370 | pass | ||
| 371 | |||
| 372 | """ | ||
| 373 | Install complementary packages based upon the list of currently installed | ||
| 374 | packages e.g. locales, *-dev, *-dbg, etc. This will only attempt to install | ||
| 375 | these packages, if they don't exist then no error will occur. Note: every | ||
| 376 | backend needs to call this function explicitly after the normal package | ||
| 377 | installation | ||
| 378 | """ | ||
| 379 | def install_complementary(self, globs=None): | ||
| 380 | # we need to write the list of installed packages to a file because the | ||
| 381 | # oe-pkgdata-util reads it from a file | ||
| 382 | if self.d.has_key('WORKDIR'): | ||
| 383 | installed_pkgs_file = os.path.join(self.d['WORKDIR'], | ||
| 384 | "installed_pkgs.txt") | ||
| 385 | else: | ||
| 386 | msger.error("No WORKDIR provided!") | ||
| 387 | |||
| 388 | with open(installed_pkgs_file, "w+") as installed_pkgs: | ||
| 389 | installed_pkgs.write(self.list_installed("arch")) | ||
| 390 | |||
| 391 | if globs is None: | ||
| 392 | if self.d.has_key('IMAGE_INSTALL_COMPLEMENTARY'): | ||
| 393 | globs = self.d['IMAGE_INSTALL_COMPLEMENTARY'] | ||
| 394 | split_linguas = set() | ||
| 395 | |||
| 396 | if self.d.has_key('IMAGE_LINGUAS'): | ||
| 397 | for translation in self.d['IMAGE_LINGUAS'].split(): | ||
| 398 | split_linguas.add(translation) | ||
| 399 | split_linguas.add(translation.split('-')[0]) | ||
| 400 | |||
| 401 | split_linguas = sorted(split_linguas) | ||
| 402 | |||
| 403 | for lang in split_linguas: | ||
| 404 | globs += " *-locale-%s" % lang | ||
| 405 | |||
| 406 | if globs is None: | ||
| 407 | return | ||
| 408 | |||
| 409 | if not self.d.has_key('PKGDATA_DIR'): | ||
| 410 | msger.error("No PKGDATA_DIR provided!") | ||
| 411 | |||
| 412 | cmd = [which(os.getenv('PATH'), "oe-pkgdata-util"), | ||
| 413 | "glob", self.d['PKGDATA_DIR'], installed_pkgs_file, | ||
| 414 | globs] | ||
| 415 | |||
| 416 | rc, out = exec_native_cmd(self.pseudo + cmd, self.native_sysroot) | ||
| 417 | if rc != 0: | ||
| 418 | msger.error("Could not compute complementary packages list. Command " | ||
| 419 | "'%s' returned %d" % | ||
| 420 | (' '.join(cmd), rc)) | ||
| 421 | |||
| 422 | self.install(out.split(), attempt_only=True) | ||
| 423 | |||
| 424 | |||
| 425 | def deploy_dir_lock(self): | ||
| 426 | if self.deploy_dir is None: | ||
| 427 | raise RuntimeError("deploy_dir is not set!") | ||
| 428 | |||
| 429 | lock_file_name = os.path.join(self.deploy_dir, "deploy.lock") | ||
| 430 | |||
| 431 | self.deploy_lock = lockfile(lock_file_name) | ||
| 432 | |||
| 433 | def deploy_dir_unlock(self): | ||
| 434 | if self.deploy_lock is None: | ||
| 435 | return | ||
| 436 | |||
| 437 | unlockfile(self.deploy_lock) | ||
| 438 | |||
| 439 | self.deploy_lock = None | ||
| 440 | |||
| 441 | |||
| 442 | class WicOpkgPM(WicPackageManager): | ||
| 443 | def __init__(self, d, target_rootfs, config_file, archs, pseudo, native_sysroot, task_name='target'): | ||
| 444 | super(WicOpkgPM, self).__init__(d, pseudo, native_sysroot) | ||
| 445 | |||
| 446 | self.target_rootfs = target_rootfs | ||
| 447 | self.config_file = config_file | ||
| 448 | self.pkg_archs = archs | ||
| 449 | self.task_name = task_name | ||
| 450 | |||
| 451 | if self.d.has_key("DEPLOY_DIR_IPK"): | ||
| 452 | self.deploy_dir = self.d["DEPLOY_DIR_IPK"] | ||
| 453 | |||
| 454 | self.deploy_lock_file = os.path.join(self.deploy_dir, "deploy.lock") | ||
| 455 | self.opkg_cmd = which(os.getenv('PATH'), "opkg-cl") | ||
| 456 | self.opkg_args = "-f %s -o %s " % (self.config_file, target_rootfs) | ||
| 457 | if self.d.has_key("OPKG_ARGS"): | ||
| 458 | self.opkg_args += self.d["OPKG_ARGS"] | ||
| 459 | |||
| 460 | if self.d.has_key('OPKGLIBDIR'): | ||
| 461 | opkg_lib_dir = self.d['OPKGLIBDIR'] | ||
| 462 | else: | ||
| 463 | opkg_lib_dir = "" | ||
| 464 | |||
| 465 | if opkg_lib_dir[0] == "/": | ||
| 466 | opkg_lib_dir = opkg_lib_dir[1:] | ||
| 467 | |||
| 468 | self.opkg_dir = os.path.join(target_rootfs, opkg_lib_dir, "opkg") | ||
| 469 | |||
| 470 | mkdirhier(self.opkg_dir) | ||
| 471 | |||
| 472 | if self.d.has_key("TMPDIR"): | ||
| 473 | tmp_dir = self.d["TMPDIR"] | ||
| 474 | else: | ||
| 475 | tmp_dir = "" | ||
| 476 | |||
| 477 | self.saved_opkg_dir = '%s/saved/%s' % (tmp_dir, self.task_name) | ||
| 478 | if not os.path.exists('%s/saved' % tmp_dir): | ||
| 479 | mkdirhier('%s/saved' % tmp_dir) | ||
| 480 | |||
| 481 | if self.d.has_key('BUILD_IMAGES_FROM_FEEDS') and self.d['BUILD_IMAGES_FROM_FEEDS'] != "1": | ||
| 482 | self._create_config() | ||
| 483 | else: | ||
| 484 | self._create_custom_config() | ||
| 485 | |||
| 486 | self.indexer = WicOpkgIndexer(self.d, self.deploy_dir) | ||
| 487 | |||
| 488 | """ | ||
| 489 | This function will change a package's status in /var/lib/opkg/status file. | ||
| 490 | If 'packages' is None then the new_status will be applied to all | ||
| 491 | packages | ||
| 492 | """ | ||
| 493 | def mark_packages(self, status_tag, packages=None): | ||
| 494 | status_file = os.path.join(self.opkg_dir, "status") | ||
| 495 | |||
| 496 | with open(status_file, "r") as sf: | ||
| 497 | with open(status_file + ".tmp", "w+") as tmp_sf: | ||
| 498 | if packages is None: | ||
| 499 | tmp_sf.write(re.sub(r"Package: (.*?)\n((?:[^\n]+\n)*?)Status: (.*)(?:unpacked|installed)", | ||
| 500 | r"Package: \1\n\2Status: \3%s" % status_tag, | ||
| 501 | sf.read())) | ||
| 502 | else: | ||
| 503 | if type(packages).__name__ != "list": | ||
| 504 | raise TypeError("'packages' should be a list object") | ||
| 505 | |||
| 506 | status = sf.read() | ||
| 507 | for pkg in packages: | ||
| 508 | status = re.sub(r"Package: %s\n((?:[^\n]+\n)*?)Status: (.*)(?:unpacked|installed)" % pkg, | ||
| 509 | r"Package: %s\n\1Status: \2%s" % (pkg, status_tag), | ||
| 510 | status) | ||
| 511 | |||
| 512 | tmp_sf.write(status) | ||
| 513 | |||
| 514 | os.rename(status_file + ".tmp", status_file) | ||
| 515 | |||
| 516 | def _create_custom_config(self): | ||
| 517 | msger.info("Building from feeds activated!") | ||
| 518 | |||
| 519 | with open(self.config_file, "w+") as config_file: | ||
| 520 | priority = 1 | ||
| 521 | for arch in self.pkg_archs.split(): | ||
| 522 | config_file.write("arch %s %d\n" % (arch, priority)) | ||
| 523 | priority += 5 | ||
| 524 | |||
| 525 | if self.d.has_key('IPK_FEED_URIS'): | ||
| 526 | ipk_feed_uris = self.d['IPK_FEED_URIS'] | ||
| 527 | else: | ||
| 528 | ipk_feed_uris = "" | ||
| 529 | |||
| 530 | for line in ipk_feed_uris.split(): | ||
| 531 | feed_match = re.match("^[ \t]*(.*)##([^ \t]*)[ \t]*$", line) | ||
| 532 | |||
| 533 | if feed_match is not None: | ||
| 534 | feed_name = feed_match.group(1) | ||
| 535 | feed_uri = feed_match.group(2) | ||
| 536 | |||
| 537 | msger.info("Add %s feed with URL %s" % (feed_name, feed_uri)) | ||
| 538 | |||
| 539 | config_file.write("src/gz %s %s\n" % (feed_name, feed_uri)) | ||
| 540 | |||
| 541 | """ | ||
| 542 | Allow to use package deploy directory contents as quick devel-testing | ||
| 543 | feed. This creates individual feed configs for each arch subdir of those | ||
| 544 | specified as compatible for the current machine. | ||
| 545 | NOTE: Development-helper feature, NOT a full-fledged feed. | ||
| 546 | """ | ||
| 547 | if self.d.has_key('FEED_DEPLOYDIR_BASE_URI'): | ||
| 548 | feed_deploydir_base_dir = self.d['FEED_DEPLOYDIR_BASE_URI'] | ||
| 549 | else: | ||
| 550 | feed_deploydir_base_dir = "" | ||
| 551 | |||
| 552 | if feed_deploydir_base_dir != "": | ||
| 553 | for arch in self.pkg_archs.split(): | ||
| 554 | if self.d.has_key("sysconfdir"): | ||
| 555 | sysconfdir = self.d["sysconfdir"] | ||
| 556 | else: | ||
| 557 | sysconfdir = None | ||
| 558 | |||
| 559 | cfg_file_name = os.path.join(self.target_rootfs, | ||
| 560 | sysconfdir, | ||
| 561 | "opkg", | ||
| 562 | "local-%s-feed.conf" % arch) | ||
| 563 | |||
| 564 | with open(cfg_file_name, "w+") as cfg_file: | ||
| 565 | cfg_file.write("src/gz local-%s %s/%s" % | ||
| 566 | arch, | ||
| 567 | feed_deploydir_base_dir, | ||
| 568 | arch) | ||
| 569 | |||
| 570 | def _create_config(self): | ||
| 571 | with open(self.config_file, "w+") as config_file: | ||
| 572 | priority = 1 | ||
| 573 | for arch in self.pkg_archs.split(): | ||
| 574 | config_file.write("arch %s %d\n" % (arch, priority)) | ||
| 575 | priority += 5 | ||
| 576 | |||
| 577 | config_file.write("src oe file:%s\n" % self.deploy_dir) | ||
| 578 | |||
| 579 | for arch in self.pkg_archs.split(): | ||
| 580 | pkgs_dir = os.path.join(self.deploy_dir, arch) | ||
| 581 | if os.path.isdir(pkgs_dir): | ||
| 582 | config_file.write("src oe-%s file:%s\n" % | ||
| 583 | (arch, pkgs_dir)) | ||
| 584 | |||
| 585 | def insert_feeds_uris(self): | ||
| 586 | if self.feed_uris == "": | ||
| 587 | return | ||
| 588 | |||
| 589 | rootfs_config = os.path.join('%s/etc/opkg/base-feeds.conf' | ||
| 590 | % self.target_rootfs) | ||
| 591 | |||
| 592 | with open(rootfs_config, "w+") as config_file: | ||
| 593 | uri_iterator = 0 | ||
| 594 | for uri in self.feed_uris.split(): | ||
| 595 | config_file.write("src/gz url-%d %s/ipk\n" % | ||
| 596 | (uri_iterator, uri)) | ||
| 597 | |||
| 598 | for arch in self.pkg_archs.split(): | ||
| 599 | if not os.path.exists(os.path.join(self.deploy_dir, arch)): | ||
| 600 | continue | ||
| 601 | msger.info('Note: adding opkg channel url-%s-%d (%s)' % | ||
| 602 | (arch, uri_iterator, uri)) | ||
| 603 | |||
| 604 | config_file.write("src/gz uri-%s-%d %s/ipk/%s\n" % | ||
| 605 | (arch, uri_iterator, uri, arch)) | ||
| 606 | uri_iterator += 1 | ||
| 607 | |||
| 608 | def update(self): | ||
| 609 | self.deploy_dir_lock() | ||
| 610 | |||
| 611 | cmd = "%s %s update" % (self.opkg_cmd, self.opkg_args) | ||
| 612 | |||
| 613 | rc, out = exec_native_cmd(self.pseudo + cmd, self.native_sysroot) | ||
| 614 | if rc != 0: | ||
| 615 | self.deploy_dir_unlock() | ||
| 616 | msger.error("Unable to update the package index files. Command '%s' " | ||
| 617 | "returned %d" % (cmd, rc)) | ||
| 618 | |||
| 619 | self.deploy_dir_unlock() | ||
| 620 | |||
| 621 | def install(self, pkgs, attempt_only=False): | ||
| 622 | if attempt_only and len(pkgs) == 0: | ||
| 623 | return | ||
| 624 | |||
| 625 | cmd = "%s %s install %s" % (self.opkg_cmd, self.opkg_args, ' '.join(pkgs)) | ||
| 626 | |||
| 627 | os.environ['D'] = self.target_rootfs | ||
| 628 | os.environ['OFFLINE_ROOT'] = self.target_rootfs | ||
| 629 | os.environ['IPKG_OFFLINE_ROOT'] = self.target_rootfs | ||
| 630 | os.environ['OPKG_OFFLINE_ROOT'] = self.target_rootfs | ||
| 631 | if self.d.has_key('WORKDIR'): | ||
| 632 | os.environ['INTERCEPT_DIR'] = os.path.join(self.d['WORKDIR'], | ||
| 633 | "intercept_scripts") | ||
| 634 | else: | ||
| 635 | os.environ['INTERCEPT_DIR'] = "." | ||
| 636 | msger.warning("No WORKDIR provided!") | ||
| 637 | |||
| 638 | if self.d.has_key('STAGING_DIR_NATIVE'): | ||
| 639 | os.environ['NATIVE_ROOT'] = self.d['STAGING_DIR_NATIVE'] | ||
| 640 | else: | ||
| 641 | msger.error("No STAGING_DIR_NATIVE provided!") | ||
| 642 | |||
| 643 | rc, out = exec_native_cmd(self.pseudo + cmd, self.native_sysroot) | ||
| 644 | if rc != 0: | ||
| 645 | msger.error("Unable to install packages. " | ||
| 646 | "Command '%s' returned %d" % (cmd, rc)) | ||
| 647 | |||
| 648 | |||
| 649 | def remove(self, pkgs, with_dependencies=True): | ||
| 650 | if with_dependencies: | ||
| 651 | cmd = "%s %s --force-depends --force-remove --force-removal-of-dependent-packages remove %s" % \ | ||
| 652 | (self.opkg_cmd, self.opkg_args, ' '.join(pkgs)) | ||
| 653 | else: | ||
| 654 | cmd = "%s %s --force-depends remove %s" % \ | ||
| 655 | (self.opkg_cmd, self.opkg_args, ' '.join(pkgs)) | ||
| 656 | |||
| 657 | rc, out = exec_native_cmd(self.pseudo + cmd, self.native_sysroot) | ||
| 658 | if rc != 0: | ||
| 659 | msger.error("Unable to remove packages. Command '%s' " | ||
| 660 | "returned %d" % (cmd, rc)) | ||
| 661 | |||
| 662 | |||
| 663 | def write_index(self): | ||
| 664 | self.deploy_dir_lock() | ||
| 665 | |||
| 666 | result = self.indexer.write_index() | ||
| 667 | |||
| 668 | self.deploy_dir_unlock() | ||
| 669 | |||
| 670 | if result is not None: | ||
| 671 | msger.error(result) | ||
| 672 | |||
| 673 | def remove_packaging_data(self): | ||
| 674 | remove(self.opkg_dir, True) | ||
| 675 | # create the directory back, it's needed by PM lock | ||
| 676 | mkdirhier(self.opkg_dir) | ||
| 677 | |||
| 678 | def list_installed(self, format=None): | ||
| 679 | return WicOpkgPkgsList(self.d, self.target_rootfs, self.config_file).list(format) | ||
| 680 | |||
| 681 | def handle_bad_recommendations(self): | ||
| 682 | if self.d.has_key("BAD_RECOMMENDATIONS"): | ||
| 683 | bad_recommendations = self.d["BAD_RECOMMENDATIONS"] | ||
| 684 | else: | ||
| 685 | bad_recommendations = "" | ||
| 686 | |||
| 687 | if bad_recommendations.strip() == "": | ||
| 688 | return | ||
| 689 | |||
| 690 | status_file = os.path.join(self.opkg_dir, "status") | ||
| 691 | |||
| 692 | # If status file existed, it means the bad recommendations has already | ||
| 693 | # been handled | ||
| 694 | if os.path.exists(status_file): | ||
| 695 | return | ||
| 696 | |||
| 697 | cmd = "%s %s info " % (self.opkg_cmd, self.opkg_args) | ||
| 698 | |||
| 699 | with open(status_file, "w+") as status: | ||
| 700 | for pkg in bad_recommendations.split(): | ||
| 701 | pkg_info = cmd + pkg | ||
| 702 | |||
| 703 | try: | ||
| 704 | output = subprocess.check_output(pkg_info.split(), stderr=subprocess.STDOUT).strip() | ||
| 705 | except subprocess.CalledProcessError as e: | ||
| 706 | msger.error("Cannot get package info. Command '%s' " | ||
| 707 | "returned %d:\n%s" % (pkg_info, e.returncode, e.output)) | ||
| 708 | |||
| 709 | if output == "": | ||
| 710 | msger.info("Ignored bad recommendation: '%s' is " | ||
| 711 | "not a package" % pkg) | ||
| 712 | continue | ||
| 713 | |||
| 714 | for line in output.split('\n'): | ||
| 715 | if line.startswith("Status:"): | ||
| 716 | status.write("Status: deinstall hold not-installed\n") | ||
| 717 | else: | ||
| 718 | status.write(line + "\n") | ||
| 719 | |||
| 720 | ''' | ||
| 721 | The following function dummy installs pkgs and returns the log of output. | ||
| 722 | ''' | ||
| 723 | def dummy_install(self, pkgs): | ||
| 724 | if len(pkgs) == 0: | ||
| 725 | return | ||
| 726 | |||
| 727 | # Create an temp dir as opkg root for dummy installation | ||
| 728 | if self.d.has_key("TMPDIR"): | ||
| 729 | tmp_dir = self.d["TMPDIR"] | ||
| 730 | else: | ||
| 731 | tmp_dir = "." | ||
| 732 | msger.warning("No TMPDIR provided!") | ||
| 733 | |||
| 734 | temp_rootfs = '%s/opkg' % tmp_dir | ||
| 735 | temp_opkg_dir = os.path.join(temp_rootfs, 'var/lib/opkg') | ||
| 736 | mkdirhier(temp_opkg_dir) | ||
| 737 | |||
| 738 | opkg_args = "-f %s -o %s " % (self.config_file, temp_rootfs) | ||
| 739 | if self.d.has_key("OPKG_ARGS"): | ||
| 740 | opkg_args += self.d["OPKG_ARGS"] | ||
| 741 | |||
| 742 | cmd = "%s %s update" % (self.opkg_cmd, opkg_args) | ||
| 743 | try: | ||
| 744 | subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) | ||
| 745 | except subprocess.CalledProcessError as e: | ||
| 746 | msger.error("Unable to update. Command '%s' " | ||
| 747 | "returned %d:\n%s" % (cmd, e.returncode, e.output)) | ||
| 748 | |||
| 749 | # Dummy installation | ||
| 750 | cmd = "%s %s --noaction install %s " % (self.opkg_cmd, | ||
| 751 | opkg_args, | ||
| 752 | ' '.join(pkgs)) | ||
| 753 | try: | ||
| 754 | output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) | ||
| 755 | except subprocess.CalledProcessError as e: | ||
| 756 | msger.error("Unable to dummy install packages. Command '%s' " | ||
| 757 | "returned %d:\n%s" % (cmd, e.returncode, e.output)) | ||
| 758 | |||
| 759 | remove(temp_rootfs, True) | ||
| 760 | |||
| 761 | return output | ||
| 762 | |||
| 763 | def backup_packaging_data(self): | ||
| 764 | # Save the opkglib for increment ipk image generation | ||
| 765 | if os.path.exists(self.saved_opkg_dir): | ||
| 766 | remove(self.saved_opkg_dir, True) | ||
| 767 | shutil.copytree(self.opkg_dir, | ||
| 768 | self.saved_opkg_dir, | ||
| 769 | symlinks=True) | ||
| 770 | |||
| 771 | def recover_packaging_data(self): | ||
| 772 | # Move the opkglib back | ||
| 773 | if os.path.exists(self.saved_opkg_dir): | ||
| 774 | if os.path.exists(self.opkg_dir): | ||
| 775 | remove(self.opkg_dir, True) | ||
| 776 | |||
| 777 | msger.info('Recover packaging data') | ||
| 778 | shutil.copytree(self.saved_opkg_dir, | ||
| 779 | self.opkg_dir, | ||
| 780 | symlinks=True) | ||
| 781 | |||
| 782 | |||
| 783 | def wic_generate_index_files(d): | ||
| 784 | if d.has_key('PACKAGE_CLASSES'): | ||
| 785 | classes = d['PACKAGE_CLASSES'].replace("package_", "").split() | ||
| 786 | else: | ||
| 787 | classes = "" | ||
| 788 | msger.warning("No PACKAGE_CLASSES provided!") | ||
| 789 | |||
| 790 | if d.has_key('DEPLOY_DIR_IPK'): | ||
| 791 | deploy_dir_ipk = d['DEPLOY_DIR_IPK'] | ||
| 792 | else: | ||
| 793 | deploy_dir_ipk = None | ||
| 794 | msger.warning("No DEPLOY_DIR_IPK provided!") | ||
| 795 | |||
| 796 | indexer_map = { | ||
| 797 | "ipk": (WicOpkgIndexer, deploy_dir_ipk) | ||
| 798 | } | ||
| 799 | |||
| 800 | result = None | ||
| 801 | |||
| 802 | for pkg_class in classes: | ||
| 803 | if not pkg_class in indexer_map: | ||
| 804 | continue | ||
| 805 | |||
| 806 | if os.path.exists(indexer_map[pkg_class][1]): | ||
| 807 | result = indexer_map[pkg_class][0](d, indexer_map[pkg_class][1]).write_index() | ||
| 808 | |||
| 809 | if result is not None: | ||
| 810 | msger.error(result) | ||
diff --git a/scripts/lib/wic/utils/partitionedfs.py b/scripts/lib/wic/utils/partitionedfs.py new file mode 100644 index 0000000000..fb95cc790e --- /dev/null +++ b/scripts/lib/wic/utils/partitionedfs.py | |||
| @@ -0,0 +1,360 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2009, 2010, 2011 Intel, Inc. | ||
| 4 | # Copyright (c) 2007, 2008 Red Hat, Inc. | ||
| 5 | # Copyright (c) 2008 Daniel P. Berrange | ||
| 6 | # Copyright (c) 2008 David P. Huff | ||
| 7 | # | ||
| 8 | # This program is free software; you can redistribute it and/or modify it | ||
| 9 | # under the terms of the GNU General Public License as published by the Free | ||
| 10 | # Software Foundation; version 2 of the License | ||
| 11 | # | ||
| 12 | # This program is distributed in the hope that it will be useful, but | ||
| 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 14 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 15 | # for more details. | ||
| 16 | # | ||
| 17 | # You should have received a copy of the GNU General Public License along | ||
| 18 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 19 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 20 | |||
| 21 | import os | ||
| 22 | |||
| 23 | from wic import msger | ||
| 24 | from wic.utils import runner | ||
| 25 | from wic.utils.errors import ImageError | ||
| 26 | from wic.utils.fs_related import * | ||
| 27 | from wic.utils.oe.misc import * | ||
| 28 | |||
| 29 | # Overhead of the MBR partitioning scheme (just one sector) | ||
| 30 | MBR_OVERHEAD = 1 | ||
| 31 | |||
| 32 | # Size of a sector in bytes | ||
| 33 | SECTOR_SIZE = 512 | ||
| 34 | |||
| 35 | class Image: | ||
| 36 | """ | ||
| 37 | Generic base object for an image. | ||
| 38 | |||
| 39 | An Image is a container for a set of DiskImages and associated | ||
| 40 | partitions. | ||
| 41 | """ | ||
| 42 | def __init__(self): | ||
| 43 | self.disks = {} | ||
| 44 | self.partitions = [] | ||
| 45 | self.parted = find_binary_path("parted") | ||
| 46 | # Size of a sector used in calculations | ||
| 47 | self.sector_size = SECTOR_SIZE | ||
| 48 | self._partitions_layed_out = False | ||
| 49 | |||
| 50 | def __add_disk(self, disk_name): | ||
| 51 | """ Add a disk 'disk_name' to the internal list of disks. Note, | ||
| 52 | 'disk_name' is the name of the disk in the target system | ||
| 53 | (e.g., sdb). """ | ||
| 54 | |||
| 55 | if disk_name in self.disks: | ||
| 56 | # We already have this disk | ||
| 57 | return | ||
| 58 | |||
| 59 | assert not self._partitions_layed_out | ||
| 60 | |||
| 61 | self.disks[disk_name] = \ | ||
| 62 | { 'disk': None, # Disk object | ||
| 63 | 'numpart': 0, # Number of allocate partitions | ||
| 64 | 'partitions': [], # Indexes to self.partitions | ||
| 65 | 'offset': 0, # Offset of next partition (in sectors) | ||
| 66 | # Minimum required disk size to fit all partitions (in bytes) | ||
| 67 | 'min_size': 0, | ||
| 68 | 'ptable_format': "msdos" } # Partition table format | ||
| 69 | |||
| 70 | def add_disk(self, disk_name, disk_obj): | ||
| 71 | """ Add a disk object which have to be partitioned. More than one disk | ||
| 72 | can be added. In case of multiple disks, disk partitions have to be | ||
| 73 | added for each disk separately with 'add_partition()". """ | ||
| 74 | |||
| 75 | self.__add_disk(disk_name) | ||
| 76 | self.disks[disk_name]['disk'] = disk_obj | ||
| 77 | |||
| 78 | def __add_partition(self, part): | ||
| 79 | """ This is a helper function for 'add_partition()' which adds a | ||
| 80 | partition to the internal list of partitions. """ | ||
| 81 | |||
| 82 | assert not self._partitions_layed_out | ||
| 83 | |||
| 84 | self.partitions.append(part) | ||
| 85 | self.__add_disk(part['disk_name']) | ||
| 86 | |||
| 87 | def add_partition(self, size, disk_name, mountpoint, source_file = None, fstype = None, | ||
| 88 | label=None, fsopts = None, boot = False, align = None, | ||
| 89 | part_type = None): | ||
| 90 | """ Add the next partition. Prtitions have to be added in the | ||
| 91 | first-to-last order. """ | ||
| 92 | |||
| 93 | ks_pnum = len(self.partitions) | ||
| 94 | |||
| 95 | # Converting MB to sectors for parted | ||
| 96 | size = size * 1024 * 1024 / self.sector_size | ||
| 97 | |||
| 98 | # We still need partition for "/" or non-subvolume | ||
| 99 | if mountpoint == "/" or not fsopts: | ||
| 100 | part = { 'ks_pnum' : ks_pnum, # Partition number in the KS file | ||
| 101 | 'size': size, # In sectors | ||
| 102 | 'mountpoint': mountpoint, # Mount relative to chroot | ||
| 103 | 'source_file': source_file, # partition contents | ||
| 104 | 'fstype': fstype, # Filesystem type | ||
| 105 | 'fsopts': fsopts, # Filesystem mount options | ||
| 106 | 'label': label, # Partition label | ||
| 107 | 'disk_name': disk_name, # physical disk name holding partition | ||
| 108 | 'device': None, # kpartx device node for partition | ||
| 109 | 'num': None, # Partition number | ||
| 110 | 'boot': boot, # Bootable flag | ||
| 111 | 'align': align, # Partition alignment | ||
| 112 | 'part_type' : part_type } # Partition type | ||
| 113 | |||
| 114 | self.__add_partition(part) | ||
| 115 | |||
| 116 | def layout_partitions(self, ptable_format = "msdos"): | ||
| 117 | """ Layout the partitions, meaning calculate the position of every | ||
| 118 | partition on the disk. The 'ptable_format' parameter defines the | ||
| 119 | partition table format and may be "msdos". """ | ||
| 120 | |||
| 121 | msger.debug("Assigning %s partitions to disks" % ptable_format) | ||
| 122 | |||
| 123 | if ptable_format not in ('msdos'): | ||
| 124 | raise ImageError("Unknown partition table format '%s', supported " \ | ||
| 125 | "formats are: 'msdos'" % ptable_format) | ||
| 126 | |||
| 127 | if self._partitions_layed_out: | ||
| 128 | return | ||
| 129 | |||
| 130 | self._partitions_layed_out = True | ||
| 131 | |||
| 132 | # Go through partitions in the order they are added in .ks file | ||
| 133 | for n in range(len(self.partitions)): | ||
| 134 | p = self.partitions[n] | ||
| 135 | |||
| 136 | if not self.disks.has_key(p['disk_name']): | ||
| 137 | raise ImageError("No disk %s for partition %s" \ | ||
| 138 | % (p['disk_name'], p['mountpoint'])) | ||
| 139 | |||
| 140 | if p['part_type']: | ||
| 141 | # The --part-type can also be implemented for MBR partitions, | ||
| 142 | # in which case it would map to the 1-byte "partition type" | ||
| 143 | # filed at offset 3 of the partition entry. | ||
| 144 | raise ImageError("setting custom partition type is not " \ | ||
| 145 | "implemented for msdos partitions") | ||
| 146 | |||
| 147 | # Get the disk where the partition is located | ||
| 148 | d = self.disks[p['disk_name']] | ||
| 149 | d['numpart'] += 1 | ||
| 150 | d['ptable_format'] = ptable_format | ||
| 151 | |||
| 152 | if d['numpart'] == 1: | ||
| 153 | if ptable_format == "msdos": | ||
| 154 | overhead = MBR_OVERHEAD | ||
| 155 | |||
| 156 | # Skip one sector required for the partitioning scheme overhead | ||
| 157 | d['offset'] += overhead | ||
| 158 | |||
| 159 | if p['align']: | ||
| 160 | # If not first partition and we do have alignment set we need | ||
| 161 | # to align the partition. | ||
| 162 | # FIXME: This leaves a empty spaces to the disk. To fill the | ||
| 163 | # gaps we could enlargea the previous partition? | ||
| 164 | |||
| 165 | # Calc how much the alignment is off. | ||
| 166 | align_sectors = d['offset'] % (p['align'] * 1024 / self.sector_size) | ||
| 167 | |||
| 168 | if align_sectors: | ||
| 169 | # If partition is not aligned as required, we need | ||
| 170 | # to move forward to the next alignment point | ||
| 171 | align_sectors = (p['align'] * 1024 / self.sector_size) - align_sectors | ||
| 172 | |||
| 173 | msger.debug("Realignment for %s%s with %s sectors, original" | ||
| 174 | " offset %s, target alignment is %sK." % | ||
| 175 | (p['disk_name'], d['numpart'], align_sectors, | ||
| 176 | d['offset'], p['align'])) | ||
| 177 | |||
| 178 | # increase the offset so we actually start the partition on right alignment | ||
| 179 | d['offset'] += align_sectors | ||
| 180 | |||
| 181 | p['start'] = d['offset'] | ||
| 182 | d['offset'] += p['size'] | ||
| 183 | |||
| 184 | p['type'] = 'primary' | ||
| 185 | p['num'] = d['numpart'] | ||
| 186 | |||
| 187 | if d['ptable_format'] == "msdos": | ||
| 188 | if d['numpart'] > 2: | ||
| 189 | # Every logical partition requires an additional sector for | ||
| 190 | # the EBR, so steal the last sector from the end of each | ||
| 191 | # partition starting from the 3rd one for the EBR. This | ||
| 192 | # will make sure the logical partitions are aligned | ||
| 193 | # correctly. | ||
| 194 | p['size'] -= 1 | ||
| 195 | |||
| 196 | if d['numpart'] > 3: | ||
| 197 | p['type'] = 'logical' | ||
| 198 | p['num'] = d['numpart'] + 1 | ||
| 199 | |||
| 200 | d['partitions'].append(n) | ||
| 201 | msger.debug("Assigned %s to %s%d, sectors range %d-%d size %d " | ||
| 202 | "sectors (%d bytes)." \ | ||
| 203 | % (p['mountpoint'], p['disk_name'], p['num'], | ||
| 204 | p['start'], p['start'] + p['size'] - 1, | ||
| 205 | p['size'], p['size'] * self.sector_size)) | ||
| 206 | |||
| 207 | # Once all the partitions have been layed out, we can calculate the | ||
| 208 | # minumim disk sizes. | ||
| 209 | for disk_name, d in self.disks.items(): | ||
| 210 | d['min_size'] = d['offset'] | ||
| 211 | |||
| 212 | d['min_size'] *= self.sector_size | ||
| 213 | |||
| 214 | def __run_parted(self, args): | ||
| 215 | """ Run parted with arguments specified in the 'args' list. """ | ||
| 216 | |||
| 217 | args.insert(0, self.parted) | ||
| 218 | msger.debug(args) | ||
| 219 | |||
| 220 | rc, out = runner.runtool(args, catch = 3) | ||
| 221 | out = out.strip() | ||
| 222 | if out: | ||
| 223 | msger.debug('"parted" output: %s' % out) | ||
| 224 | |||
| 225 | if rc != 0: | ||
| 226 | # We don't throw exception when return code is not 0, because | ||
| 227 | # parted always fails to reload part table with loop devices. This | ||
| 228 | # prevents us from distinguishing real errors based on return | ||
| 229 | # code. | ||
| 230 | msger.error("WARNING: parted returned '%s' instead of 0 (use --debug for details)" % rc) | ||
| 231 | |||
| 232 | def __create_partition(self, device, parttype, fstype, start, size): | ||
| 233 | """ Create a partition on an image described by the 'device' object. """ | ||
| 234 | |||
| 235 | # Start is included to the size so we need to substract one from the end. | ||
| 236 | end = start + size - 1 | ||
| 237 | msger.debug("Added '%s' partition, sectors %d-%d, size %d sectors" % | ||
| 238 | (parttype, start, end, size)) | ||
| 239 | |||
| 240 | args = ["-s", device, "unit", "s", "mkpart", parttype] | ||
| 241 | if fstype: | ||
| 242 | args.extend([fstype]) | ||
| 243 | args.extend(["%d" % start, "%d" % end]) | ||
| 244 | |||
| 245 | return self.__run_parted(args) | ||
| 246 | |||
| 247 | def __format_disks(self): | ||
| 248 | self.layout_partitions() | ||
| 249 | |||
| 250 | for dev in self.disks.keys(): | ||
| 251 | d = self.disks[dev] | ||
| 252 | msger.debug("Initializing partition table for %s" % \ | ||
| 253 | (d['disk'].device)) | ||
| 254 | self.__run_parted(["-s", d['disk'].device, "mklabel", | ||
| 255 | d['ptable_format']]) | ||
| 256 | |||
| 257 | msger.debug("Creating partitions") | ||
| 258 | |||
| 259 | for p in self.partitions: | ||
| 260 | d = self.disks[p['disk_name']] | ||
| 261 | if d['ptable_format'] == "msdos" and p['num'] == 5: | ||
| 262 | # The last sector of the 3rd partition was reserved for the EBR | ||
| 263 | # of the first _logical_ partition. This is why the extended | ||
| 264 | # partition should start one sector before the first logical | ||
| 265 | # partition. | ||
| 266 | self.__create_partition(d['disk'].device, "extended", | ||
| 267 | None, p['start'] - 1, | ||
| 268 | d['offset'] - p['start']) | ||
| 269 | |||
| 270 | if p['fstype'] == "swap": | ||
| 271 | parted_fs_type = "linux-swap" | ||
| 272 | elif p['fstype'] == "vfat": | ||
| 273 | parted_fs_type = "fat32" | ||
| 274 | elif p['fstype'] == "msdos": | ||
| 275 | parted_fs_type = "fat16" | ||
| 276 | else: | ||
| 277 | # Type for ext2/ext3/ext4/btrfs | ||
| 278 | parted_fs_type = "ext2" | ||
| 279 | |||
| 280 | # Boot ROM of OMAP boards require vfat boot partition to have an | ||
| 281 | # even number of sectors. | ||
| 282 | if p['mountpoint'] == "/boot" and p['fstype'] in ["vfat", "msdos"] \ | ||
| 283 | and p['size'] % 2: | ||
| 284 | msger.debug("Substracting one sector from '%s' partition to " \ | ||
| 285 | "get even number of sectors for the partition" % \ | ||
| 286 | p['mountpoint']) | ||
| 287 | p['size'] -= 1 | ||
| 288 | |||
| 289 | self.__create_partition(d['disk'].device, p['type'], | ||
| 290 | parted_fs_type, p['start'], p['size']) | ||
| 291 | |||
| 292 | if p['boot']: | ||
| 293 | flag_name = "boot" | ||
| 294 | msger.debug("Set '%s' flag for partition '%s' on disk '%s'" % \ | ||
| 295 | (flag_name, p['num'], d['disk'].device)) | ||
| 296 | self.__run_parted(["-s", d['disk'].device, "set", | ||
| 297 | "%d" % p['num'], flag_name, "on"]) | ||
| 298 | |||
| 299 | # Parted defaults to enabling the lba flag for fat16 partitions, | ||
| 300 | # which causes compatibility issues with some firmware (and really | ||
| 301 | # isn't necessary). | ||
| 302 | if parted_fs_type == "fat16": | ||
| 303 | if d['ptable_format'] == 'msdos': | ||
| 304 | msger.debug("Disable 'lba' flag for partition '%s' on disk '%s'" % \ | ||
| 305 | (p['num'], d['disk'].device)) | ||
| 306 | self.__run_parted(["-s", d['disk'].device, "set", | ||
| 307 | "%d" % p['num'], "lba", "off"]) | ||
| 308 | |||
| 309 | def cleanup(self): | ||
| 310 | if self.disks: | ||
| 311 | for dev in self.disks.keys(): | ||
| 312 | d = self.disks[dev] | ||
| 313 | try: | ||
| 314 | d['disk'].cleanup() | ||
| 315 | except: | ||
| 316 | pass | ||
| 317 | |||
| 318 | def __write_partition(self, num, source_file, start, size): | ||
| 319 | """ | ||
| 320 | Install source_file contents into a partition. | ||
| 321 | """ | ||
| 322 | if not source_file: # nothing to write | ||
| 323 | return | ||
| 324 | |||
| 325 | # Start is included in the size so need to substract one from the end. | ||
| 326 | end = start + size - 1 | ||
| 327 | msger.debug("Installed %s in partition %d, sectors %d-%d, size %d sectors" % (source_file, num, start, end, size)) | ||
| 328 | |||
| 329 | dd_cmd = "dd if=%s of=%s bs=%d seek=%d count=%d conv=notrunc" % \ | ||
| 330 | (source_file, self.image_file, self.sector_size, start, size) | ||
| 331 | exec_cmd(dd_cmd) | ||
| 332 | |||
| 333 | |||
| 334 | def assemble(self, image_file): | ||
| 335 | msger.debug("Installing partitions") | ||
| 336 | |||
| 337 | self.image_file = image_file | ||
| 338 | |||
| 339 | for p in self.partitions: | ||
| 340 | d = self.disks[p['disk_name']] | ||
| 341 | if d['ptable_format'] == "msdos" and p['num'] == 5: | ||
| 342 | # The last sector of the 3rd partition was reserved for the EBR | ||
| 343 | # of the first _logical_ partition. This is why the extended | ||
| 344 | # partition should start one sector before the first logical | ||
| 345 | # partition. | ||
| 346 | self.__write_partition(p['num'], p['source_file'], | ||
| 347 | p['start'] - 1, | ||
| 348 | d['offset'] - p['start']) | ||
| 349 | |||
| 350 | self.__write_partition(p['num'], p['source_file'], | ||
| 351 | p['start'], p['size']) | ||
| 352 | |||
| 353 | def create(self): | ||
| 354 | for dev in self.disks.keys(): | ||
| 355 | d = self.disks[dev] | ||
| 356 | d['disk'].create() | ||
| 357 | |||
| 358 | self.__format_disks() | ||
| 359 | |||
| 360 | return | ||
diff --git a/scripts/lib/wic/utils/runner.py b/scripts/lib/wic/utils/runner.py new file mode 100644 index 0000000000..2ae9f417c5 --- /dev/null +++ b/scripts/lib/wic/utils/runner.py | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | #!/usr/bin/env python -tt | ||
| 2 | # | ||
| 3 | # Copyright (c) 2011 Intel, Inc. | ||
| 4 | # | ||
| 5 | # This program is free software; you can redistribute it and/or modify it | ||
| 6 | # under the terms of the GNU General Public License as published by the Free | ||
| 7 | # Software Foundation; version 2 of the License | ||
| 8 | # | ||
| 9 | # This program is distributed in the hope that it will be useful, but | ||
| 10 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| 11 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| 12 | # for more details. | ||
| 13 | # | ||
| 14 | # You should have received a copy of the GNU General Public License along | ||
| 15 | # with this program; if not, write to the Free Software Foundation, Inc., 59 | ||
| 16 | # Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 17 | |||
| 18 | import os | ||
| 19 | import subprocess | ||
| 20 | |||
| 21 | from wic import msger | ||
| 22 | |||
| 23 | def runtool(cmdln_or_args, catch=1): | ||
| 24 | """ wrapper for most of the subprocess calls | ||
| 25 | input: | ||
| 26 | cmdln_or_args: can be both args and cmdln str (shell=True) | ||
| 27 | catch: 0, quitely run | ||
| 28 | 1, only STDOUT | ||
| 29 | 2, only STDERR | ||
| 30 | 3, both STDOUT and STDERR | ||
| 31 | return: | ||
| 32 | (rc, output) | ||
| 33 | if catch==0: the output will always None | ||
| 34 | """ | ||
| 35 | |||
| 36 | if catch not in (0, 1, 2, 3): | ||
| 37 | # invalid catch selection, will cause exception, that's good | ||
| 38 | return None | ||
| 39 | |||
| 40 | if isinstance(cmdln_or_args, list): | ||
| 41 | cmd = cmdln_or_args[0] | ||
| 42 | shell = False | ||
| 43 | else: | ||
| 44 | import shlex | ||
| 45 | cmd = shlex.split(cmdln_or_args)[0] | ||
| 46 | shell = True | ||
| 47 | |||
| 48 | if catch != 3: | ||
| 49 | dev_null = os.open("/dev/null", os.O_WRONLY) | ||
| 50 | |||
| 51 | if catch == 0: | ||
| 52 | sout = dev_null | ||
| 53 | serr = dev_null | ||
| 54 | elif catch == 1: | ||
| 55 | sout = subprocess.PIPE | ||
| 56 | serr = dev_null | ||
| 57 | elif catch == 2: | ||
| 58 | sout = dev_null | ||
| 59 | serr = subprocess.PIPE | ||
| 60 | elif catch == 3: | ||
| 61 | sout = subprocess.PIPE | ||
| 62 | serr = subprocess.STDOUT | ||
| 63 | |||
| 64 | try: | ||
| 65 | p = subprocess.Popen(cmdln_or_args, stdout=sout, | ||
| 66 | stderr=serr, shell=shell) | ||
| 67 | (sout, serr) = p.communicate() | ||
| 68 | # combine stdout and stderr, filter None out | ||
| 69 | out = ''.join(filter(None, [sout, serr])) | ||
| 70 | except OSError, e: | ||
| 71 | if e.errno == 2: | ||
| 72 | # [Errno 2] No such file or directory | ||
| 73 | msger.error('Cannot run command: %s, lost dependency?' % cmd) | ||
| 74 | else: | ||
| 75 | raise # relay | ||
| 76 | finally: | ||
| 77 | if catch != 3: | ||
| 78 | os.close(dev_null) | ||
| 79 | |||
| 80 | return (p.returncode, out) | ||
| 81 | |||
| 82 | def show(cmdln_or_args): | ||
| 83 | # show all the message using msger.verbose | ||
| 84 | |||
| 85 | rc, out = runtool(cmdln_or_args, catch=3) | ||
| 86 | |||
| 87 | if isinstance(cmdln_or_args, list): | ||
| 88 | cmd = ' '.join(cmdln_or_args) | ||
| 89 | else: | ||
| 90 | cmd = cmdln_or_args | ||
| 91 | |||
| 92 | msg = 'running command: "%s"' % cmd | ||
| 93 | if out: out = out.strip() | ||
| 94 | if out: | ||
| 95 | msg += ', with output::' | ||
| 96 | msg += '\n +----------------' | ||
| 97 | for line in out.splitlines(): | ||
| 98 | msg += '\n | %s' % line | ||
| 99 | msg += '\n +----------------' | ||
| 100 | |||
| 101 | msger.verbose(msg) | ||
| 102 | return rc | ||
| 103 | |||
| 104 | def outs(cmdln_or_args, catch=1): | ||
| 105 | # get the outputs of tools | ||
| 106 | return runtool(cmdln_or_args, catch)[1].strip() | ||
| 107 | |||
| 108 | def quiet(cmdln_or_args): | ||
| 109 | return runtool(cmdln_or_args, catch=0)[0] | ||
