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]
示例#4
0
    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)