1############################################################################### 2# Copyright (c) 2013 INRIA 3# Copyright (c) 2019 Mishal Shah (added search, getconf, install options) 4# 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License version 2 as 7# published by the Free Software Foundation; 8# 9# This program is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License 15# along with this program; if not, write to the Free Software 16# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17# 18# Authors: Daniel Camara <daniel.camara@inria.fr> 19# Mathieu Lacage <mathieu.lacage@sophia.inria.fr> 20# Mishal Shah <shahmishal1998@gmail.com> 21############################################################################### 22''' 23 Bake.py 24 25 This is the main Bake file, it stores all the classes related to the 26 basic Bake operation. The class Bake is responsible to identify and 27 execute the defined options 28''' 29 30import xml.etree.ElementTree as ET 31try: 32 from xml.etree.ElementTree import ParseError 33except ImportError: 34 from xml.parsers.expat import ExpatError as ParseError 35import sys 36import os 37import distro 38import signal 39import copy 40import requests 41import bake.Utils 42from bake.Configuration import Configuration 43from bake.ModuleEnvironment import ModuleEnvironment 44from bake.ModuleLogger import StdoutModuleLogger, LogfileModuleLogger, LogdirModuleLogger 45from optparse import OptionParser 46from bake.Dependencies import Dependencies, DependencyUnmet 47from bake.Exceptions import MetadataError 48from bake.Utils import ColorTool 49from bake.Exceptions import TaskError 50from bake.ModuleSource import SystemDependency 51from bake.ModuleBuild import NoneModuleBuild 52from bake.Module import ModuleDependency 53from bake.ModuleAppStore import BaseClient 54from bake.Constants import * 55 56 57def signal_handler(signal, frame): 58 """ Handles Ctrl+C keyboard interruptions """ 59 60 print (os.linesep + ' > Bake was aborted! (Ctrl+C)') 61 os._exit(130) 62 63class MyOptionParser(OptionParser): 64 def format_description(self, formatter): 65 import os 66 import sys 67 return self.description % os.path.basename(sys.argv[0]) 68 69 70class Bake: 71 """ Main Bake class """ 72 73 main_options = "" 74 75 def __init__(self): 76 pass 77 78 def _error(self, string): 79 """ Handles hard exceptions, the kind of exceptions Bake should not 80 recover from.""" 81 82 import sys 83 print(' > Error: %s ' % string) 84 if Bake.main_options.debug: 85 import bake.Utils 86 bake.Utils.print_backtrace() 87 else: 88 print(' For more information call Bake with --debug and/or' 89 ' -v, -vvv, for full verbose mode (bake --help)') 90 sys.exit(1) 91 92 def _fix_config(self, config, args): 93 """Handles the fix_cinfig command line option. It intends to fix 94 manually changed files and updates the in-use configuration with 95 new values.""" 96 97 parser = OptionParser(usage='usage: %prog fix-config [options]') 98 self._enable_disable_options(parser) 99 parser.add_option("-f", "--conffile", action="store", type="string", 100 dest="bakeconf", default="bakeconf.xml", 101 help="The Bake meta-data configuration from where to" 102 " get the updated modules file to use. Default: %default.") 103 parser.add_option("--objdir", action="store", type="string", 104 dest="objdir", default=None, 105 help="The per-module directory where the object" 106 " files of each module will be compiled.") 107 parser.add_option("--sourcedir", action="store", type="string", 108 dest="sourcedir", default=None, 109 help="The directory where the source code of all modules " 110 "will be downloaded.") 111 parser.add_option("-i", "--installdir", action="store", type="string", 112 dest="installdir", default=None, 113 help="The directory where all modules will be installed.") 114 115 parser.add_option("-t", "--target-file", action="store", type="string", 116 dest="targetfile", default=None, 117 help="New target file, if not defined Bake" 118 " overwrites the present configuration file.") 119 120 (options, args_left) = parser.parse_args(args) 121 122 if options.bakeconf == "bakeconf.xml": 123 options.bakeconf = self.check_configuration_file(options.bakeconf, False); 124 125 config = self.check_configuration_file(config, True) 126 127 contribconf = [] 128 try: 129 for cfile in os.listdir("contrib"): 130 if cfile.endswith(".xml"): 131 contribconf.append("contrib/"+cfile) 132 except Exception as e: 133 True 134 135 # Stores the present configuration 136 old_config = Configuration(config) 137 old_config.read() 138 139 if options.targetfile: 140 new_config = Configuration(options.targetfile, 141 relative_directory_root=old_config.get_relative_directory_root()) 142 else: 143 new_config = Configuration(config, 144 relative_directory_root=old_config.get_relative_directory_root()) 145 146 147 try: 148 new_config.read_metadata(options.bakeconf) 149 except Exception as e: 150 self._error('Problem reading Configuration file "%s" \n Error: %s' % (options.bakeconf, str(e))) 151 152 for cconf in contribconf: 153 try: 154 new_config.read_metadata(cconf) 155 except Exception as e: 156 self._error('Problem reading Configuration file "%s" \n Error: %s' % (cconf, str(e))) 157 158 # Checks if the directories where set and if so set the new config file 159 # with the new parameters, or let the old ones 160 if options.installdir: 161 new_config.set_installdir(options.installdir) 162 else: 163 new_config.set_installdir(old_config.get_installdir()) 164 if options.objdir: 165 new_config.set_objdir(options.objdir) 166 else: 167 new_config.set_objdir(old_config.get_objdir()) 168 if options.sourcedir: 169 new_config.set_sourcedir(options.sourcedir) 170 else: 171 new_config.set_sourcedir(old_config.get_sourcedir()) 172 173 # copy installed files. 174 for old_module in old_config.modules(): 175 new_module = new_config.lookup(old_module.name()) 176 if new_module is None: 177 # ignore old modules that do not exist in the new configuration 178 continue 179 new_module.installed = old_module.installed 180 181 # copy which modules are enabled into new config 182 for old_module in old_config.enabled(): 183 new_module = new_config.lookup(old_module.name()) 184 if new_module is None: 185 # ignore old enabled modules that do not exist in the new configuration 186 continue 187 new_config.enable(new_module) 188 189 # copy which modules are disabled into new config 190 for old_module in old_config.disabled(): 191 new_module = new_config.lookup(old_module.name()) 192 if new_module is None: 193 # ignore old disabled modules that do not exist in the new configuration 194 continue 195 new_config.disable(new_module) 196 197 # now, parse new enabled/disabled options 198 self._parse_enable_disable(options, new_config) 199 200 # copy old variables into new config for all modules 201 for old_module in old_config.modules(): 202 new_module = new_config.lookup(old_module.name()) 203 if new_module is None: 204 # ignore old modules that do not exist in the new configuration 205 continue 206 old_build = old_module.get_build() 207 new_build = new_module.get_build() 208 for old_attribute in old_build.attributes(): 209 if new_build.attribute(old_attribute.value) is None: 210 continue 211 new_build.attribute(old_attribute.name).value = old_attribute.value 212 213 new_config.write() 214 215 def _enable_disable_options(self, parser): 216 """ Allows the parser to recognize --enable and --disable options.""" 217 218 parser.add_option("-e", "--enable", action="append", type="string", 219 dest="enable", default=[], 220 help="A module to enable in the Bake configuration") 221 parser.add_option("-d", "--disable", action="append", type="string", 222 dest="disable", default=[], 223 help="A module to disable in the Bake configuration") 224 parser.add_option("-a", "--enable-all", action="store_true", 225 dest="enable_all", default=None, 226 help="Enable all modules.") 227 parser.add_option("-m", "--enable-minimal", action="store_true", 228 dest="enable_minimal", default=None, 229 help="Disable all non-mandatory dependencies.") 230 231 def resolve_contrib_dependencies (self, module, fmod, configuration): 232 """ Handles the contrib type dependencies""" 233 for dep in module.dependencies (): 234 dep_mod = configuration.lookup (dep._name) 235 if dep_mod.mtype() == "ns-contrib": 236 # Do not prepend contrib prefix to user supplied contrib name more than once 237 if not(module.get_source().attribute("module_directory").value.startswith(fmod + '/contrib')): 238 dep_mod.get_source().attribute("module_directory").value = fmod+'/contrib/'+dep_mod.get_source().attribute("module_directory").value 239 dep_mod.addDependencies(ModuleDependency(fmod, False)) 240 self.resolve_contrib_dependencies (dep_mod, fmod, configuration) 241 242 def _enable(self, enable, configuration): 243 """ Handles the --enable option, setting defined modules as enable.""" 244 for module_name in enable: 245 module = configuration.lookup(module_name) 246 if not module: 247 self._error('Module "%s" not found' % module_name) 248 if module.mtype() == "ns-contrib": 249 found=0 250 fmod = None 251 for mod in enable: 252 if configuration.lookup(mod).mtype() == "ns" and ((mod>=module.minver() and (module.maxver() is None or mod<=module.maxver())) or (mod == "ns-3-dev" and module.maxver() is None)): 253 found+= 1 254 fmod = mod 255 if not found==1: 256 self._error('Module "%s" has unmet dependency: %s' % (module_name, module.minver())) 257 258 # Do not prepend contrib prefix to user supplied contrib name more than once 259 if not(module.get_source().attribute("module_directory").value.startswith(fmod + '/contrib')): 260 module.get_source().attribute("module_directory").value = fmod+'/contrib/'+module.get_source().attribute("module_directory").value 261 262 module.addDependencies(ModuleDependency(fmod, False)) 263 self.resolve_contrib_dependencies (module, fmod, configuration) 264 configuration.enable(module) 265 266 def _disable(self, disable, configuration): 267 """ Handles the --disable option, setting the defined modules as disable.""" 268 269 for module_name in disable: 270 module = configuration.lookup(module_name) 271 if not module: 272 self._error('Module "%s" not found' % module_name) 273 configuration.disable(module) 274 if module.mtype() == "ns": 275 enabled_list = configuration.enabled() 276 for mod in enabled_list: 277 if mod.mtype() == "ns-contrib": 278 configuration.disable(mod) 279 280 def _variables_process(self, items, configuration, is_append): 281 """ Handles the defined configured variables .""" 282 283 for module_name, name, value in items: 284 if module_name: 285 module = configuration.lookup(module_name) 286 if not module: 287 self._error('Module "%s" not found' % module_name) 288 if not module.get_build().attribute(name): 289 self._error('Module "%s" has no attribute "%s"' % 290 (module_name, name)) 291 if is_append: 292 module.get_build().attribute(name).value = \ 293 module.get_build().attribute(name).value + ' ' + value 294 else: 295 module.get_build().attribute(name).value = value 296 else: 297 for module in configuration.modules(): 298 if module.get_build().attribute(name): 299 if is_append and module.get_build().attribute(name).value : 300 module.get_build().attribute(name).value = \ 301 module.get_build().attribute(name).value + ' ' + value 302 else: 303 module.get_build().attribute(name).value = value 304 305 def _parse_enable_disable(self, options, configuration): 306 """ Identify the enabled and disabled options passed as parameters 307 in the configuration. 308 """ 309 310 # enables/disables the explicit enable/disable modules passed as argument 311 self._enable(options.enable, configuration) 312 for mod in options.disable: 313 if not mod in options.enable: 314 self._error('Module "%s" not enabled' % mod) 315 self._disable(options.disable, configuration) 316 317 # if the option -a is used, meaning all the modules should be enabled 318 if options.enable_all: 319 for module in configuration.modules(): 320 configuration.enable(module) 321 322 323 # if the option -m is used, meaning the minimum configuration should be used 324 # it disables all the non mandatory dependencies 325 if options.enable_minimal: 326 enabled = [] 327 def _enabled_iterator(module): 328 """ Assigns the module as enabled.""" 329 enabled.append(module) 330 return True 331 332 self._iterate(configuration, _enabled_iterator, 333 configuration.enabled(), 334 follow_optional=True) 335 enabled_optional = [] 336 def _enabled_optional_iterator(module): 337 enabled_optional.append(module) 338 return True 339 self._iterate(configuration, _enabled_optional_iterator, 340 configuration.enabled(), 341 follow_optional=False) 342 for module in enabled: 343 if not module in enabled_optional: 344 configuration.disable(module) 345 346 def _parse_variable(self, string, configuration): 347 """ Verifies if the module and requested attribute exists.""" 348 349 retval = [] 350 data = string.split(":") 351 352 # if it is an setting for all the modules that contains such variable 353 if len(data) == 1: 354 name, value = string.split("=") 355 for module in configuration.modules(): 356 if module.get_build().attribute(name): 357 retval.append((module, name, value)) 358 if not retval: 359 print ('Error: no module contains variable %s' % name) 360 # if it is a setting for a specific module 361 elif len(data) == 2: 362 name, value = data[1].split("=") 363 module = configuration.lookup(data[0]) 364 if not module: 365 self._error('non-existing module %s in variable' 366 ' specification %s' % (name, string)) 367 if not module.get_build().attribute(name): 368 self._error('non-existing variable %s in module %s' % 369 (name, module._name)) 370 retval.append((module, name, value)) 371 # if the variable is set incorrectly 372 else: 373 self._error('invalid variable specification: "%s"' % string) 374 return retval 375 376 def _read_resource_file(self, configuration): 377 """ Reads the predefined elements on the uer's resource file.""" 378 379 rcPredefined = [] 380 fileName = os.path.join(os.path.expanduser("~"), ".bakerc") 381 382 if os.path.isfile(fileName): 383 rcPredefined = configuration.read_predefined(fileName) 384 385 return rcPredefined 386 387 def _get_predefined(self, configuration): 388 """ Gets the values of enable and disable as a predefined setting.""" 389 390 predefined =ET.Element('predefined', {'name':'last'}) 391 for e in configuration._enabled: 392 enable_node = ET.Element('enable', {'name':e.name()}) 393 predefined.append(enable_node) 394 395 for e in configuration._disabled: 396 enable_node = ET.Element('disable', {'name':e.name()}) 397 predefined.append(enable_node) 398 return predefined 399 400 401 def save_resource_file(self, configuration, fileName): 402 """ Saves the pretty resource file.""" 403 404 try: 405 fout = open(fileName, "w") 406 fout.write(bake.Utils.prettify(configuration)) 407 fout.close() 408 except IOError as e: 409 "" 410 # print ('Problems writing the resource file, error: %s' % e) 411 412 def _save_resource_configuration(self, configuration): 413 """ Saves the last call to the predefined elements on the 414 user's resource file. 415 """ 416 417 allPredefined = [] 418 fileName = os.path.join(os.path.expanduser("~"), ".bakerc") 419 lastConfig = self._get_predefined(configuration) 420 421 if os.path.isfile(fileName): 422 try: 423 et = ET.parse(fileName) 424 root = et.getroot() 425 for element in root.findall('predefined'): 426 if element.attrib['name'] == "last": 427 root.remove(element) 428 break 429 430 root.append(lastConfig) 431 self.save_resource_file(root, fileName) 432 return 433 except ParseError as e : 434 print ('Problems reading the resource file, error: %s'% e) 435 436 # There is no configuration file, so wee need to create one 437 configuration = ET.Element('configuration', {}) 438 configuration.append(lastConfig) 439 self.save_resource_file(configuration, fileName) 440 441 def _list(self, config, args): 442 """ Handles the list option for %prog """ 443 444 # sets the options the parser should recognize for the configuration 445 parser = OptionParser(usage='usage: %prog list [options]') 446 parser.add_option("-f", "--conffile", action="store", type="string", 447 dest="bakeconf", default="bakeconf.xml", 448 help="The Bake meta-data configuration file to use. " 449 "Default: %default.") 450 parser.add_option("-c", "--contrib", action="store_true", 451 dest="contrib", default="False", 452 help="Show only contrib modules.") 453 (options, args_left) = parser.parse_args(args) 454 listconf = Configuration(config) 455 contrib_list = [] 456 module_list = [] 457 458 contribconf = [] 459 try: 460 for cfile in os.listdir("contrib"): 461 if cfile.endswith(".xml"): 462 contribconf.append("contrib/"+cfile) 463 except Exception as e: 464 True 465 466 try: 467 listconf.read_metadata(options.bakeconf) 468 except Exception as e: 469 self._error('Problem reading Configuration file "%s" \n Error: %s' % (options.bakeconf, str(e))) 470 471 for cconf in contribconf: 472 try: 473 listconf.read_metadata(cconf) 474 except Exception as e: 475 self._error('Problem reading Configuration file "%s" \n Error: %s' % (cconf, str(e))) 476 477 for mod in listconf.modules(): 478 if mod.mtype() == "ns-contrib": 479 contrib_list.append(mod.name()) 480 elif not options.contrib == True: 481 module_list.append(mod.name()) 482 483 contrib_list.sort() 484 module_list.sort() 485 for m in module_list: 486 print("module: "+m) 487 for c in contrib_list: 488 print("contrib: "+c) 489 490 def _configure(self, config, args): 491 """ Handles the configuration option for %prog """ 492 493 # sets the options the parser should recognize for the configuration 494 parser = OptionParser(usage='usage: %prog configure [options]') 495 self._enable_disable_options(parser) 496 parser.add_option("-f", "--conffile", action="store", type="string", 497 dest="bakeconf", default="bakeconf.xml", 498 help="The Bake meta-data configuration file to use. " 499 "Default: %default.") 500 parser.add_option("-g", "--gui", action="store_true", 501 dest="gui", default="False", 502 help="Use a GUI to define the configuration.") 503 parser.add_option("-s", "--set", action="append", type="string", 504 dest="set", 505 default=[], 506 help="Format: module:name=value. A variable to set" 507 " in the Bake configuration for the matching module.") 508 parser.add_option("--append", action="append", type="string", 509 dest="append", default=[], 510 help="Format: module:name=value. A variable to" 511 " append to in the Bake build " 512 "configuration for the especified module.") 513 parser.add_option("--objdir", action="store", type="string", 514 dest="objdir", default="objdir", 515 help="The per-module directory where the object" 516 " files of each module will be compiled.") 517 parser.add_option("--sourcedir", action="store", type="string", 518 dest="sourcedir", default="source", 519 help="The directory where the source code of all modules " 520 "will be downloaded.") 521 parser.add_option("-i", "--installdir", action="store", type="string", 522 dest="installdir", default="build", 523 help="The directory where all modules will be installed.") 524 parser.add_option("-p", "--predefined", action="store", type="string", 525 dest="predefined", default=None, 526 help="A predefined configuration to apply") 527 528 parser.add_option('--logfile', help='File in which we want to store log output ' 529 'of requested operation', action="store", type="string", dest="logfile", 530 default='') 531 parser.add_option('--logdir', help='Directory in which we want to store log output ' 532 'of requested operation. One file per module.', action="store", 533 type="string", dest="logdir", 534 default='') 535 parser.add_option('-v', '--verbose', action='count', dest='verbose', 536 default=0, help='Increase the log verbosity level') 537 parser.add_option('-q', '--quiet', action='count', dest='quiet', 538 default=0, help='Increase the log quietness level') 539 parser.add_option("-c", "--clean", action="store_true", 540 dest="remove", default=False, 541 help="Remove all enabled modules") 542 543 # sets the configuration values got from the line command 544 (options, args_left) = parser.parse_args(args) 545 if options.bakeconf == "bakeconf.xml": 546 options.bakeconf = self.check_configuration_file(options.bakeconf, False); 547 548 contribconf = [] 549 try: 550 for cfile in os.listdir("contrib"): 551 if cfile.endswith(".xml"): 552 contribconf.append("contrib/"+cfile) 553 except Exception as e: 554 True 555 556 configuration = Configuration(config) 557 558 if not options.remove: 559 try: 560 configuration.read() 561 for m in configuration.enabled(): 562 if m.name() not in options.enable: 563 options.enable.append(m.name()) 564 except Exception as e: 565 True 566 567 try: 568 configuration.read_metadata(options.bakeconf) 569 except Exception as e: 570 self._error('Problem reading Configuration file "%s" \n Error: %s' % (options.bakeconf, str(e))) 571 572 for cconf in contribconf: 573 try: 574 configuration.read_metadata(cconf) 575 except Exception as e: 576 self._error('Problem reading Configuration file "%s" \n Error: %s' % (cconf, str(e))) 577 578 configuration.set_sourcedir(options.sourcedir) 579 configuration.set_objdir(options.objdir) 580 configuration.set_installdir(options.installdir) 581 582 # if used the predefined settings, reads the predefined configuration 583 if options.predefined: 584 data = options.predefined.split(':') 585 requested = None 586 predefined = configuration.read_predefined(options.bakeconf) 587 588 # if the user has a bake configuration 589 rcPredefined = self._read_resource_file(configuration) 590 predefined = rcPredefined + predefined 591 592 593 if len(data) == 1: 594 requested = data[0] 595 elif len(data) == 2: 596 predefined += configuration.read_predefined(data[0]) 597 requested = data[1] 598 else: 599 self._error('Invalid --predefined content: "%s"' % predefined) 600 for p in requested.split(','): 601 found = False 602 for predef in predefined: 603 if predef.name == p: 604 found = True 605 self._enable(predef.enable, configuration) 606 self._disable(predef.disable, configuration) 607 self._variables_process(predef.variables_set, 608 configuration, is_append=False) 609 self._variables_process(predef.variables_append, 610 configuration, is_append=True) 611 directories = predef.directories 612 if 'sourcedir' in directories: 613 configuration.set_sourcedir(directories['sourcedir']) 614 if 'objdir' in directories: 615 configuration.set_objdir(directories['objdir']) 616 if 'installdir' in directories: 617 configuration.set_installdir(directories['installdir']) 618 break 619 if not found: 620 self._error('--predefined: "%s" not found.' % p) 621 622 # Registers the modules are that enabled/disabled 623 # handles the -a, -m, --disable, --enable tags 624 self._parse_enable_disable(options, configuration) 625 626 # handles the set command line option, to overwrite the specific 627 # module setting with the new specified value 628 for variable in options.set: 629 matches = self._parse_variable(variable, configuration) 630 for module, name, value in matches: 631 module.get_build().attribute(name).value = value 632 633 # handles the append command line option, to add the new 634 # value to the module setting 635 for variable in options.append: 636 matches = self._parse_variable(variable, configuration) 637 for module, name, value in matches: 638 current_value = module.get_build().attribute(name).value 639 module.get_build().attribute(name).value = current_value + ' ' + value 640 configuration.write() 641 642 if not configuration._enabled and not options.append and not options.remove: 643 env = self._get_dummy_env(options) 644 env._logger.commands.write(' > No module enabled: Bake configuration requires at least one module to be enabled' 645 ' (enable, predefined), or appended.\n' 646 ' Argument(s) %s is not enough for an unambiguous action.\n' % (args_left)) 647 self._error('No module enabled, please use -e <name of the module>, -p <predefined modules> or -a, to activate all modules.') 648 649 self._save_resource_configuration(configuration) 650 651 652 dependencyChain=None 653 def _iterate(self, configuration, functor, targets, follow_optional=True): 654 """Iterates over the configuration modules applying the functor 655 function and solve reminding dependencies. 656 """ 657 658 deps = Dependencies() 659 660 # execute just one time to get the optional dependencies chain 661 if not self.dependencyChain: 662 deps.checkDependencies(targets,configuration.modules()) 663 self.dependencyChain = deps.dependencies 664 else : 665 deps.dependencies= self.dependencyChain 666# 667# 668 669 class Wrapper: 670 def __init__(self, module): 671 self._module = module 672 def function(self): 673 retval = functor(self._module) 674 configuration.write() 675 return retval 676 # for all the modules saves the configuration 677 for m in configuration.modules(): 678 wrapper = Wrapper(m) 679 deps.add_dst(m, wrapper.function) 680 # Review the dependencies of all the configured modules 681 for m in configuration.modules(): 682 for dependency in m.dependencies(): 683 src = configuration.lookup (dependency._name) 684 685 # verifies if the dependency really exists in the configuration 686 # if not we could have a problem of a corrupt, or badly 687 # configured xml file, e.g. misspelled module name 688 if src is None: 689 self._error('Dependency "%s" not found' % dependency._name) 690 691 if not src in configuration.disabled(): 692 # if it is set to add even the optional modules, or the 693 # dependency is not optional, add the module it depends on 694 # as a dependency 695 if follow_optional or not dependency.is_optional(): 696 deps.add_dep(src, m, optional=dependency.is_optional()) 697 698 try: 699 deps.resolve(targets) 700# deps.dump2(sys.stdout) 701 except DependencyUnmet as error: 702 if not error.method() =='': 703 errorAppend = ' ' + error.method() 704 else: 705 errorAppend = ' failed' 706 707 self._error(' Critical dependency, module "' + error.failed().name()+'"' + errorAppend) 708 709 def _read_config(self, config, directory=None): 710 """Reads the configuration file.""" 711 712 configuration = Configuration(config, directory) 713 if not configuration.read(): 714 sys.stderr.write('The configuration file has been changed or has moved.\n' 715 'Running \'fix-config\'. You should consider running it\n' 716 'yourself to tweak some parameters if needed.\n') 717 self._fix_config(config, []) 718 print(">> " + config) 719 configuration = Configuration(config) 720 if not configuration.read(): 721 self._error('Oops. \'fix-config\' did not succeed. You should consider\n' 722 'deleting your bakefile and running \'configure\' again.') 723 724 return configuration 725 726 def _option_parser(self, operation_name): 727 """Adds generic options to the options parser. Receives the name of the 728 present option as parameter. 729 """ 730 731 parser = OptionParser(usage='usage: %prog ' + operation_name + ' [options]') 732 parser.add_option('--logfile', help='File in which we want to store log output ' 733 'of requested operation', action="store", type="string", dest="logfile", 734 default='') 735 parser.add_option('--logdir', help='Directory in which we want to store log output ' 736 'of requested operation. One file per module.', action="store", 737 type="string", dest="logdir", 738 default='') 739 parser.add_option('-v', '--verbose', action='count', dest='verbose', 740 default=0, help='Increase the log verbosity level') 741 parser.add_option('-q', '--quiet', action='count', dest='quiet', 742 default=0, help='Increase the log quietness level') 743 parser.add_option("-o", "--one", action="store", type="string", 744 dest="one", default="", 745 help="Process only the module specified.") 746 parser.add_option("-a", "--all", action="store_true", 747 dest="all", default=False, 748 help="Process all modules") 749 parser.add_option("--stop-on-error", action="store_true", 750 dest="stopOnError", default=False, 751 help="Stop on the first error found and do not advance while the error is not corrected.") 752 parser.add_option("-s", "--start", action="store", type="string", 753 dest="start", default="", 754 help="Process all modules enabled starting from the module specified.") 755 parser.add_option("--after", action="store", type="string", 756 dest="after", default="", 757 help="Process all modules enabled starting after the module specified.") 758 parser.add_option("-i", "--environment-file-identification", 759 action="store", type="string", 760 dest="environment_file_identification", 761 default="bakeSetEnv.sh", 762 help="Name of the environment setting file") 763 parser.add_option("-x", "--no-environment-file", action='store_true', 764 dest='no_environment_file', default=False, 765 help='Do not create the environment file for this run') 766 parser.add_option("--sudo", action="store_true", 767 dest="call_with_sudo", default=False, 768 help='Best effort attempt to install dependencies and modules, when' 769 ' required, using sudo. The user has to have sudo rights (be careful using it).') 770 771 return parser 772 773 774 def createEnvironment(self, config, options, directory=None): 775 """ Auxiliary function to create an instance of the module environment""" 776 777 configuration = self._read_config(config, directory) 778 if options.logdir == '' and options.logfile == '': 779 logger = StdoutModuleLogger() 780 elif options.logdir != '': 781 assert options.logfile == '' 782 logger = LogdirModuleLogger(options.logdir) 783 else: 784 assert options.logfile != '' 785 logger = LogfileModuleLogger(options.logfile) 786 verbose = options.verbose - options.quiet 787 verbose = verbose if verbose >= 0 else 0 788 logger.set_verbose(verbose) 789 env = ModuleEnvironment(logger, 790 configuration.compute_installdir(), 791 configuration.compute_sourcedir(), 792 configuration.get_objdir(), 793 Bake.main_options.debug) 794 return configuration, env 795 796 def _do_operation(self, config, options, functor, directory=None): 797 """Applies the function, passed as parameter, over the options.""" 798 799 configuration, env = self.createEnvironment(config, options, directory) 800 must_disable = [] 801 if options.one != '': 802 if options.all or options.start != '' or options.after != '': 803 self._error('incompatible options') 804 module = configuration.lookup(options.one) 805 functor(configuration, module, env) 806 configuration.write() 807 elif options.all: 808 if options.start != '' or options.after != '': 809 self._error('incompatible options') 810 def _iterator(module): 811 return functor (configuration, module, env) 812 self._iterate(configuration, _iterator, configuration.modules()) 813 elif options.start != '': 814 if options.after != '': 815 self._error('incompatible options') 816 must_process = [] 817 first_module = configuration.lookup(options.start) 818 def _iterator(module): 819 if module == first_module: 820 must_process.append(0) 821 if len(must_process) != 0: 822 return functor (configuration, module, env) 823 else: 824 return True 825 self._iterate(configuration, _iterator, configuration.enabled()) 826 elif options.after != '': 827 # this is a list because the inner function below 828 # is not allowed to modify the outer function reference 829 must_process = [] 830 first_module = configuration.lookup(options.after) 831 def _iterator(module): 832 if len(must_process) != 0: 833 return functor (configuration, module, env) 834 elif module == first_module: 835 must_process.append(1) 836 return True 837 self._iterate(configuration, _iterator, configuration.enabled()) 838 else: 839 def _iterator(module): 840 return functor (configuration, module, env) 841 self._iterate(configuration, _iterator, configuration.enabled()) 842 return env 843 844 def _get_enabled_ns(self, config): 845 """ returns the enabled ns versions""" 846 config = self.check_configuration_file(config, True); 847 848 import os 849 if os.path.isfile(config): 850 configuration = self._read_config(config) 851 else: 852 print(" > Couldn't find the " + config + " configuration file. \n" 853 " Call bake with -f [full path configuration file name].\n") 854 return 855 856 enabled = [] 857 def _iterator(module): 858 if module.mtype()=="ns": 859 enabled.append(module.name()) 860 return True 861 862 self._iterate(configuration, _iterator, configuration.enabled()) 863 864 return enabled 865 866 def _search(self, config, args): 867 """Handles the search command line option""" 868 parser = self._option_parser('search') 869 870 (options, args_left) = parser.parse_args(args) 871 872 ns_enabled = self._get_enabled_ns(config) 873 874 logger = StdoutModuleLogger() 875 webclient = BaseClient(logger, SEARCH_API) 876 # lists all the apps from the AppStore 877 if len(args_left) == 0: 878 response = webclient.search_api() 879 for app in response: 880 sys.stdout.write(app['name'] + " (" + app['app_type'] + ") - " + app['abstract'] + "\n") 881 sys.stdout.flush() 882 # lists the apps matching the substring from the AppStore 883 elif len(args_left) == 1: 884 response = webclient.search_api(args_left[0], ns_enabled) 885 for app in response: 886 sys.stdout.write(app['app']['name'] + " (" + app['version'] + ") - " + app['app']['abstract'] + "\n") 887 sys.stdout.flush() 888 else: 889 self._error("Please provide only one parameter to search for an app") 890 891 892 def _deploy(self, config, args): 893 """Handles the deploy command line option.""" 894 895 print("Downloading, building and installing the selected modules and dependencies.") 896 print("Please, be patient, this may take a while!") 897 returnValue = self._download(config, args); 898 if not returnValue: 899 return self._build(config, args) 900 901 902 def _getconf(self, config, args): 903 """Handles the getconf command line option""" 904 parser = self._option_parser('getconf') 905 (options, args_left) = parser.parse_args(args) 906 907 ns_enabled = self._get_enabled_ns(config) 908 909 logger = StdoutModuleLogger() 910 webclient = BaseClient(logger, INSTALL_API, "http://localhost:8000") 911 912 if len(args_left) == 1 and ns_enabled is not None: 913 argument_module = args_left[0] 914 if len(argument_module.split("=="))==2: 915 sys.stdout.write("Collecting " + argument_module + "\n") 916 module_name, version = argument_module.split("==")[0], argument_module.split("==")[1] 917 response, bakefile_obj = webclient.install_api(module_name, version, ns=ns_enabled) 918 elif len(argument_module.split("="))==2: 919 self._error('Invalid requirement: %s \n\ 920 = is not a valid operator. Did you mean == ?' % args_left[0]) 921 elif len(argument_module.split("=="))==1: 922 sys.stdout.write("Collecting " + argument_module + "\n") 923 module_name = args_left[0] 924 response, bakefile_obj = webclient.install_api(module_name, ns=ns_enabled) 925 926 # Create contrib directory if it does not exist 927 try: 928 os.mkdir('contrib') 929 except: 930 pass 931 # download the bakeconf xml file in contrib directory 932 with open("contrib/" + response['name'] + "-" + response['version'] + ".xml", 'wb') as f: 933 f.write(bakefile_obj.content) 934 935 return response 936 else: 937 self._error("ns not configured") 938 939 940 def _install(self, config, args): 941 """Handles the install command line option""" 942 parser = self._option_parser('install') 943 (options, args_left) = parser.parse_args(args) 944 res = self._getconf(config, args) 945 # Take an input of modules to enable/disable/enable-minimal 946 arguments_for_configure = [] 947 arguments_for_configure.append("-e") 948 arguments_for_configure.append("ns-" + res['ns']) 949 arguments_for_configure.append("-e") 950 arguments_for_configure.append(res['name']) 951 952 ## Ask if the non-mandatory dependecies are to be disabled 953 enable_minimal = raw_input("Disable all non-mandatory dependencies? (Y/n): ") 954 if enable_minimal.lower() == 'y': 955 arguments_for_configure.append("-m") 956 957 configureResult = self._configure(config, arguments_for_configure) 958 if not configureResult: 959 self._deploy(config, []) 960 961 962 def _download(self, config, args): 963 """Handles the download command line option.""" 964 965 parser = self._option_parser('download') 966 parser.add_option("--force_download", action='store_true', 967 dest='force_download', default=False, 968 help='Force the download of all modules again') 969 970 971 (options, args_left) = parser.parse_args(args) 972 def _do_download(configuration, module, env): 973 974 if module._source.name() == 'none': 975 return True 976 977 dependencyExists = False 978 if isinstance(module._source, SystemDependency): 979 980 sys.stdout.write (" >> Searching for system dependency " + module.name() + " - ") 981 sys.stdout.flush() 982 # We support one of the following three attributes: 983 # file_test, executable_test, and dependency_test (deprecated) 984 if (module._source.attribute('file_test').value is not None): 985 dependencyExists = module._source._check_file_expression ( 986 module._source.attribute('file_test').value) 987 elif (module._source.attribute('executable_test').value is not None): 988 dependencyExists = module._source._check_executable_expression ( 989 module._source.attribute('executable_test').value) 990 # XXX Deprecated attribute; will be removed in future 991 elif (module._source.attribute('dependency_test').value is not None): 992 dependencyExists = module._source._check_dependency_expression(env, 993 module._source.attribute('dependency_test').value) 994 elif (module._source.attribute('import_test').value is not None): 995 dependencyExists = module._source._check_import( 996 module._source.attribute('import_test').value) 997 998 # if the dependency exists there is nothing else to do 999 if (dependencyExists) : 1000 env.start_source(module.name(), ".") 1001 module.printResult(env, "Search", module.OK) 1002 env.end_source() 1003 return True 1004 1005 if not dependencyExists: 1006 # Dependency did not exist 1007 targetDir='' 1008 if module._source.attribute('module_directory') and not module._source.attribute('module_directory').value.strip() =='': 1009 targetDir=' (target directory:%s)'%module._source.attribute('module_directory').value 1010 1011 if not isinstance(module._source, SystemDependency): 1012 sys.stdout.write (" >> Downloading " + module.name() + targetDir + " - ") 1013 sys.stdout.flush() 1014 if env._logger._verbose > 0: 1015 print() 1016 1017 env._sudoEnabled=options.call_with_sudo 1018 ModuleEnvironment._stopOnError=options.stopOnError 1019 valueToReturn=module.check_source_version(env) 1020 1021 1022 if valueToReturn: 1023 return module.download(env, options.force_download) 1024 else: 1025 if isinstance(module._source, SystemDependency): 1026 module.printResult(env, "Dependency ", module.FAIL) 1027 else: 1028 module.printResult(env, "Download", module.FAIL) 1029 1030 if isinstance(module._source, SystemDependency): 1031 env._logger.commands.write(' Module: \"%s\" is required by other modules but it is not available on your system.\n' 1032 ' Ask your system admin or review your library database to add \"%s\"\n' 1033 ' More information from the module: \"%s\"\n'% (module.name(), module.name(), 1034 module._source.attribute('more_information').value)) 1035 return False 1036 1037 else: 1038 tool = module._source.name() 1039 raise TaskError(' Unavailable Downloading tool %s' 1040 ' for module "%s". Try to call \"%s check\"\n' % 1041 (tool, module.name(), 1042 os.path.basename(sys.argv[0]))) 1043 self._do_operation(config, options, _do_download) 1044 1045 def _update(self, config, args): 1046 """Handles the update command line option.""" 1047 1048 parser = self._option_parser('update') 1049 (options, args_left) = parser.parse_args(args) 1050 self._check_source_version(config, options) 1051 1052 1053 def _do_update(configuration, module, env): 1054 if module._source.name() == 'none': 1055 return True 1056 1057 targetDir='' 1058 if module._source.attribute('module_directory') and not module._source.attribute('module_directory').value.strip() =='': 1059 targetDir=' (target directory:%s)'%module._source.attribute('module_directory').value 1060 1061 if not isinstance(module._source, SystemDependency): 1062 sys.stdout.write (" >> Updating " + module.name() + targetDir + " - ") 1063 sys.stdout.flush() 1064 if env._logger._verbose > 0: 1065 print() 1066 1067 return module.update(env) 1068 1069 self._do_operation(config, options, _do_update) 1070 1071 def _check_build_version(self, config, options): 1072 """Checks if the required build tools are available in the machine.""" 1073 1074 def _do_check(configuration, module, env): 1075 if not module.check_build_version(env): 1076 env._logger.commands.write(' Unavailable building tool for' 1077 ' module "%s"\n' % module.name()) 1078 return False 1079 return True 1080 self._do_operation(config, options, _do_check) 1081 1082 1083 def _check_source_version(self, config, options): 1084 """Checks if the source can be handled by the programs in the machine.""" 1085 okForTool=True 1086 def _do_check(configuration, module, env): 1087 if not module.check_source_version(env): 1088 env._logger.commands.write(' Unavailable source tool' 1089 ' for module %s\n' % module.name()) 1090 okForTool=False 1091 return False 1092 return True 1093 self._do_operation(config, options, _do_check) 1094 return okForTool 1095 1096 def _check_source_code(self, config, options, directory=None): 1097 """ Checks if we have already downloaded the matching source code.""" 1098 1099 def _do_check(configuration, module, env): 1100 if not module.is_downloaded(env): 1101 env._logger.commands.write(' Unavailable source code for' 1102 ' module %s. Try %s download first.\n' 1103 %(module.name(), sys.argv[0])) 1104 return False 1105 return True 1106 self._do_operation(config, options, _do_check, directory) 1107 1108 1109 def _build(self, config, args): 1110 """Handles the build command line option.""" 1111 1112 parser = self._option_parser('build') 1113 parser.add_option('-j', '--jobs', help='Allow N jobs at once.' 1114 ,type='int', action='store', 1115 dest='jobs', default=-1) 1116 parser.add_option('--force-clean', help='Forces the call of the clean' 1117 ' option for the build.', action="store_true", 1118 default=False, dest='force_clean') 1119 (options, args_left) = parser.parse_args(args) 1120 #self._check_build_version(config, options) 1121 self._check_source_code(config, options) 1122 1123 def _do_build(configuration, module, env): 1124 1125 if isinstance(module._source, SystemDependency) or isinstance(module._build, NoneModuleBuild) : 1126 if isinstance(module._build, NoneModuleBuild): 1127 # Only to threat the variables and pre and post instalation 1128 # that may be set even for none build kind of modules 1129 module.build(env, options.jobs, options.force_clean) 1130 return True 1131 1132 sys.stdout.write(" >> Building " + module.name() + " - ") 1133 1134 sys.stdout.flush() 1135 if env._logger._verbose > 0: 1136 print 1137 1138 env._sudoEnabled=options.call_with_sudo 1139 ModuleEnvironment._stopOnError=options.stopOnError 1140 1141 if module.check_build_version(env): 1142 retval = module.build(env, options.jobs, options.force_clean) 1143 if retval: 1144 module.update_libpath(env) 1145 return retval 1146 else: 1147 module.printResult(env, "Building", module.FAIL) 1148 print(" >> Unavailable building tool for module %s, install %s" 1149 %(module.name(),module._build.name())) 1150 1151 env = self._do_operation(config, options, _do_build) 1152 1153 if not options.no_environment_file: 1154 env.create_environment_file(options.environment_file_identification) 1155 1156 def _clean(self, config, args): 1157 """Handles the clean command line option.""" 1158 1159 parser = self._option_parser('clean') 1160 (options, args_left) = parser.parse_args(args) 1161 self._check_build_version(config, options) 1162 1163 def _do_clean(configuration, module, env): 1164 if isinstance(module._source, SystemDependency) or isinstance(module._build, NoneModuleBuild): 1165 return True 1166 1167 sys.stdout.write(" >> Clean " + module.name() + " - ") 1168 module.clean(env) 1169 return True 1170 self._do_operation(config, options, _do_clean) 1171 1172 def _distclean(self, config, args): 1173 """Handles the distclean command line option.""" 1174 1175 parser = self._option_parser('distclean') 1176 (options, args_left) = parser.parse_args(args) 1177 1178 1179 def _do_distclean(configuration, module, env): 1180 if isinstance(module._source, SystemDependency) or isinstance(module._build, NoneModuleBuild): 1181 return True 1182 1183 sys.stdout.write(" >> Distribution clean " + module.name() + " - ") 1184 returnValue = module.distclean(env) 1185 return True 1186 self._do_operation(config, options, _do_distclean) 1187 1188 def _fullclean(self, config, args): 1189 """Handles the fullclean command line option.""" 1190 1191 parser = self._option_parser('fullclean') 1192 (options, args_left) = parser.parse_args(args) 1193 1194 def _do_fullclean(configuration, module, env): 1195 if isinstance(module._source, SystemDependency) or isinstance(module._build, NoneModuleBuild): 1196 return True 1197 1198 returnValue = module.fullclean(env) 1199 return returnValue 1200 self._do_operation(config, options, _do_fullclean) 1201 1202 def _uninstall(self, config, args): 1203 """Handles the uninstall command line option.""" 1204 1205 parser = self._option_parser('uninstall') 1206 (options, args_left) = parser.parse_args(args) 1207 def _do_uninstall(configuration, module, env): 1208 sys.stdout.write(" >> Uninstall " + module.name() + " - ") 1209 module.uninstall(env) 1210 return True 1211 self._do_operation(config, options, _do_uninstall) 1212 1213 def _shell(self, config, args): 1214 """Handles the shell command line option.""" 1215 1216 parser = self._option_parser('build') 1217 (options, args_left) = parser.parse_args(args) 1218 1219 def _do_env_update(configuration, module, env): 1220 module.update_libpath(env) 1221 return True 1222 env = self._do_operation(config, options, _do_env_update) 1223 import os 1224 env.run([os.environ['SHELL']], directory=env.objdir, interactive=True) 1225 1226 def _check(self, config, args): 1227 """Handles the check command line option.""" 1228 1229 checkPrograms = [['python3', 'Python3'], 1230 ['hg', 'Mercurial'], 1231 # ['cvs', 'CVS'], 1232 ['git', 'Git'], 1233 # ['bzr', 'Bazaar'], 1234 ['tar', 'Tar tool'], 1235 ['unzip', 'Unzip tool'], 1236 # ['unrar', 'Unrar tool'], 1237 # ['7z', '7z data compression utility'], 1238 # ['unxz', 'XZ data compression utility'], 1239 ['make', 'Make'], 1240 ['cmake', 'cMake'], 1241 ['patch', 'patch tool'], 1242 # ['autoreconf', 'autoreconf tool'] 1243 ] 1244 if sys.platform == 'darwin': 1245 checkPrograms.insert(1,['clang++', 'Clang C++ compiler']) 1246 else: 1247 checkPrograms.insert(1,['g++', 'GNU C++ compiler']) 1248 parser = self._option_parser('build') 1249 (options, args_left) = parser.parse_args(args) 1250 def _do_env_check(configuration, module, env): 1251 return True 1252 1253 env = self._get_dummy_env(options) 1254 colorTool = ColorTool() 1255 for element in checkPrograms: 1256 if env.check_program(element[0]): 1257 colorTool.cPrintln(colorTool.OK, " > " + element[1] + " - OK") 1258 else: 1259 colorTool.cPrintln(colorTool.WARNING, " > " + element[1] + 1260 " - is missing") 1261 print ('\n') 1262 colorTool.cPrint(colorTool.OK, " > Path searched for tools:") 1263 for item in env.path_list(): 1264 sys.stdout.write (' ' + item) 1265 sys.stdout.flush() 1266 print ('\n') 1267 1268 def _get_dummy_env(self, options): 1269 """ Returns a dummy environment just for verifying the user's system configuration. """ 1270 configuration = Configuration("") 1271 1272 if options.logdir == '' and options.logfile == '': 1273 logger = StdoutModuleLogger() 1274 elif options.logdir != '': 1275 assert options.logfile == '' 1276 logger = LogdirModuleLogger(options.logdir) 1277 else: 1278 assert options.logfile != '' 1279 logger = LogfileModuleLogger(options.logfile) 1280 verbose = options.verbose - options.quiet 1281 verbose = verbose if verbose >= 0 else 0 1282 logger.set_verbose(verbose) 1283 logger._update_file(logger._file) 1284 1285 return ModuleEnvironment(logger, "","","", Bake.main_options.debug) 1286 1287 def _show_one_builtin(self, builtin, string, variables): 1288 """Go over the available builtins handling tools.""" 1289 1290 import textwrap 1291 if builtin.name() != 'none': 1292 print ('%s %s' % (string, builtin.name())) 1293 if variables: 1294 for attribute in builtin().attributes(): 1295 print (' %s=%s' % (attribute.name, attribute.value)) 1296 lines = [' %s' % line for line in textwrap.wrap(attribute.help)] 1297 print ('\n'.join(lines)) 1298 1299 def _show_variables(self, module): 1300 """Handles the show the variables available for source and build.""" 1301 1302 source = module.get_source() 1303 if source.attributes(): 1304 print (' source %s' % source.name()) 1305 for attribute in source.attributes(): 1306 print (' %s=%s' % (attribute.name, attribute.value)) 1307 build = module.get_build() 1308 1309 if build.attributes(): 1310 print (' build %s' % build.name()) 1311 for attribute in build.attributes(): 1312 print (' %s=%s' % (attribute.name, attribute.value)) 1313 1314 def _show_builtin(self, config, args): 1315 """Handles the show one builtin command line option.""" 1316 1317 from bake.ModuleSource import ModuleSource 1318 from bake.ModuleBuild import ModuleBuild 1319 parser = OptionParser(usage='usage: %prog show [options]') 1320 parser.add_option('-a', '--all', action='store_true', dest='all', 1321 default=False, 1322 help='Display all known information about builtin source and build commands') 1323 parser.add_option('--source', action='store_true', dest='source', 1324 default=False, 1325 help='Display information about builtin source commands') 1326 parser.add_option('--build', action='store_true', dest='build', 1327 default=False, 1328 help='Display information about builtin build commands') 1329 parser.add_option('--variables', action='store_true', dest='variables', 1330 default=False, 1331 help='Display variables for builtin commands') 1332 (options, args_left) = parser.parse_args(args) 1333 1334 if options.all : 1335 options.source = True 1336 options.build = True 1337 options.variables = True 1338 elif not options.source and not options.build : 1339 options.source = True 1340 options.build = True 1341 1342 1343 if options.source: 1344 for source in ModuleSource.subclasses(): 1345 self._show_one_builtin(source, 'source', options.variables) 1346 1347 if options.build: 1348 for build in ModuleBuild.subclasses(): 1349 self._show_one_builtin(build, 'build', options.variables) 1350 1351 systemDependencies=dict() 1352 1353 def show_module(self, state, options, config, label): 1354 """ Handles the printing of the information of modules and dependencies.""" 1355 1356 depen=dict() 1357 1358 if not state: 1359 return 1360 for mod in state: 1361 if mod.mtype(): 1362 print('module %s: %s (%s)' % (mod.mtype(), mod.name(), label)) 1363 else: 1364 print('module: %s (%s)' % (mod.name(), label)) 1365 dependencies = mod.dependencies() 1366 1367 # Stores the system dependencies 1368 if isinstance(mod._source, SystemDependency) and label=="enabled": 1369 self.systemDependencies[mod.name()] = mod._source 1370 1371 # Collects the dependencies 1372 if not mod.name() in depen: 1373 depen[mod.name()] = dict() 1374 1375 if dependencies and not options.brief == True: 1376 print(' depends on:') 1377 for dependsOn in mod.dependencies(): 1378 print(' %s (optional:%s)' % 1379 (dependsOn._name, dependsOn.is_optional())) 1380 depen[mod.name()][dependsOn._name]= dependsOn.is_optional() 1381 elif not options.brief == True: 1382 print(' No dependencies!') 1383 1384 1385 if options.variables: 1386 self._show_variables(mod) 1387 1388 if options.enabledTree and label=="enabled": 1389 print("\n-- Enabled modules dependency tree --") 1390 self.deptree(depen, depen, label, dict(), "", " ") 1391 1392 return mod 1393 1394 def showSystemDependencies(self, systemDependencies,config): 1395 """ Shows the System dependencies of the defined configuration. """ 1396 1397 if len(systemDependencies)<=0: 1398 return 1399 1400 print ("\n-- System Dependencies --") 1401 1402 (distribution, version, version_id) = distro.linux_distribution() 1403 1404 if not distribution: 1405 distribution = 'darwin' # osName 1406 else: 1407 distribution = distribution.lower() 1408 1409 missing=False 1410 returnValue="" 1411 depend_keys = systemDependencies.keys() 1412 depend_keys=sorted(depend_keys) 1413 1414 # creates the environment 1415 configuration = self._read_config(config) 1416 logger = StdoutModuleLogger() 1417 logger.set_verbose(0) 1418 env = ModuleEnvironment(logger, "","", 1419 configuration.get_objdir()) 1420 1421 for this_key in depend_keys: 1422 sysDep=systemDependencies[this_key] 1423 dependencyExists = False 1424 1425 # We support one of the following three attributes: 1426 # file_test, executable_test, and dependency_test (deprecated) 1427 if (sysDep.attribute('file_test').value is not None): 1428 dependencyExists = sysDep._check_file_expression ( 1429 sysDep.attribute('file_test').value) 1430 elif (sysDep.attribute('executable_test').value is not None): 1431 dependencyExists = sysDep._check_executable_expression ( 1432 sysDep.attribute('executable_test').value) 1433 # XXX Deprecated attribute; will be removed in future 1434 elif (sysDep.attribute('dependency_test').value is not None): 1435 dependencyExists = sysDep._check_dependency_expression(env, 1436 sysDep.attribute('dependency_test').value) 1437 elif (sysDep.attribute('import_test').value is not None): 1438 dependencyExists = sysDep._check_import( 1439 sysDep.attribute('import_test').value) 1440 1441 if not dependencyExists: 1442 sys.stdout.write(" > " + this_key + " - ") 1443 ColorTool.cPrintln(ColorTool.FAIL, "Missing") 1444 print(" >> " + sysDep.attribute('more_information').value) 1445 command = sysDep._get_command(distribution) 1446 command = command.strip() 1447 if not command == '': 1448 installerName = sysDep.attribute('name_' + command.split()[0]).value 1449 1450 # if didn't find the specific installer name uses the default one 1451 if(not installerName): 1452 installerName = this_key 1453 1454 if (sysDep.attribute('import_test').value is None): 1455 print(' >> Try: "sudo ' + command + ' ' + 1456 installerName + '", if you have sudo rights.') 1457 1458 missing = True 1459 else: 1460 sys.stdout.write(" > " + this_key + " - ") 1461 ColorTool.cPrintln(ColorTool.OK, "OK") 1462 1463 returnValue= returnValue + this_key 1464 1465 # if there is a missing dependency the system error level is set to 1 1466 if missing: 1467 sys.exit(1) 1468 1469 return returnValue 1470 1471 def deptree(self, fulldep, depen, key, has_passed, optionalModule, padding): 1472 """ Shows the dependency tree. """ 1473 1474 sys.stdout.write(padding[:-1] + '+-' + key + '/') 1475 color=ColorTool.FAIL 1476 if 'optional' in optionalModule: 1477 color=ColorTool.OK 1478 ColorTool.cPrintln(color, optionalModule) 1479 padding = padding + ' ' 1480 1481 # to avoid loops 1482 if key in has_passed: 1483 sys.stdout.write(padding) 1484 ColorTool.cPrintln(ColorTool.FAIL, "> Cyclic Dependency") 1485 return "> Cyclic Dependency." 1486 else: 1487 has_passed[key]=True 1488 1489 depend_keys = depen.keys() 1490 depend_keys=sorted(depend_keys) 1491 1492 # goes recursively over the list of keys reading the dictionaries with 1493 # the dependencies 1494 count = 0 1495 listStr = '' 1496 for this_key in depend_keys: 1497 count += 1 1498 print (padding + '|') 1499 optional="" 1500 color=ColorTool.FAIL 1501 if this_key in depen and isinstance(depen[this_key],bool)>0: 1502 if depen[this_key]: 1503 optional = " (optional)" 1504 color=ColorTool.OK 1505 else: 1506 optional = " (mandatory)" 1507 1508 if this_key in fulldep and len(fulldep[this_key])>0: 1509 1510 if count == len(depend_keys): 1511 listStr = listStr + self.deptree(fulldep, fulldep[this_key], this_key, has_passed, optional, padding + ' ') 1512 else: 1513 listStr = listStr + self.deptree(fulldep, fulldep[this_key], this_key, has_passed, optional, padding + '|') 1514 else: 1515 if this_key in fulldep: 1516 sys.stdout.write(padding + '+-' + this_key) 1517 ColorTool.cPrintln(color, optional) 1518 listStr = this_key +'.'+ listStr 1519 1520 del has_passed[key] 1521 return key +'/'+ listStr 1522 1523 def _print_version(self): 1524 print(" > Bake Version 0.1") 1525 1526 def _show(self, config, args): 1527 """Handles the show command line option.""" 1528 1529 parser = OptionParser(usage='usage: %prog show [options]') 1530 parser.add_option('-a', '--all', action='store_true', dest='all', 1531 default=False, 1532 help='Display all known information about current configuration') 1533 parser.add_option('--enabled', action='store_true', dest='enabled', 1534 default=False, help='Display information about existing enabled modules') 1535 parser.add_option('--disabled', action='store_true', dest='disabled', 1536 default=False, help='Display information about existing disabled modules') 1537 parser.add_option('--available', action='store_true', dest='available', 1538 default=False, help='Display information about available modules') 1539 parser.add_option('--variables', action='store_true', dest='variables', 1540 default=False, 1541 help='Display information on the variables set for the modules selected') 1542 parser.add_option('--predefined', action='store_true', dest='predefined', 1543 default=False, 1544 help='Display information on the items predefined') 1545 parser.add_option('--directories', action='store_true', dest='directories', 1546 default=False, 1547 help='Display information about which directories have been configured') 1548 parser.add_option('--enabledTree', action='store_true', dest='enabledTree', 1549 default=False, 1550 help='Shows the enabled modules dependency tree') 1551 parser.add_option('--showSystemDep', action='store_true', dest='showSystemDep', 1552 default=True, 1553 help='Shows the system dependency of the enabled/disabled modules') 1554 parser.add_option('-b', '--brief', action='store_true', dest='brief', 1555 default=False, 1556 help='Show only the module name') 1557 parser.add_option('-c', '--configured', action='store_true', dest='configured', 1558 default=False, 1559 help='Show only the configured module') 1560 (options, args_left) = parser.parse_args(args) 1561 # adds a default value so that show will show something even if there is 1562 # no option 1563 if not args: 1564 options.enabled = True 1565 options.showSystemDep = True 1566 else: 1567 if not options.disabled and not options.enabled and not options.configured: 1568 options.enabled=True 1569 1570 config= self.check_configuration_file(config, True); 1571 1572 import os 1573 if os.path.isfile(config): 1574 configuration = self._read_config(config) 1575 else: 1576 # try to get the default 1577 print(" > Couldn't find the " + config + " configuration file. \n" 1578 " Call bake with -f [full path configuration file name].\n") 1579 return 1580 if options.all: 1581 options.enabled = True 1582 options.disabled = True 1583 options.directories = True 1584 options.variables = True 1585 options.predefined = True 1586 options.enabledTree = True 1587 elif options.available: 1588 options.enabled = True 1589 options.disabled = True 1590 1591 if options.directories: 1592 print ('installdir : ' + configuration.compute_installdir()) 1593 print ('sourcedir : ' + configuration.compute_sourcedir()) 1594 print ('objdir : ' + configuration.get_objdir()) 1595 1596 1597 enabled = [] 1598 def _iterator(module): 1599 enabled.append(module) 1600 return True 1601 self._iterate(configuration, _iterator, configuration.enabled()) 1602 disabled = filter(lambda module: not module in enabled, configuration.modules()) 1603 1604 if options.enabled: 1605 self.show_module(enabled, options, config, 'enabled') 1606 1607 if options.configured: 1608 self.show_module(configuration.configured(), options, config, 'configured') 1609 1610 if options.disabled: 1611 self.show_module(disabled, options, config, 'disabled') 1612 1613 if options.showSystemDep: 1614 self.showSystemDependencies(self.systemDependencies, config) 1615 1616 1617 def check_configuration_file(self, configFile, considersTemplate=False): 1618 """ Checks if the configuration file exists, if not tries to use the 1619 one on the root bake directory.""" 1620 1621 # If the name is not the default one... do not interfere 1622 if configFile != "bakeconf.xml" and configFile != "bakefile.xml": 1623 return configFile 1624 1625 # If the file is the default, and exists on the local directory, fine 1626 if os.path.isfile(configFile): 1627 return configFile 1628 1629 presentDir = os.path.dirname(sys.argv[0]) 1630 if not presentDir: 1631 presentDir = "." 1632 # if the file does not exist on the local directory 1633 # tries the standard configuration file on the installation directory 1634 if os.path.isfile(os.path.join(presentDir, configFile)): 1635 return os.path.join(presentDir, configFile) 1636 1637 # if the standard file does not exist 1638 # tries the generic configuration file on the installation directory 1639 if considersTemplate and os.path.isfile(os.path.join(presentDir, 1640 "bakeconf.xml")): 1641 return os.path.join(presentDir,"bakeconf.xml") 1642 1643 # if everything else fail.... returns the same name 1644 return configFile 1645 1646 options = "" 1647 1648 def checkPythonVersion(self): 1649 """ Checks the version of the user's machine python. python-2.6 or 1650 2.7 supported""" 1651 1652 if sys.hexversion < 0x02060000: 1653 print(">>> Old Python version detected, please use python2 >= version 2.6") 1654 sys.exit(1) 1655 1656 def main(self, argv): 1657 """Main Bake function.""" 1658 1659 # catches Ctrl-c 1660 signal.signal(signal.SIGINT, signal_handler) 1661 1662 self.checkPythonVersion() 1663 1664 parser = MyOptionParser(usage='usage: %prog [options] command [command options]', 1665 description="""Where command is one of: 1666 deploy : Downloads the configured modules AND makes the build in one step 1667 configure : Setup the build configuration (source, build, install directory, 1668 and per-module build options) from the module descriptions 1669 fix-config : Update the build configuration from a newer module description 1670 search : Search for modules from the AppStore 1671 getconf : Downloads the bakefile for the module 1672 install : Download and build the module 1673 download : Download all modules enabled during configure 1674 update : Update the source tree of all modules enabled during configure 1675 build : Build all modules enabled during configure 1676 clean : Cleanup the source tree of all modules built previously 1677 shell : Start a shell and setup relevant environment variables 1678 uninstall : Remove all files that were installed during build 1679 distclean : Call the modules distclean option, if available 1680 fullclean : Remove all the build AND source files 1681 show : Report on build configuration 1682 show-builtin : Report on builtin source and build commands 1683 check : Checks if all the required tools are available on the system 1684 1685To get more help about each command, try: 1686 %s command --help 1687""") 1688 parser.add_option("-f", "--file", action="store", type="string", 1689 dest="config_file", default="bakefile.xml", 1690 help="The Bake file to use, and the target " 1691 "configuration/reconfiguration. Default: %default.") 1692 parser.add_option("--debug", action="store_true", 1693 dest="debug", default=False, 1694 help="Prints out all the error messages and problems.") 1695 parser.add_option("--noColor", action="store_true", 1696 dest="noColor", default=False, 1697 help='Print messages with no color') 1698 parser.add_option("-V", action="store_true", 1699 dest="version", default=False, 1700 help='Prints the version of Bake' ) 1701 parser.disable_interspersed_args() 1702 (options, args_left) = parser.parse_args(argv[1:]) 1703 1704 if options.version: 1705 self._print_version() 1706 1707 1708 Bake.main_options = options 1709 1710 # if asked to not having collors, useful for non iteractive 1711 # use and users that do not have a color enabled terminal 1712 if options.noColor: 1713 ColorTool.disable() 1714 else: 1715 has_colours = ColorTool.has_colours(sys.stdout) 1716 if not has_colours: 1717 ColorTool.disable() 1718 1719 1720 if len(args_left) == 0: 1721 if not options.version: 1722 parser.print_help() 1723 sys.exit(1) 1724 ops = [ ['deploy', self._deploy], 1725 ['configure', self._configure], 1726 ['fix-config', self._fix_config], 1727 ['search', self._search], 1728 ['getconf', self._getconf], 1729 ['install', self._install], 1730 ['download', self._download], 1731 ['update', self._update], 1732 ['build', self._build], 1733 ['clean', self._clean], 1734 ['shell', self._shell], 1735 ['uninstall', self._uninstall], 1736 ['distclean', self._distclean], 1737 ['fullclean', self._fullclean], 1738 ['show', self._show], 1739 ['show-builtin', self._show_builtin], 1740 ['check', self._check], 1741 ['list', self._list], 1742 ] 1743 recognizedCommand = False 1744 1745 for name, function in ops: 1746 if args_left[0].lower() == name: 1747 recognizedCommand = True 1748 if options.debug: 1749 function(config=options.config_file, args=args_left[1:]) 1750 else: 1751 try: 1752 function(config=options.config_file, args=args_left[1:]) 1753 except Exception as e: 1754 print ('\n'+ str(e)) 1755 sys.exit(1) 1756 except TaskError as e: 1757 print ('\n'+e.reason) 1758 sys.exit(1) 1759 1760 if not recognizedCommand: 1761 print (' >> Unrecognized option: ' + args_left[0]) 1762 sys.exit(1) 1763 1764