''' This script can be run to update paths to gcc, openOCD and other tools/files/folders. Script verify and add data to 'buildData.json' file. ''' import os import shutil import utilities as utils import updateBuildData as build import updateTasks as tasks import updateLaunchConfig as launch import updateWorkspaceFile as workspaceFile __version__ = utils.__version__ class UpdatePaths(): def __init__(self): self.bStr = build.BuildDataStrings() # list of paths with explanatory names and (optionally) default path # keys must match with 'self.bStr.toolsPaths' list self.pathsDescriptionsData = { self.bStr.gccExePath: { "name": "arm-none-eabi-gcc executable (arm-none-eabi-gcc.exe)", "defaultPath": "arm-none-eabi-gcc"}, self.bStr.buildToolsPath: { "name": "make executable (make.exe)", "defaultPath": "make"}, self.bStr.openOcdPath: { "name": "OpenOCD executable (openocd.exe)", "defaultPath": "openocd"}, self.bStr.openOcdInterfacePath: { "name": "OpenOCD ST Link interface path ('stlink.cfg')", "defaultPath": "./scripts/interface/stlink.cfg"}, self.bStr.stm32SvdPath: { "name": "STM target '*.svd' file (.../Keil*/CMSIS/SVD/STM32F0x1.svd)", "defaultPath": None} } def verifyToolsPaths(self, toolsPaths, request=False): ''' This function checks if paths in 'toolsPaths.json' are a valid paths. If any path is not valid/missing, user is asked for update via updatePath(). If 'request' is set to True, user is asked to update path even if it is a valid path. Returns updated valid tools paths. ''' for pathName in self.bStr.toolsPaths: try: mustBeUpdated = False if pathName in toolsPaths: # 'toolsPaths.json' keys are not lists. Always a plain path (string) if not utils.pathExists(toolsPaths[pathName]): mustBeUpdated = True # path not valid, check if command if utils.commandExists(toolsPaths[pathName]): mustBeUpdated = False if mustBeUpdated: if toolsPaths[pathName] != '': # avoid reporting invalid file path, if there is an empty string msg = "\n\nInvalid path detected in '" + pathName + "' key." print(msg) else: if request: msg = "\n\nValid path(s) for " + pathName + " detected: '" + toolsPaths[pathName] + "'." msg += "\n\tUpdate? [y/n]: " if utils.getYesNoAnswer(msg): mustBeUpdated = True else: # this key is missing in toolsPaths.json! mustBeUpdated = True if mustBeUpdated: if pathName in self.bStr.derivedPaths: continue elif pathName == self.bStr.openOcdConfig: # get openOcdConfig - special handler toolsPaths[pathName] = utils.getOpenOcdConfig(toolsPaths[self.bStr.openOcdPath]) elif pathName in self.pathsDescriptionsData: name = self.pathsDescriptionsData[pathName]['name'] defaultPath = self.pathsDescriptionsData[pathName]['defaultPath'] toolsPaths[pathName] = self.updatePath(name, defaultPath) else: toolsPaths[pathName] = self.updatePath(pathName, None) except Exception as err: toolsPaths[pathName] = self.updatePath(pathName, None) for pathName in self.bStr.derivedPaths: if pathName == self.bStr.pythonExec: toolsPaths[self.bStr.pythonExec] = utils.getPython3Executable() elif pathName == self.bStr.gccInludePath: toolsPaths[self.bStr.gccInludePath] = utils.getGccIncludePath(toolsPaths[self.bStr.gccExePath]) else: errorMsg = "ideScripts design error: pathName '" + pathName + "' is in 'self.bStr.derivedPaths' list, " errorMsg += "but no 'get()' handler is specified." utils.printAndQuit(errorMsg) return toolsPaths def verifyTargetConfigurationPaths(self, buildData, request=False): ''' This function checks if 'buildData.json' contains targetConfiguration paths. If any path is not valid/missing, user is asked for update via updatePath(). If 'request' is set to True, user is asked to update path even if it is a valid path. Returns buildData with a valid, updated tools paths. ''' for pathName in self.bStr.targetConfigurationPaths: mustBeUpdated = False if pathName in self.bStr.derivedPaths: # derived paths, build later continue if pathName not in buildData: mustBeUpdated = True else: if isinstance(buildData[pathName], list): if not buildData[pathName]: mustBeUpdated = True else: for path in buildData[pathName]: if not utils.pathExists(path): mustBeUpdated = True break else: # not a list, a single path expected if not utils.pathExists(buildData[pathName]): mustBeUpdated = True # path not valid, check if command if utils.commandExists(buildData[pathName]): mustBeUpdated = False if mustBeUpdated: notify = True # avoid reporting invalid file path, if there is an empty string/list if isinstance(buildData[pathName], list): if not buildData[pathName]: notify = False else: if buildData[pathName] == '': notify = False if notify: msg = "\n\nInvalid path detected in 'buildData.json' '" + pathName + "' key." print(msg) else: if request: msg = "\n\nValid path(s) for " + pathName + " detected: '" + str(buildData[pathName]) + "'." msg += "\n\tUpdate? [y/n]: " if utils.getYesNoAnswer(msg): mustBeUpdated = True if mustBeUpdated: if pathName == self.bStr.openOcdConfig: # get openOcdConfig - special handler buildData[pathName] = utils.getOpenOcdConfig(buildData[self.bStr.openOcdPath]) elif pathName in self.bStr.derivedPaths: name = self.bStr.derivedPaths[pathName]['name'] defaultPath = self.bStr.derivedPaths[pathName]['defaultPath'] buildData[pathName] = self.updatePath(name, defaultPath) else: buildData[pathName] = self.updatePath(pathName, None) return buildData def copyTargetConfigurationFiles(self, buildData): ''' This function checks if paths to target configuration files listed in 'BuildDataStrings.targetConfigurationPaths' are available, stored inside this workspace '.vscode' subfolder. Once this files are copied, paths are updated and new buildData is returned. Paths are previously checked/updated in 'verifyTargetConfigurationPaths()' ''' for pathName in self.bStr.targetConfigurationPaths: currentPaths = buildData[pathName] if isinstance(currentPaths, list): isList = True else: isList = False currentPaths = [currentPaths] newPaths = [] for currentPath in currentPaths: fileName = utils.getFileName(currentPath, withExtension=True) fileInVsCodeFolder = os.path.join(utils.vsCodeFolderPath, fileName) if not utils.pathExists(fileInVsCodeFolder): # file does not exist in '.vscode' folder try: newPath = shutil.copy(currentPath, utils.vsCodeFolderPath) except Exception as err: errorMsg = "Unable to copy file '" + fileName + "' to '.vscode' folder. Exception:\n" + str(err) utils.printAndQuit(errorMsg) newPath = os.path.relpath(fileInVsCodeFolder) newPath = utils.pathWithForwardSlashes(newPath) newPaths.append(newPath) if isList: buildData[pathName] = newPaths else: buildData[pathName] = newPaths[0] return buildData def updatePath(self, pathName, default): ''' This function is called when a path is detected as invalid or the user requests to update paths. ''' pathDefault = None # check if default is a path if utils.pathExists(default): pathDefault = default # not a path command, check if it's a command elif utils.commandExists(default): pathDefault = shutil.which(default) if pathDefault is not None: msg = "\n\tDefault path to '" + pathName + "' detected at '" + pathDefault + "'\n\tUse this path? [y/n]: " if utils.getYesNoAnswer(msg): return pathDefault # default not detected or user wants custom path/command newPath = utils.getUserPath(pathName) return newPath ######################################################################################################################## if __name__ == "__main__": utils.verifyFolderStructure() paths = UpdatePaths() bData = build.BuildData() tasks = tasks.Tasks() launch = launch.LaunchConfigurations() wksFile = workspaceFile.UpdateWorkspaceFile() # update build data buildData = bData.prepareBuildData(request=True) bData.overwriteBuildDataFile(buildData) # update tasks tasks.checkTasksFile() tasksData = tasks.getTasksData() tasksData = tasks.addAllTasks(tasksData) tasks.overwriteTasksFile(tasksData) # update launch configurations launch.checkLaunchFile() launchData = launch.getLaunchData() launchData = launch.addAllLaunchConfigurations(launchData) launch.overwriteLaunchFile(launchData) # update workspace file with "cortex-debug" specifics wksFile.checkWorkspaceFile() wksData = wksFile.getWorkspaceFileData() wksData = wksFile.addBuildDataToWorkspaceFile(wksData, buildData) wksFile.overwriteWorkspaceFile(wksData)