def AddCommandLineOptions(self, parserObj): ''' adds command line options to the argparser ''' # PlatformSettings could also be a subclass of UefiBuilder, who knows! if isinstance(self.PlatformSettings, UefiBuilder): self.PlatformBuilder = self.PlatformSettings else: try: # if it's not, we will try to find it in the module that was originally provided. self.PlatformBuilder = locate_class_in_module(self.PlatformModule, UefiBuilder)() except (TypeError): raise RuntimeError(f"UefiBuild not found in module:\n{dir(self.PlatformModule)}") self.PlatformBuilder.AddPlatformCommandLineOptions(parserObj)
def ParseCommandLineOptions(self): ''' Parses command line options. Sets up argparser specifically to get PlatformSettingsManager instance. Then sets up second argparser and passes it to child class and to PlatformSettingsManager. Finally, parses all known args and then reads the unknown args in to build vars. ''' # first argparser will only get settings manager and help will be disabled settingsParserObj = argparse.ArgumentParser(add_help=False) # instantiate the second argparser that will get passed around epilog = ''' <key>=<value> - Set an env variable for the pre/post build process BLD_*_<key>=<value> - Set a build flag for all build types. Key=value will get passed to build process BLD_<TARGET>_<key>=<value> - Set a build flag for build type of <target> Key=value will get passed to build process for given build type)''' parserObj = argparse.ArgumentParser(epilog=epilog) settingsParserObj.add_argument( '-c', '--platform_module', dest='platform_module', default="PlatformBuild.py", type=str, help= 'Provide the Platform Module relative to the current working directory.' f'This should contain a {self.GetSettingsClass().__name__} instance.' ) # get the settings manager from the provided file and load an instance settingsArg, unknown_args = settingsParserObj.parse_known_args() try: self.PlatformModule = import_module_by_file_name( os.path.abspath(settingsArg.platform_module)) self.PlatformSettings = locate_class_in_module( self.PlatformModule, self.GetSettingsClass())() except (TypeError, FileNotFoundError) as e: # Gracefully exit if setup doesn't go well. try: # If this works, we can provide help for whatever special functions # the subclass is offering. self.AddCommandLineOptions(settingsParserObj) except: # If it didn't work, oh well. pass print(e) settingsParserObj.print_help() sys.exit(0) # now to get the big arg parser going... # first pass it to the subclass self.AddCommandLineOptions(parserObj) # next pass it to the settings manager self.PlatformSettings.AddCommandLineOptions(parserObj) default_build_config_path = os.path.join(self.GetWorkspaceRoot(), "BuildConfig.conf") # add the common stuff that everyone will need parserObj.add_argument('--build-config', dest='build_config', default=default_build_config_path, type=str, help='Provide shell variables in a file') parserObj.add_argument('--verbose', '--VERBOSE', '-v', dest="verbose", action='store_true', default=False, help='verbose') # setup sys.argv and argparse round 2 sys.argv = [sys.argv[0]] + unknown_args args, unknown_args = parserObj.parse_known_args() self.Verbose = args.verbose # give the parsed args to the subclass self.RetrieveCommandLineOptions(args) # give the parsed args to platform settings manager self.PlatformSettings.RetrieveCommandLineOptions(args) # # Look through unknown_args and BuildConfig for strings that are x=y, # set env.SetValue(x, y), # then remove this item from the list. # env = shell_environment.GetBuildVars() BuildConfig = os.path.abspath(args.build_config) if os.path.isfile(BuildConfig): with open(BuildConfig) as file: for line in file: stripped_line = line.strip() if not stripped_line.startswith("#"): unknown_args.append(line) i = 0 while i < len(unknown_args): unknown_arg = unknown_args[i] if (unknown_arg.count("=") == 1): tokens = unknown_arg.strip().split("=") env.SetValue(tokens[0].strip().upper(), tokens[1].strip(), "From CmdLine") del unknown_args[i] else: i += 1 if len(unknown_args) > 0: parserObj.print_help() raise RuntimeError(f"Unknown variables passed in: {unknown_args}")
def ParseCommandLineOptions(self): ''' Parses command line options. Sets up argparser specifically to get PlatformSettingsManager instance. Then sets up second argparser and passes it to child class and to PlatformSettingsManager. Finally, parses all known args and then reads the unknown args in to build vars. ''' # first argparser will only get settings manager and help will be disabled settingsParserObj = argparse.ArgumentParser(add_help=False) # instantiate the second argparser that will get passed around epilog = ''' <key>=<value> - Set an env variable for the pre/post build process BLD_*_<key>=<value> - Set a build flag for all build types. Key=value will get passed to build process BLD_<TARGET>_<key>=<value> - Set a build flag for build type of <target> Key=value will get passed to build process for given build type)''' parserObj = argparse.ArgumentParser(epilog=epilog) settingsParserObj.add_argument( '-c', '--platform_module', dest='platform_module', default="PlatformBuild.py", type=str, help= 'Provide the Platform Module relative to the current working directory.' f'This should contain a {self.GetSettingsClass().__name__} instance.' ) # get the settings manager from the provided file and load an instance settingsArg, unknown_args = settingsParserObj.parse_known_args() try: self.PlatformModule = import_module_by_file_name( os.path.abspath(settingsArg.platform_module)) self.PlatformSettings = locate_class_in_module( self.PlatformModule, self.GetSettingsClass())() except (TypeError): # Gracefully exit if the file we loaded isn't the right type class_name = self.GetSettingsClass().__name__ print( f"Unable to use {settingsArg.platform_module} as a {class_name}" ) print("Did you mean to use a different kind of invocable?") try: # If this works, we can provide help for whatever special functions # the subclass is offering. self.AddCommandLineOptions(settingsParserObj) Module = self.PlatformModule module_contents = dir(Module) # Filter through the Module, we're only looking for classes. classList = [ getattr(Module, obj) for obj in module_contents if inspect.isclass(getattr(Module, obj)) ] # Get the name of all the classes classNameList = [obj.__name__ for obj in classList] # TODO improve filter to no longer catch imports as well as declared classes imported_classes = ", ".join( classNameList) # Join the classes together print(f"The module you imported contains {imported_classes}") except Exception: # Otherwise, oh well we'll just ignore this. raise pass settingsParserObj.print_help() sys.exit(1) except (FileNotFoundError): # Gracefully exit if we can't find the file print(f"We weren't able to find {settingsArg.platform_module}") settingsParserObj.print_help() sys.exit(2) except Exception as e: print( f"Error: We had trouble loading {settingsArg.platform_module}. Is the path correct?" ) # Gracefully exit if setup doesn't go well. settingsParserObj.print_help() print(e) sys.exit(2) # now to get the big arg parser going... # first pass it to the subclass self.AddCommandLineOptions(parserObj) # next pass it to the settings manager self.PlatformSettings.AddCommandLineOptions(parserObj) default_build_config_path = os.path.join(self.GetWorkspaceRoot(), "BuildConfig.conf") # add the common stuff that everyone will need parserObj.add_argument('--build-config', dest='build_config', default=default_build_config_path, type=str, help='Provide shell variables in a file') parserObj.add_argument('--verbose', '--VERBOSE', '-v', dest="verbose", action='store_true', default=False, help='verbose') # setup sys.argv and argparse round 2 sys.argv = [sys.argv[0]] + unknown_args args, unknown_args = parserObj.parse_known_args() self.Verbose = args.verbose # give the parsed args to the subclass self.RetrieveCommandLineOptions(args) # give the parsed args to platform settings manager self.PlatformSettings.RetrieveCommandLineOptions(args) # # Look through unknown_args and BuildConfig for strings that are x=y, # set env.SetValue(x, y), # then remove this item from the list. # env = shell_environment.GetBuildVars() BuildConfig = os.path.abspath(args.build_config) for argument in unknown_args: if argument.count("=") != 1: raise RuntimeError( f"Unknown variable passed in via CLI: {argument}") tokens = argument.strip().split("=") env.SetValue(tokens[0].strip().upper(), tokens[1].strip(), "From CmdLine") unknown_args.clear() # remove the arguments we've already consumed if os.path.isfile(BuildConfig): with open(BuildConfig) as file: for line in file: stripped_line = line.strip().partition("#")[0] if len(stripped_line) == 0: continue unknown_args.append(stripped_line) for argument in unknown_args: if argument.count("=") != 1: raise RuntimeError( f"Unknown variable passed in via BuildConfig: {argument}") tokens = argument.strip().split("=") env.SetValue(tokens[0].strip().upper(), tokens[1].strip(), "From BuildConf")
def test_locate_class_in_module(self): module = sys.modules[__name__] found_class = utilities.locate_class_in_module(module, DesiredClass) self.assertIsNotNone(found_class) self.assertEqual(found_class, GrandChildOfDesiredClass)