def modifyElement(element, previousValue): """ Updates the xml node corresponding to `element` in the correct file in the working directory. `element` has to be of type Attribute or SimpleElement. Other elements (e.g. comments, viewpoints, etc.) must not be of state modified since the modification is inside an child-member. """ logger.debug("Modifying element {}, its previous value was"\ " '{}'".format(element.__class__, previousValue)) if not (issubclass(type(element), p.SimpleElement) or issubclass(type(element), p.Attribute)): raise ValueError("Element is not an attribute or simple element. Only"\ " these two types can be updated. Actual type of element:"\ " {}".format(type(element))) # filename in which `element` will be found fileName = getFileOfElement(element) if not fileName: raise ValueError("For {} no file can be found that contains it."\ "file".format(element)) bcfPath = util.getBcfDir() # path of the topic `element` is contained in topicPath = os.path.join(bcfPath, getTopicDir(element)) # filepath of the file `element` is contained in filePath = os.path.join(topicPath, fileName) # parsed version of the file xmlfile = ET.parse(filePath) xmlroot = xmlfile.getroot() logger.debug("Modifying element in file"\ " {}".format(filePath)) # set element to old state to get more reliable matching newValue = element.value element.value = previousValue if issubclass(type(element), p.SimpleElement): logger.debug("Modifying the text of a simple xml node") parentElem = element.containingObject etElem = getEtElementFromFile(xmlroot, element, []) etElem.text = str(newValue) elif issubclass(type(element), p.Attribute): logger.debug("Modifying the value of an attribute") parentElem = element.containingObject parentEtElem = getEtElementFromFile(xmlroot, parentElem, []) parentEtElem.attrib[element.xmlName] = str(newValue) writeXMLFile(xmlroot, filePath)
def copyFileToProject(path: str, destName: str = "", topic: Topic = None): """ Copy the file behind `path` into the working directory. If `topic` is not None and references an existing topic in the project then the file behind path is copied into the topic directory. Otherwise it is copied into the root directory of the project. If `destName` is given the resulting filename will be the value of `destName`. Otherwise the original filename is used. Before everything takes place, a backup of the current project is made. If an error occurs, the current project will be rolled back to the backup. """ global curProject logger.info("Copying file {} into the project".format(path)) if not os.path.exists(path): logger.error("File `{}` does not exist. Nothing is beeing copied.") return OperationResults.FAILURE if not isProjectOpen(): return OperationResults.FAILURE srcFileName = os.path.basename(path) dstFileName = srcFileName if destName == "" else destName destPath = util.getBcfDir() if topic is not None: realTopic = _searchRealTopic(topic) if realTopic is None: return OperationResults.FAILURE destPath = os.path.join(destPath, str(realTopic.xmlId)) destPath = os.path.join(destPath, dstFileName) i = 1 while os.path.exists(destPath): if i == 1: logger.info("{} already exists.".format(destPath)) dir, file = os.path.split(destPath) splitFN = dstFileName.split(".") splitFN[0] += "({})".format(i) file = ".".join(splitFN) destPath = os.path.join(dir, file) i += 1 if i != 1: logger.info("Changed filename to {}.".format(destPath)) shutil.copyfile(path, destPath)
def getSnapshots(topic: Topic): """ Returns a list of files representing the snapshots contained in `topic`. No deep copy has to made here, since the list returnde by `markup.getSnapshotFileList()` is already a list of strings with no tie to the data model. Every entry of the list returned by `markup.getSnapshotFileList()` is assumed to be just the filename of the snapshot file. Thus the string is joined with the path to the working directory. """ logger.debug("Retrieving snapshots for topic {}".format(topic.title)) if not isProjectOpen(): return OperationResults.FAILURE realTopic = _searchRealTopic(topic) if realTopic is None: return OperationResults.FAILURE markup = realTopic.containingObject snapshots = markup.getSnapshotFileList() topicDir = os.path.join(util.getBcfDir(), str(realTopic.xmlId)) return [os.path.join(topicDir, snapshot) for snapshot in snapshots]
def getFilePath(self, index): """ Construct the file path of the document on `index`. Here a distinction between external and internal documents is made. For documents marked as internal the path to the working directory is prepended to the document's path. Otherwise the path is assumed to be absolute. The resulting path is to be returned. """ global bcfDir if not index.isValid(): return None if index.row() >= len(self.documents): return None doc = self.documents[index.row()] path = str(doc.reference) if not doc.external: sysTmp = util.getBcfDir() path = os.path.join(sysTmp, path) return path
def saveProject(dstFile): """ Save the current state of the working directory to `dstfile` """ logger.info("Saving the project to {}".format(dstFile)) bcfRootPath = util.getBcfDir() writer.zipToBcfFile(bcfRootPath, dstFile)
def deleteElement(element): """ Deletes `element` from the correct file in the working directory. Viewpoint files are only deleted if they are flagged with the state DELETED and their accompanying viewpoint references are also deleted. """ logger.debug("Deleting element {} from the working"\ " directory".format(element.__class__)) elementHierarchy = element.getHierarchyList() logger.debug("Deleting element {}".format(element)) # filename in which `element` will be found fileName = getFileOfElement(element) if not fileName: raise ValueError("For {} no file can be found to delete from"\ "".format(element.__class__.__name__)) bcfPath = util.getBcfDir() # path of the topic `element` is contained in topicPath = os.path.join(bcfPath, getTopicDir(element)) # filepath of the file `element` is contained in filePath = os.path.join(topicPath, fileName) # parsed version of the file xmlfile = ET.parse(filePath) xmlroot = xmlfile.getroot() logger.debug("Element is going to be deleted from file"\ " {}".format(filePath)) # if identifiable then search for the guid using xmlpath. if issubclass(type(element), iI.XMLIdentifiable): logger.debug("Deleting element by its GUID {}".format(element.xmlId)) deleteXMLIdentifiableElement(element, xmlroot) if isinstance(element, m.ViewpointReference): if element.viewpoint.state == iS.State.States.DELETED: vpElem = element.viewpoint vpFile = getFileOfElement(vpElem) if not vpFile: raise ValueError("No file could be found for element {}"\ "\nSo the element won't be deleted.".format(vpElem)) logger.debug("Also deleting viewpoint file {}".format(vpFile)) vpFilePath = os.path.join(topicPath, str(vpFile)) os.remove(vpFilePath) # attributes have to be deleted from the attrib dictionary elif isinstance(element, p.Attribute): logger.debug("Deleting element as attribute") parentElem = element.containingObject parentEtElem = getEtElementFromFile(xmlroot, parentElem, []) del parentEtElem.attrib[element.xmlName] # otherwise employ getEtElementFromFile to get the right element else: logger.debug("Element does not have an Id. Deleting it anyway.") fileEtElement = getEtElementFromFile(xmlroot, element, []) parentEtElement = getParentElement(element, xmlroot) #parentEtElement = getEtElementFromFile(xmlroot, #element.containingObject, []) parentEtElement.remove(fileEtElement) writeXMLFile(xmlroot, filePath)
def addElement(element): """ Adds a new element to the correct file in the working directory. In this context an element can be a simple or complex xml element as well as just an attribute of an element that was added to the datamodel and shall now be added to the file as well. Both additions have the following approach in common: - the current file is read into an xml.etree.ElementTree structure. - this structure is updated with the new values - the old file is overwritten with the updated xml.etree.ElementTree structure For the addition of attributes it is assumed that the containing element already exists in the file. This element is searched for and expanded by the new attribute. For the addition of elements the parent element is searched for, and in the predefined sequence of the parent the right insertion index is looked up, since the element cant just be appended, otherwise it would not be schema conform anymore. """ logger.debug("Adding element {} to the working"\ " directory.".format(element.__class__)) addToProject = False # filename in which `element` will be found fileName = getFileOfElement(element) if not fileName: raise ValueError("{} is not applicable to be added to anyone"\ "file".format(element.xmlName)) elif fileName == projectFileName: addToProject = True if fileName is None: raise NotImplementedError("Writing of bcf.version"\ " is not supported") bcfPath = util.getBcfDir() topicPath = "" if not addToProject: topicDir = getTopicDir(element) if not topicPath and addToProject: raise RuntimeError("Element {} could not be associated to any topic."\ "This may be the case if properties in project.bcfp should be"\ "modified, which is currently not implemented!".format(str(element))) topicPath = os.path.join(bcfPath, topicDir) filePath = "" if not addToProject: filePath = os.path.join(topicPath, fileName) # file path shall only be set if an element shall be added to project.bcfp # and not project.bcfp shall be created in the first place elif addToProject and not isinstance(element, p.Project): filePath = os.path.join(bcfPath, fileName) logger.debug("Element is going to be added to"\ " {}".format(filePath)) if isinstance(element, p.Project): workDir = util.getSystemTmp() logger.debug("Creating new project in {}".format(workDir)) _createProject(element, workDir) return # adds a complete new topic folder to the zip file if isinstance(element, m.Markup): logger.debug("Creating new markup file in"\ " {}".format(topicPath)) _createMarkup(element, topicPath) return xmltree = ET.parse(filePath) xmlroot = xmltree.getroot() # different handling for attributes and elements if isinstance(element, p.Attribute): logger.debug("Element is added as attribute.") xmlroot = _addAttribute(element, xmlroot) else: logger.debug("Element is added as XML node.") xmlroot = _addElement(element, xmlroot) # generate viewpoint.bcfv file for added viewpoint if (isinstance(element, m.ViewpointReference) and element.viewpoint is not None and element.viewpoint.state == iS.State.States.ADDED): logger.debug("Creating new viewpoint file in"\ " {}".format(topicPath)) _createViewpoint(element, topicPath) writeXMLFile(xmlroot, filePath)