def restoreOriginalMakefile(self): ''' Check wether current 'Makefile' has print capabilities. If it has, this means it was already altered by this script. If it was, replace it with backup copy: 'Makefile.backup'. If it does not have print capabilities, it is assumed 'Makefile' was regenerated with CubeMX tool - print function is added and backup file is overwritten with this new 'Makefile'. At the end, fresh 'Makefile' with print function should be available. ''' if utils.pathExists(utils.makefilePath): # Makefile exists, check if it is original (no print capabilities) if self.hasPrintCapabilities(utils.makefilePath): # Makefile exists, already modified if utils.pathExists(utils.makefileBackupPath): # can original file be restored from backup file? if self.hasPrintCapabilities(utils.makefileBackupPath): errorMsg = "Both, 'Makefile' and 'Makefile.backup' exists, but they are both modified!\n" errorMsg += "Did you manually delete, replace or modify any of Makefiles?\n" errorMsg += "-> Delete all Makefiles and regenerate with CubeMX." utils.printAndQuit(errorMsg) else: # original will be restored from backup file print( "Existing 'Makefile' file will be restored from 'Makefile.backup'." ) utils.copyAndRename(utils.makefileBackupPath, utils.makefilePath) else: errorMsg = "'Makefile.backup' does not exist, while 'Makefile' was already modified!\n" errorMsg += "Did you manually delete, replace or modify any of Makefiles?\n" errorMsg += "-> Delete all Makefiles and regenerate with CubeMX." utils.printAndQuit(errorMsg) else: print("Existing 'Makefile' file found (original).") utils.copyAndRename(utils.makefilePath, utils.makefileBackupPath) elif utils.pathExists(utils.makefileBackupPath): # Makefile does not exist, but Makefile.backup does if self.hasPrintCapabilities(utils.makefileBackupPath): errorMsg = "'Makefile.backup' exists, but is already modified!\n" errorMsg += "Did you manually delete, replace or modify any of Makefiles?\n" errorMsg += "-> Delete all Makefiles and regenerate with CubeMX." utils.printAndQuit(errorMsg) else: # original will be restored from backup file print( "'Makefile' file will be restored from 'Makefile.backup'.") utils.copyAndRename(utils.makefileBackupPath, utils.makefilePath) else: errorMsg = "No Makefiles available, unable to proceed!\n" errorMsg += "-> Regenerate with CubeMX." utils.printAndQuit(errorMsg) self.addMakefileCustomFunctions(pathToMakefile=utils.makefilePath)
def checkTasksFile(self): ''' Check if 'tasks.json' file exists. If it does, check if it is a valid JSON file. If it doesn't exist, create new according to template. ''' if utils.pathExists(utils.tasksPath): # file exists, check if it loads OK try: with open(utils.tasksPath, 'r') as tasksFile: json.load(tasksFile) print("Existing 'tasks.json' file found.") return except Exception as err: errorMsg = "Invalid 'tasks.json' file. Creating backup and new one.\n" errorMsg += "Possible cause: invalid json format or comments (not supported by this scripts). Error:\n" errorMsg += str(err) print(errorMsg) utils.copyAndRename(utils.tasksPath, utils.tasksBackupPath) self.createTasksFile() else: # 'tasks.json' file does not exist jet, create it according to template string self.createTasksFile()
def restoreOriginalMakefile(self): ''' Check wether current 'Makefile' has print capabilities. If it has, this means it was already altered by this script. If it was, replace it with backup copy: 'Makefile.backup'. If it does not have prin capabilities, is is assumed 'Makefile' was regenerated with CubeMX tool - print function is added and backup file is overwritten with this new 'Makefile'. At the end, add 'print-variable' capabilities ''' if utils.pathExists(utils.makefileBackupPath): # Makefile.backup exists, check if it is original (no print capabilities) if self.hasPrintCapabilities( pathToMakefile=utils.makefileBackupPath): errorMsg = "Makefile.backup exist, but looks like it was already modified!\n" errorMsg += "Did you manually delete, replace or modify any of Makefiles? " errorMsg += "Delete all Makefiles and regenerate with CubeMX." utils.printAndQuit(errorMsg) else: # OK - seems like original Makefile, replace Makefile with Makefile.backup, add print capabilities utils.copyAndRename(utils.makefileBackupPath, utils.makefilePath) else: # Makefile.backup does not exist, check if current Makefile has print capabilities. if self.hasPrintCapabilities(pathToMakefile=utils.makefilePath): errorMsg = "Looks like Makefile was already modified! Makefile.backup does not exist.\n" errorMsg += "Did you manually delete, replace or modify any of Makefiles? " errorMsg += "Delete all Makefiles and regenerate with CubeMX." utils.printAndQuit(errorMsg) else: # Makefile looks like an original one. Create a backup copy and add print capabilities utils.copyAndRename(utils.makefilePath, utils.makefileBackupPath) self.addMakefileCustomFunctions(pathToMakefile=utils.makefilePath)
def checkToolsPathFile(self): ''' Returns True if 'toolsPaths.json' file exists and is a valid JSON file. If it doesn't exist, delete it and return False. ''' if utils.pathExists(utils.toolsPaths): # file exists, check if it loads OK try: with open(utils.toolsPaths, 'r') as toolsFileHandler: data = json.load(toolsFileHandler) print("Valid 'toolsPaths.json' file found.") return True except Exception as err: errorMsg = "Invalid 'toolsPaths.json' file. Error:\n" + str( err) print(errorMsg) try: os.remove(utils.toolsPaths) errorMsg = "\tDeleted. New 'toolsPaths.json' will be created on first valid user paths update." print(errorMsg) except Exception as err: errorMsg = "\tError deleting 'toolsPaths.json'. Error:\n" + str( err) print(errorMsg) return False else: # toolsPaths.json does not exist return False
def checkCPropertiesFile(self): ''' Check if 'c_cpp_properties.json' file exists. If it does, check if it is a valid JSON file. If it doesn't exist, create new according to template. ''' if utils.pathExists(utils.cPropertiesPath): # file exists, check if it loads OK try: with open(utils.cPropertiesPath, 'r') as cPropertiesFile: currentData = json.load(cPropertiesFile) # this is a valid json file print("Existing valid 'c_cpp_properties.json' file found.") # merge current 'c_cpp_properties.json' with its template templateData = json.loads(tmpStr.c_cpp_template) dataToWrite = utils.mergeCurrentDataWithTemplate(currentData, templateData) dataToWrite = json.dumps(dataToWrite, indent=4, sort_keys=False) with open(utils.cPropertiesPath, 'w') as cPropertiesFile: cPropertiesFile.write(dataToWrite) print("\tKeys updated according to the template.") return except Exception as err: errorMsg = "Invalid 'c_cpp_properties.json' file. Creating backup and new one.\n" errorMsg += "Possible cause: invalid json format or comments (not supported by this scripts). Error:\n" errorMsg += str(err) print(errorMsg) utils.copyAndRename(utils.cPropertiesPath, utils.cPropertiesBackupPath) self.createCPropertiesFile() else: # 'c_cpp_properties.json' file does not exist jet, create it according to template string self.createCPropertiesFile()
def checkBuildDataFile(self): ''' This function makes sure 'buildData.json' is available. If existing 'buildData.json' file is a valid JSON, it returns immediately. If it is not a valid JSON file OR it does not exist, new 'buildData.json' file is created from template. Note: There is no backup file for buildData.json, since it is always regenerated on Update task. ''' if utils.pathExists(utils.buildDataPath): # file exists, check if it loads OK try: with open(utils.buildDataPath, 'r') as buildDataFileHandler: json.load(buildDataFileHandler) print("Valid 'buildData.json' file found.") return except Exception as err: errorMsg = "Invalid 'buildData.json' file. Error:\n" + str(err) print(errorMsg) try: os.remove(utils.buildDataPath) msg = "\tDeleted. New 'buildData.json' will be created on first workspace update." print(msg) except Exception as err: errorMsg = "Error deleting 'buildData.json'. Error:\n" + str( err) utils.printAndQuit(errorMsg) # else: buildData.json does not exist self.createBuildDataFile()
def checkToolsPathFile(self): ''' Returns True if 'toolsPaths.json' file exists and is a valid JSON file. If it is not a valid JSON, delete it and return False. ''' if utils.pathExists(utils.toolsPaths): # file exists, check if it loads OK try: with open(utils.toolsPaths, 'r') as toolsFileHandler: json.load(toolsFileHandler) print("Valid 'toolsPaths.json' file found. " + utils.toolsPaths) return True except Exception as err: errorMsg = "Invalid 'toolsPaths.json' file. Error:\n" + str( err) print(errorMsg) try: os.remove(utils.toolsPaths) msg = "\tDeleted. New 'toolsPaths.json' will be created on first workspace update." print(msg) except Exception as err: errorMsg = "Error deleting 'toolsPaths.json'. Error:\n" + str( err) utils.printAndQuit(errorMsg) # else: toolsPaths.json does not exist return False
def checkMakefileFile(self): ''' Check if 'Makefile' file exists. If it doesn't, report as error. ''' if not utils.pathExists(utils.makefilePath): errorMsg = "Makefile does not exist! Did CubeMX generated Makefile?\n" errorMsg += "File name must be 'Makefile'." utils.printAndQuit(errorMsg)
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. ''' # check if default path is command pathDefault = None if utils.commandExists(default): pathDefault = shutil.which(default) # if not a command, check if it's a path elif utils.pathExists(default): pathDefault = 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
def prepareBuildData(self, request=False): ''' This function is used in all 'update*.py' scripts and makes sure, that 'toolsPaths.json' and 'buildData.json' with a valid tools/target cofniguration paths exist. Invalid paths are updated (requested from the user). Returns available, valid build data. Note: tools paths listed in 'BuildDataStrings.toolsPaths' are stored in system local 'toolsPaths.json' file, and are copied (overwritten) to 'buildData.json' on first 'Update' task run. This makes it possible for multiple code contributors. ''' paths = pth.UpdatePaths() self.checkBuildDataFile() buildData = self.getBuildData() if self.checkToolsPathFile(): # a valid toolsPaths.json exists toolsPathsData = self.getToolsPathsData() else: # no valid data from 'toolsPaths.json' file # try to get data from current 'buildData.json' - backward compatibility for paths that already exist in 'buildData.json' toolsPathsData = json.loads(tmpStr.toolsPathsTemplate) for path in self.bStr.toolsPaths: if path in buildData: if utils.pathExists(buildData[path]): toolsPathsData[path] = buildData[path] # update/overwrite tools paths file. Don't mind if paths are already valid. toolsPathsData = paths.verifyToolsPaths(toolsPathsData, request) self.createUserToolsFile(toolsPathsData) buildData = self.addToolsPathsToBuildData(buildData, toolsPathsData) templateBuildData = json.loads(tmpStr.buildDataTemplate) buildData = utils.mergeCurrentDataWithTemplate(buildData, templateBuildData) buildData = paths.verifyTargetConfigurationPaths(buildData, request) buildData = paths.copyTargetConfigurationFiles(buildData) return buildData
def checkWorkspaceFile(self): ''' Check if workspace '*.code-workspace' file exists. If it does, check if it is a valid JSON file. If it doesn't exist report error and quit. ''' workspaceFiles = utils.getCodeWorkspaces() if len(workspaceFiles) == 1: _, fileName = os.path.split(workspaceFiles[0]) workspaceFileName, _ = os.path.splitext(fileName) if utils.pathExists(utils.workspaceFilePath): # file exists, check if it loads OK try: with open(utils.workspaceFilePath, 'r') as workspaceFile: workspaceFileData = json.load(workspaceFile) print("Existing " + workspaceFileName + " file found.") except Exception as err: errorMsg = "Invalid " + workspaceFileName + " file.\n" errorMsg += "Possible cause: invalid json format or comments (not supported by this scripts). Error:\n" errorMsg += str(err) print(errorMsg)
def checkBuildDataFile(self): ''' Check if 'buildData.json' file exists. If it does, check if it is a valid JSON file. If it doesn't exist, create new according to template. ''' if utils.pathExists(utils.buildDataPath): # file exists, check if it loads OK try: with open(utils.buildDataPath, 'r') as buildDataFile: data = json.load(buildDataFile) print("Existing 'buildData.json' file found.") except Exception as err: errorMsg = "Invalid 'buildData.json' file. Creating new one. Error:\n" errorMsg += "Possible cause: invalid json format or comments (not supported by this scripts). Error:\n" errorMsg += str(err) print(errorMsg) self.createBuildDataFile() else: # 'buildData.json' file does not exist jet, create it according to template string self.createBuildDataFile()
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 verifyExistingPaths(self, buildData, request=False): ''' This function checks if configuration paths (not workspace sources) from 'buildData.json' are valid paths. Common configuration paths are previoulsy fetched from 'toolsPaths.json'. If any path is not valid/missing, user is asked for update via updatePath(). Returns updated valid paths. ''' for pathName in self.bStr.configurationPaths: mustBeUpdated = False try: isPathValid = False if pathName in buildData: pathToCheck = buildData[pathName] if isinstance(pathToCheck, list): for path in pathToCheck: if not utils.pathExists(path): break else: isPathValid = True else: # not a list, a single path expected if utils.pathExists(pathToCheck): isPathValid = True else: # path not valid, check if command if utils.commandExists(pathToCheck): isPathValid = True if isPathValid: if request: # if the user made the path verification request msg = "\n\nValid paths for " + pathName + " detected: '" + str(pathToCheck) + "'.\n\tUpdate? [y/n]: " if utils.getYesNoAnswer(msg): mustBeUpdated = True else: # non-valid path, must be updated mustBeUpdated = True if mustBeUpdated: if pathName in [self.bStr.pythonExec, self.bStr.gccInludePath]: # derived paths, build later continue elif pathName in self.toolsList: name = self.toolsList[pathName]["name"] defaultPath = self.toolsList[pathName]["defaultPath"] buildData[pathName] = self.updatePath(name, defaultPath) # handle special paths cases - custom get() handlers elif pathName == self.bStr.openOcdInterfacePath: buildData[pathName] = utils.getOpenOcdInterface(buildData[self.bStr.openOcdPath]) elif pathName == self.bStr.openOcdConfig: # get openOcdConfig buildData[self.bStr.openOcdConfig] = utils.getOpenOcdConfig(buildData[self.bStr.openOcdInterfacePath]) # basic path question, default name else: buildData[pathName] = self.updatePath(pathName, None) except Exception as err: buildData[pathName] = self.updatePath(pathName, None) # get gccIncludePath buildData[self.bStr.gccInludePath] = utils.getGccIncludePath(buildData[self.bStr.gccExePath]) # get python3 executable buildData[self.bStr.pythonExec] = utils.getPython3Executable() return buildData