示例#1
0
    def _copyZipDir(self, zipFilePath, inDirPath, path):
        '''
        Copy a directory from a ZIP archive to a filesystem directory

        @param zipFilePath: string
            The path of the ZIP archive
        @param inDirPath: string
            The path to the file in the ZIP archive
        @param path: string
            Destination path where the ZIP directory is copied
        '''
        # make sure the ZIP file path is normalized and uses the OS separator
        zipFilePath = normOSPath(zipFilePath)
        # make sure the ZIP file path is normalized and uses the ZIP separator
        inDirPath = normZipPath(inDirPath)
        zipFile = ZipFile(zipFilePath)
        if isdir(path):
            if self._isSyncFile(zipFilePath, path):
                return
            rmtree(path)
        entries = [ent for ent in zipFile.namelist() if ent.startswith(inDirPath)]
        tmpDir = TemporaryDirectory()
        zipFile.extractall(tmpDir.name, entries)
        tmpDirPath = join(tmpDir.name, normOSPath(inDirPath))
        os.makedirs(path)
        for entry in os.listdir(tmpDirPath):
            move(join(tmpDirPath, entry), path)
示例#2
0
    def _copyZipDir(self, zipFilePath, inDirPath, path):
        '''
        Copy a directory from a ZIP archive to a filesystem directory

        @param zipFilePath: string
            The path of the ZIP archive
        @param inDirPath: string
            The path to the file in the ZIP archive
        @param path: string
            Destination path where the ZIP directory is copied
        '''
        # make sure the ZIP file path is normalized and uses the OS separator
        zipFilePath = normOSPath(zipFilePath)
        # make sure the ZIP file path is normalized and uses the ZIP separator
        inDirPath = normZipPath(inDirPath)
        zipFile = ZipFile(zipFilePath)
        entries = [ent for ent in zipFile.namelist() if ent.startswith(inDirPath)]
        tmpDir = TemporaryDirectory()
        zipFile.extractall(tmpDir.name, entries)
        tmpDirPath = join(tmpDir.name, normOSPath(inDirPath))
        if not isdir(path): os.makedirs(path)
        for entry in os.listdir(tmpDirPath):
            dstPath = join(path, entry)
            if isfile(dstPath): os.remove(dstPath)
            elif isdir(dstPath): rmtree(dstPath)
            move(join(tmpDirPath, entry), path)
示例#3
0
    def process(self, errorProcessing, chain, request, response, responseCnt, **keyargs):
        '''
        @see: HandlerProcessor.process
        
        Provide the file content as a response.
        '''
        assert isinstance(errorProcessing, Processing), 'Invalid processing %s' % errorProcessing
        assert isinstance(chain, Chain), 'Invalid processors chain %s' % chain
        assert isinstance(request, Request), 'Invalid request %s' % request
        assert isinstance(response, Response), 'Invalid response %s' % response
        assert isinstance(responseCnt, ResponseContent), 'Invalid response content %s' % responseCnt

        if request.method != GET:
            response.allows = GET
            response.code, response.text = METHOD_NOT_AVAILABLE, 'Path only available for GET'
        else:
            chain.proceed()
            # Make sure the given path points inside the repository
            entryPath = normOSPath(join(self.repositoryPath, normZipPath(unquote(request.uri))))
            if not entryPath.startswith(self.repositoryPath):
                response.code, response.text = RESOURCE_NOT_FOUND, 'Out of repository path'
            else:
                # Initialize the read file handler with None value
                # This will be set upon successful file open
                rf = None
                if isfile(entryPath):
                    rf, size = open(entryPath, 'rb'), os.path.getsize(entryPath)
                else:
                    linkPath = entryPath
                    while len(linkPath) > len(self.repositoryPath):
                        if isfile(linkPath + self._linkExt):
                            with open(linkPath + self._linkExt) as f: links = json.load(f)
                            subPath = normOSPath(entryPath[len(linkPath):]).lstrip(sep)
                            for linkType, *data in links:
                                if linkType in self._linkTypes:
                                    # make sure the subpath is normalized and uses the OS separator
                                    if not self._isPathDeleted(join(linkPath, subPath)):
                                        entry = self._linkTypes[linkType](subPath, *data)
                                        if entry is not None:
                                            rf, size = entry
                                            break
                            break
                        subLinkPath = dirname(linkPath)
                        if subLinkPath == linkPath:
                            break
                        linkPath = subLinkPath
        
                if rf is None:
                    response.code, response.text = METHOD_NOT_AVAILABLE, 'Invalid content resource'
                else:
                    response.code, response.text = RESOURCE_FOUND, 'Resource found'
                    responseCnt.source = rf
                    responseCnt.length = size
                    responseCnt.type, _encoding = guess_type(entryPath)
                    if not responseCnt.type: responseCnt.type = self.defaultContentType
                    return
        
        chain.branch(errorProcessing)
示例#4
0
    def process(self, request:Request, response:Response, responseCnt:ResponseContent, **keyargs):
        '''
        @see: HandlerProcessorProceed.process
        
        Provide the file content as a response.
        '''
        assert isinstance(request, Request), 'Invalid request %s' % request
        assert isinstance(response, Response), 'Invalid response %s' % response
        assert isinstance(responseCnt, ResponseContent), 'Invalid response content %s' % responseCnt

        if request.method != HTTP_GET:
            if response.allows is not None: response.allows.append(HTTP_GET)
            else: response.allows = [HTTP_GET]
            response.code, response.status, response.isSuccess = METHOD_NOT_AVAILABLE
        else:
            # Make sure the given path points inside the repository
            entryPath = normOSPath(join(self.repositoryPath, normZipPath(unquote(request.uri))))
            if not entryPath.startswith(self.repositoryPath):
                response.code, response.status, response.isSuccess = PATH_NOT_FOUND
            else:
                # Initialize the read file handler with None value
                # This will be set upon successful file open
                rf = None
                if isfile(entryPath):
                    rf, size = open(entryPath, 'rb'), os.path.getsize(entryPath)
                else:
                    linkPath = entryPath
                    while len(linkPath) > len(self.repositoryPath):
                        if isfile(linkPath + self._linkExt):
                            with open(linkPath + self._linkExt) as f: links = json.load(f)
                            subPath = normOSPath(entryPath[len(linkPath):]).lstrip(sep)
                            for linkType, *data in links:
                                if linkType in self._linkTypes:
                                    # make sure the subpath is normalized and uses the OS separator
                                    if not self._isPathDeleted(join(linkPath, subPath)):
                                        entry = self._linkTypes[linkType](subPath, *data)
                                        if entry is not None:
                                            rf, size = entry
                                            break
                            break
                        subLinkPath = dirname(linkPath)
                        if subLinkPath == linkPath:
                            break
                        linkPath = subLinkPath
        
                if rf is None:
                    response.code, response.status, response.isSuccess = PATH_NOT_FOUND
                else:
                    response.code, response.status, response.isSuccess = PATH_FOUND
                    responseCnt.source = rf
                    responseCnt.length = size
                    responseCnt.type, _encoding = guess_type(entryPath)
                    if not responseCnt.type: responseCnt.type = self.defaultContentType
                    responseCnt.type += '; charset=utf-8'
                    return
示例#5
0
 def _processZiplink(self, subPath, zipFilePath, inFilePath):
     '''
     Reads a link description file and returns a file handler to
     the linked file inside the ZIP archive.
     '''
     # make sure the ZIP file path uses the OS separator
     zipFilePath = normOSPath(zipFilePath)
     # convert the internal ZIP path to OS format in order to use standard path functions
     inFilePath = normOSPath(inFilePath)
     zipFile = ZipFile(zipFilePath)
     # resource internal ZIP path should be in ZIP format
     resPath = normZipPath(join(inFilePath, subPath))
     if resPath in zipFile.NameToInfo:
         return zipFile.open(resPath, 'r'), zipFile.getinfo(resPath).file_size
示例#6
0
    def _isValidZIPLink(self, link, subPath):
        '''
        Returns true if the file identified by subpath exists in
        the given link to a ZIP archive, false otherwise.

        @param link: list
            Link description in JSON format.
        @param subPath: string
            The path inside the linked directory (if needed)
        '''
        zipFilePath = normOSPath(link[1])
        inFilePath = normOSPath(link[2], True)
        zipFile = ZipFile(zipFilePath)
        inZipFile = normZipPath(join(inFilePath, subPath)) if subPath else normZipPath(inFilePath)
        return inZipFile in zipFile.NameToInfo
示例#7
0
 def _processZiplink(self, subPath, zipFilePath, inFilePath):
     '''
     Reads a link description file and returns a file handler to
     the linked file inside the ZIP archive.
     '''
     # make sure the ZIP file path uses the OS separator
     zipFilePath = normOSPath(zipFilePath)
     # convert the internal ZIP path to OS format in order to use standard path functions
     inFilePath = normOSPath(inFilePath)
     zipFile = ZipFile(zipFilePath)
     # resource internal ZIP path should be in ZIP format
     resPath = normZipPath(join(inFilePath, subPath))
     if resPath in zipFile.NameToInfo:
         return zipFile.open(resPath,
                             'r'), zipFile.getinfo(resPath).file_size
示例#8
0
    def _isValidZIPLink(self, link, subPath):
        '''
        Returns true if the file identified by subpath exists in
        the given link to a ZIP archive, false otherwise.

        @param link: list
            Link description in JSON format.
        @param subPath: string
            The path inside the linked directory (if needed)
        '''
        zipFilePath = normOSPath(link[1])
        inFilePath = normOSPath(link[2], True)
        zipFile = ZipFile(zipFilePath)
        inZipFile = normZipPath(join(inFilePath, subPath)) if subPath else normZipPath(inFilePath)
        return inZipFile in zipFile.NameToInfo
示例#9
0
 def __init__(self):
     assert isinstance(self.serverURI, str), 'Invalid server URI value %s' % self.serverURI
     assert isinstance(self.repositoryPath, str), 'Invalid repository directory value %s' % self.repositoryPath
     self.repositoryPath = normOSPath(self.repositoryPath)
     if not os.path.exists(self.repositoryPath): os.makedirs(self.repositoryPath)
     assert isdir(self.repositoryPath) and os.access(self.repositoryPath, os.W_OK), \
     'Unable to access the repository directory %s' % self.repositoryPath
示例#10
0
 def __init__(self):
     assert isinstance(self.serverURI, str), 'Invalid server URI value %s' % self.serverURI
     assert isinstance(self.repositoryPath, str), 'Invalid repository directory value %s' % self.repositoryPath
     self.repositoryPath = normOSPath(self.repositoryPath)
     if not os.path.exists(self.repositoryPath): os.makedirs(self.repositoryPath)
     assert isdir(self.repositoryPath) and os.access(self.repositoryPath, os.W_OK), \
     'Unable to access the repository directory %s' % self.repositoryPath
示例#11
0
 def publishFromDir(self, path, dirPath):
     '''
     @see ICDM.publishFromDir
     '''
     assert isinstance(
         path, str) and len(path) > 0, 'Invalid content path %s' % path
     assert isinstance(dirPath,
                       str), 'Invalid directory path value %s' % dirPath
     path, fullPath = self._validatePath(path)
     if not isdir(dirPath):
         # not a directory, see if it's a entry in a zip file
         zipFilePath, inDirPath = getZipFilePath(
             dirPath, self.delivery.getRepositoryPath())
         if not inDirPath.endswith(ZIPSEP): inDirPath = inDirPath + ZIPSEP
         self._copyZipDir(zipFilePath, inDirPath, fullPath)
         assert log.debug('Success publishing ZIP dir %s (%s) to path %s',
                          inDirPath, zipFilePath, path) or True
         return
     dirPath = normpath(dirPath)
     assert os.access(
         dirPath, os.R_OK), 'Unable to read the directory path %s' % dirPath
     for root, _dirs, files in os.walk(dirPath):
         relPath = relpath(root, dirPath)
         for file in files:
             publishPath = join(normOSPath(path), relPath.lstrip(os.sep),
                                file)
             filePath = join(root, file)
             self.publishFromFile(publishPath, filePath)
         assert log.debug('Success publishing directory %s to path %s',
                          dirPath, path) or True
示例#12
0
 def __init__(self):
     assert isinstance(self.dumpRequestsSize, int), 'Invalid dump size %s' % self.dumpRequestsSize
     assert isinstance(self.dumpRequestsPath, str), 'Invalid dump path %s' % self.dumpRequestsPath
     self.dumpRequestsPath = normOSPath(self.dumpRequestsPath)
     if not os.path.exists(self.dumpRequestsPath): os.makedirs(self.dumpRequestsPath)
     assert isdir(self.dumpRequestsPath) and os.access(self.dumpRequestsPath, os.W_OK), \
     'Unable to access the dump directory %s' % self.dumpRequestsPath
     super().__init__()
     
     self._count = 0
示例#13
0
    def _removeZiplink(self, link, path, entryPath, subPath):
        '''
        Removes a link to a file or directory in a ZIP archive.

        @param link: list
            Link description in JSON format.
        @param path: string
            The repository path to remove.
        @param entryPath: string
            The full path for which to create the deletion mark.
        @param subPath: string
            The path inside the linked ZIP archive.
        '''
        zipFilePath = normOSPath(link[1])
        inFilePath = normOSPath(link[2], True)
        zipFile = ZipFile(zipFilePath)
        inZipFile = normZipPath(join(inFilePath, subPath))
        if not inZipFile in zipFile.NameToInfo:
            raise PathNotFound(path)
        self._createDelMark(entryPath)
示例#14
0
    def _removeZiplink(self, link, path, entryPath, subPath):
        '''
        Removes a link to a file or directory in a ZIP archive.

        @param link: list
            Link description in JSON format.
        @param path: string
            The repository path to remove.
        @param entryPath: string
            The full path for which to create the deletion mark.
        @param subPath: string
            The path inside the linked ZIP archive.
        '''
        zipFilePath = normOSPath(link[1])
        inFilePath = normOSPath(link[2], True)
        zipFile = ZipFile(zipFilePath)
        inZipFile = normZipPath(join(inFilePath, subPath))
        if not inZipFile in zipFile.NameToInfo:
            raise PathNotFound(path)
        self._createDelMark(entryPath)
示例#15
0
def synchronizeURIToDir(path, dirPath):
    '''
    Publishes the entire contents from the URI path to the provided directory path.

    @param path: string
        The path to a resource: a file system path, a ZIP path
    @param dirPath: string
        The directory path to synchronize with.
    '''
    assert isinstance(path, str) and path, 'Invalid content path %s' % path
    assert isinstance(dirPath, str), 'Invalid directory path value %s' % dirPath

    if not isdir(path):
        # not a directory, see if it's a entry in a zip file
        zipFilePath, inDirPath = getZipFilePath(path)
        zipFile = ZipFile(zipFilePath)
        if not inDirPath.endswith(ZIPSEP): inDirPath = inDirPath + ZIPSEP

        tmpDir = TemporaryDirectory()

        lenPath, zipTime = len(inDirPath), datetime.fromtimestamp(stat(zipFilePath).st_mtime)
        for zipInfo in zipFile.filelist:
            assert isinstance(zipInfo, ZipInfo), 'Invalid zip info %s' % zipInfo
            if zipInfo.filename.startswith(inDirPath):
                if zipInfo.filename[0] == '/': dest = zipInfo.filename[1:]
                else: dest = zipInfo.filename

                dest = normpath(join(dirPath, dest[lenPath:]))

                if exists(dest) and zipTime <= datetime.fromtimestamp(stat(dest).st_mtime): continue
                destDir = dirname(dest)
                if not exists(destDir): makedirs(destDir)

                zipFile.extract(zipInfo.filename, tmpDir.name)
                move(join(tmpDir.name, normOSPath(zipInfo.filename)), dest)
                if zipInfo.filename.endswith('.exe'): os.chmod(dest, stat(dest).st_mode | S_IEXEC)
        return

    path = normpath(path)
    assert os.access(path, os.R_OK), 'Unable to read the directory path %s' % path
    lenPath = len(path) + 1
    for root, _dirs, files in os.walk(path):
        for file in files:
            src, dest = join(root, file), join(dirPath, root[lenPath:], file)

            if exists(dest) and \
            datetime.fromtimestamp(stat(src).st_mtime) <= datetime.fromtimestamp(stat(dest).st_mtime): continue

            destDir = dirname(dest)
            if not exists(destDir): makedirs(destDir)
            copy(src, dest)
            if file.endswith('.exe'): os.chmod(dest, stat(dest).st_mode | S_IEXEC)
示例#16
0
    def __init__(self):
        assert isinstance(self.dumpRequestsSize,
                          int), 'Invalid dump size %s' % self.dumpRequestsSize
        assert isinstance(self.dumpRequestsPath,
                          str), 'Invalid dump path %s' % self.dumpRequestsPath
        self.dumpRequestsPath = normOSPath(self.dumpRequestsPath)
        if not os.path.exists(self.dumpRequestsPath):
            os.makedirs(self.dumpRequestsPath)
        assert isdir(self.dumpRequestsPath) and os.access(self.dumpRequestsPath, os.W_OK), \
        'Unable to access the dump directory %s' % self.dumpRequestsPath
        super().__init__()

        self._count = 0
示例#17
0
def timestampURI(path):
    '''
    Returns the last modified time stamp for the given path.

    @param path: string
        The path to a resource: a file system path, a ZIP path
    @return: datetime
        The last modified time stamp.
    '''
    path = normOSPath(path)
    if isfile(path):
        return datetime.fromtimestamp(stat(path).st_mtime)
    zipFilePath, _inZipPath = getZipFilePath(path)
    return datetime.fromtimestamp(stat(zipFilePath).st_mtime)
示例#18
0
def timestampURI(path):
    '''
    Returns the last modified time stamp for the given path.

    @param path: string
        The path to a resource: a file system path, a ZIP path
    @return: datetime
        The last modified time stamp.
    '''
    path = normOSPath(path)
    if isfile(path):
        return datetime.fromtimestamp(stat(path).st_mtime)
    zipFilePath, _inZipPath = getZipFilePath(path)
    return datetime.fromtimestamp(stat(zipFilePath).st_mtime)
示例#19
0
 def _processLink(self, subPath, linkedFilePath):
     '''
     Reads a link description file and returns a file handler to
     the linked file.
     '''
     # make sure the file path uses the OS separator
     linkedFilePath = normOSPath(linkedFilePath)
     if isdir(linkedFilePath):
         resPath = join(linkedFilePath, subPath)
     elif not subPath:
         resPath = linkedFilePath
     else:
         return None
     if isfile(resPath):
         return open(resPath, 'rb'), os.path.getsize(resPath)
示例#20
0
 def _processLink(self, subPath, linkedFilePath):
     '''
     Reads a link description file and returns a file handler to
     the linked file.
     '''
     # make sure the file path uses the OS separator
     linkedFilePath = normOSPath(linkedFilePath)
     if isdir(linkedFilePath):
         resPath = join(linkedFilePath, subPath)
     elif not subPath:
         resPath = linkedFilePath
     else:
         return None
     if isfile(resPath):
         return open(resPath, 'rb'), os.path.getsize(resPath)
示例#21
0
def openURI(path):
    """
    Returns a read file object for the given path.
    
    @param path: string
        The path to a resource: a file system path, a ZIP path
    @return: byte file
        A file like object that delivers bytes.
    """
    path = normOSPath(path)
    if isfile(path):
        return open(path, "rb")
    zipFilePath, inZipPath = getZipFilePath(path)
    zipFile = ZipFile(zipFilePath)
    if inZipPath in zipFile.NameToInfo and not inZipPath.endswith(ZIPSEP) and inZipPath != "":
        return zipFile.open(inZipPath)
    raise IOError("Invalid file path %s" % path)
示例#22
0
def openURI(path, byteMode=True):
    '''
    Returns a read file object for the given path.

    @param path: string
        The path to a resource: a file system path, a ZIP path
    @return: byte file
        A file like object that delivers bytes.
    '''
    path = normOSPath(path)
    mode = 'rb' if byteMode else 'rt'
    if isfile(path): return open(path, mode)
    zipFilePath, inZipPath = getZipFilePath(path)
    zipFile = ZipFile(zipFilePath)
    if inZipPath in zipFile.NameToInfo and not inZipPath.endswith(ZIPSEP) and inZipPath != '':
        f = zipFile.open(inZipPath)
        if byteMode: return f
        else: return StringIO(f.read().decode())
    raise IOError('Invalid file path %s' % path)
示例#23
0
def openURI(path, byteMode=True):
    '''
    Returns a read file object for the given path.

    @param path: string
        The path to a resource: a file system path, a ZIP path
    @return: byte file
        A file like object that delivers bytes.
    '''
    path = normOSPath(path)
    mode = 'rb' if byteMode else 'rt'
    if isfile(path): return open(path, mode)
    zipFilePath, inZipPath = getZipFilePath(path)
    zipFile = ZipFile(zipFilePath)
    if inZipPath in zipFile.NameToInfo and not inZipPath.endswith(
            ZIPSEP) and inZipPath != '':
        f = zipFile.open(inZipPath)
        if byteMode: return f
        else: return StringIO(f.read().decode())
    raise IOError('Invalid file path %s' % path)
示例#24
0
 def publishFromDir(self, path, dirPath):
     '''
     @see ICDM.publishFromDir
     '''
     assert isinstance(path, str) and len(path) > 0, 'Invalid content path %s' % path
     assert isinstance(dirPath, str), 'Invalid directory path value %s' % dirPath
     path, fullPath = self._validatePath(path)
     if not isdir(dirPath):
         # not a directory, see if it's a entry in a zip file
         zipFilePath, inDirPath = getZipFilePath(dirPath, self.delivery.getRepositoryPath())
         if not inDirPath.endswith(ZIPSEP): inDirPath = inDirPath + ZIPSEP
         self._copyZipDir(zipFilePath, inDirPath, fullPath)
         assert log.debug('Success publishing ZIP dir %s (%s) to path %s', inDirPath, zipFilePath, path) or True
         return
     dirPath = normpath(dirPath)
     assert os.access(dirPath, os.R_OK), 'Unable to read the directory path %s' % dirPath
     for root, _dirs, files in os.walk(dirPath):
         relPath = relpath(root, dirPath)
         for file in files:
             publishPath = join(normOSPath(path), relPath.lstrip(os.sep), file)
             filePath = join(root, file)
             self.publishFromFile(publishPath, filePath)
         assert log.debug('Success publishing directory %s to path %s', dirPath, path) or True
示例#25
0
    def testLocalFileSystemLinkCDM(self):
        d = HTTPDelivery()
        rootDir = TemporaryDirectory()
        d.serverURI = 'http://localhost/content/'
        d.repositoryPath = rootDir.name
        d.repositoryPath = '/var/www/repository'
#        ioc.Initializer.initialize(d)
        cdm = LocalFileSystemLinkCDM()
        cdm.delivery = d

        try:
            exceptionRaised = False
            cdm.publishFromFile('a/../../b', 'somefile.txt')
        except PathNotFound:
            exceptionRaised = True
        self.assertTrue(exceptionRaised, 'No exception was raised on out of repository path')

        # test publish from a file from the file system
        try:
            srcTmpFile = NamedTemporaryFile()
            dstFile = join('testdir7', 'tempfile.txt')
            cdm.publishFromFile(dstFile, srcTmpFile.name)
            dstLinkPath = join(d.getRepositoryPath(), dstFile + cdm._linkExt)
            self.assertTrue(isfile(dstLinkPath))
            with open(dstLinkPath) as f:
                links = json.load(f)
                self.assertIsInstance(links, list)
                self.assertEqual(links[0][0], 'FS')
                self.assertEqual(srcTmpFile.name, links[0][1])
                self.assertEqual(stat(srcTmpFile.name).st_mtime,
                                 cdm.getTimestamp('testdir7/tempfile.txt'))
        finally:
            rmtree(dirname(dstLinkPath))

        # test publish from a file from a zip archive
        try:
            dstFile = join('testdir8', 'tempfile2.txt')
            inFileName = join('dir1', 'subdir2', 'file1.txt')
            srcFilePath = join(dirname(__file__), 'test.zip', inFileName)
            cdm.publishFromFile(dstFile, srcFilePath)
            dstLinkPath = join(d.getRepositoryPath(), dstFile + cdm._linkExt)
            self.assertTrue(isfile(dstLinkPath))
            with open(dstLinkPath) as f:
                links = json.load(f)
                self.assertEqual(links[0][0], 'ZIP')
                zipPath = links[0][1]
                inPath = normOSPath(links[0][2], True)
                linkPath = join(zipPath, inPath)
                self.assertEqual(normpath(linkPath), normpath(srcFilePath))
                self.assertEqual(stat(join(dirname(__file__), 'test.zip')).st_mtime,
                                 cdm.getTimestamp('testdir8/tempfile2.txt'))
        finally:
            rmtree(dirname(dstLinkPath))

        # test publish from a directory from the file system
        srcTmpDir = TemporaryDirectory()
        dirs = (join(srcTmpDir.name, 'test1/subdir1'), join(srcTmpDir.name, 'test2/subdir1'))
        for dir in dirs:
            makedirs(dir)
            with open(join(dir, 'text.html'), 'w+') as _f: pass
        try:
            cdm.publishFromDir('testlink1', srcTmpDir.name)
            dstLinkPath = join(d.getRepositoryPath(), 'testlink1' + cdm._linkExt)
            self.assertTrue(isfile(dstLinkPath))
            with open(dstLinkPath) as f:
                links = json.load(f)
                self.assertEqual(links[0][0], 'FS')
                self.assertEqual(srcTmpDir.name, links[0][1])
                self.assertEqual(stat(join(srcTmpDir.name, 'test1/subdir1/text.html')).st_mtime,
                                 cdm.getTimestamp('testlink1/test1/subdir1/text.html'))
            # test path remove
            delPath1 = 'testlink1/test1/subdir1/text.html'
            cdm.removePath(delPath1)
            self.assertTrue(isfile(join(d.getRepositoryPath(), delPath1 + '.deleted')))
            delPath2 = 'testlink1/test1'
            cdm.removePath(delPath2)
            self.assertTrue(isfile(join(d.getRepositoryPath(), delPath2 + '.deleted')))
        finally:
            rmtree(join(d.getRepositoryPath(), 'testlink1'))
            remove(dstLinkPath)

        # test publish from a file from a zip archive
        try:
            srcFilePath = join(dirname(__file__), 'test.zip', 'dir1') + sep
            cdm.publishFromFile('testlink2', srcFilePath)
            dstLinkPath = join(d.getRepositoryPath(), 'testlink2' + cdm._linkExt)
            self.assertTrue(isfile(dstLinkPath))
            with open(dstLinkPath) as f:
                links = json.load(f)
                self.assertEqual(links[0][0], 'ZIP')
                zipPath = links[0][1]
                inPath = normOSPath(links[0][2], True)
                link = join(zipPath, inPath)
                self.assertEqual(link, srcFilePath)
                self.assertEqual(stat(join(dirname(__file__), 'test.zip')).st_mtime,
                                 cdm.getTimestamp('testlink2/subdir1/file1.txt'))
            # test path remove
            delPath1 = 'testlink2/subdir1/file1.txt'
            cdm.removePath(delPath1)
            self.assertTrue(isfile(join(d.getRepositoryPath(), delPath1 + '.deleted')))
            delPath2 = 'testlink2/subdir1/'
            self.assertTrue(isdir(join(d.getRepositoryPath(), delPath2)))
            cdm.removePath(delPath2)
            self.assertTrue(isfile(join(d.getRepositoryPath(), delPath2.rstrip('/') + '.deleted')))
            self.assertFalse(isdir(join(d.getRepositoryPath(), delPath2)))
            self.assertFalse(isfile(join(d.getRepositoryPath(), delPath1 + '.deleted')))
        finally:
            rmtree(join(d.getRepositoryPath(), 'testlink2'))
            remove(dstLinkPath)
示例#26
0
 def _validatePath(self, path):
     path = normOSPath(path, True)
     fullPath = normOSPath(self._getItemPath(path), True)
     if not fullPath.startswith(self.delivery.getRepositoryPath()):
         raise PathNotFound('Path is outside the repository: %s' % path)
     return (path, fullPath)
示例#27
0
 def _getItemPath(self, path):
     return join(self.delivery.getRepositoryPath(), normOSPath(path.lstrip(os.sep), True))
示例#28
0
def synchronizeURIToDir(path, dirPath):
    '''
    Publishes the entire contents from the URI path to the provided directory path.

    @param path: string
        The path to a resource: a file system path, a ZIP path
    @param dirPath: string
        The directory path to synchronize with.
    '''
    assert isinstance(path, str) and path, 'Invalid content path %s' % path
    assert isinstance(dirPath,
                      str), 'Invalid directory path value %s' % dirPath

    if not isdir(path):
        # not a directory, see if it's a entry in a zip file
        zipFilePath, inDirPath = getZipFilePath(path)
        zipFile = ZipFile(zipFilePath)
        if not inDirPath.endswith(ZIPSEP): inDirPath = inDirPath + ZIPSEP

        tmpDir = TemporaryDirectory()

        lenPath, zipTime = len(inDirPath), datetime.fromtimestamp(
            stat(zipFilePath).st_mtime)
        for zipInfo in zipFile.filelist:
            assert isinstance(zipInfo,
                              ZipInfo), 'Invalid zip info %s' % zipInfo
            if zipInfo.filename.startswith(inDirPath):
                if zipInfo.filename[0] == '/': dest = zipInfo.filename[1:]
                else: dest = zipInfo.filename

                dest = normpath(join(dirPath, dest[lenPath:]))

                if exists(dest) and zipTime <= datetime.fromtimestamp(
                        stat(dest).st_mtime):
                    continue
                destDir = dirname(dest)
                if not exists(destDir): makedirs(destDir)

                zipFile.extract(zipInfo.filename, tmpDir.name)
                move(join(tmpDir.name, normOSPath(zipInfo.filename)), dest)
                if zipInfo.filename.endswith('.exe'):
                    os.chmod(dest, stat(dest).st_mode | S_IEXEC)
        return

    path = normpath(path)
    assert os.access(path,
                     os.R_OK), 'Unable to read the directory path %s' % path
    lenPath = len(path) + 1
    for root, _dirs, files in os.walk(path):
        for file in files:
            src, dest = join(root, file), join(dirPath, root[lenPath:], file)

            if exists(dest) and \
            datetime.fromtimestamp(stat(src).st_mtime) <= datetime.fromtimestamp(stat(dest).st_mtime):
                continue

            destDir = dirname(dest)
            if not exists(destDir): makedirs(destDir)
            copy(src, dest)
            if file.endswith('.exe'):
                os.chmod(dest, stat(dest).st_mode | S_IEXEC)
示例#29
0
    def process(self, request: Request, response: Response,
                responseCnt: ResponseContent, **keyargs):
        '''
        @see: HandlerProcessorProceed.process
        
        Provide the file content as a response.
        '''
        assert isinstance(request, Request), 'Invalid request %s' % request
        assert isinstance(response, Response), 'Invalid response %s' % response
        assert isinstance(
            responseCnt,
            ResponseContent), 'Invalid response content %s' % responseCnt

        if request.method != HTTP_GET:
            if response.allows is not None: response.allows.append(HTTP_GET)
            else: response.allows = [HTTP_GET]
            response.code, response.status, response.isSuccess = METHOD_NOT_AVAILABLE
        else:
            # Make sure the given path points inside the repository
            entryPath = normOSPath(
                join(self.repositoryPath, normZipPath(unquote(request.uri))))
            if not entryPath.startswith(self.repositoryPath):
                response.code, response.status, response.isSuccess = PATH_NOT_FOUND
            else:
                # Initialize the read file handler with None value
                # This will be set upon successful file open
                rf = None
                if isfile(entryPath):
                    rf, size = open(entryPath,
                                    'rb'), os.path.getsize(entryPath)
                else:
                    linkPath = entryPath
                    while len(linkPath) > len(self.repositoryPath):
                        if isfile(linkPath + self._linkExt):
                            with open(linkPath + self._linkExt) as f:
                                links = json.load(f)
                            subPath = normOSPath(
                                entryPath[len(linkPath):]).lstrip(sep)
                            for linkType, *data in links:
                                if linkType in self._linkTypes:
                                    # make sure the subpath is normalized and uses the OS separator
                                    if not self._isPathDeleted(
                                            join(linkPath, subPath)):
                                        entry = self._linkTypes[linkType](
                                            subPath, *data)
                                        if entry is not None:
                                            rf, size = entry
                                            break
                            break
                        subLinkPath = dirname(linkPath)
                        if subLinkPath == linkPath:
                            break
                        linkPath = subLinkPath

                if rf is None:
                    response.code, response.status, response.isSuccess = PATH_NOT_FOUND
                else:
                    response.code, response.status, response.isSuccess = PATH_FOUND
                    responseCnt.source = rf
                    responseCnt.length = size
                    responseCnt.type, _encoding = guess_type(entryPath)
                    if not responseCnt.type:
                        responseCnt.type = self.defaultContentType
                    responseCnt.type += '; charset=utf-8'
                    return
示例#30
0
    def testLocalFilesystemCDM(self):
        d = HTTPDelivery()
        rootDir = TemporaryDirectory()
        d.serverURI = 'http://localhost/content/'
        d.repositoryPath = rootDir.name
#        d.repositoryPath = '/var/www/repository'
#        ioc.Initializer.initialize(d)
        cdm = LocalFileSystemCDM()
        cdm.delivery = d

        # test publish from a file from the file system
        try:
            srcTmpFile = NamedTemporaryFile(delete=False)
            srcTmpFile.close()
            dstPath = 'testdir1/tempfile.txt'
            cdm.publishFromFile(dstPath, srcTmpFile.name)
            dstFilePath = join(d.getRepositoryPath(), normOSPath(dstPath))
            self.assertTrue(isfile(dstFilePath))
            self.assertEqual(datetime.fromtimestamp(stat(dstFilePath).st_mtime),
                             cdm.getTimestamp(dstPath))
        finally:
            rmtree(dirname(dstFilePath))
            remove(srcTmpFile.name)

        # test publish from a file from a zip archive
        try:
            inFileName = join('dir1', 'subdir2', 'file1.txt')
            dstPath = join('testdir2', 'tempfile2.txt')
            cdm.publishFromFile(dstPath,
                                join(dirname(__file__), 'test.zip', inFileName))
            dstFilePath = join(d.getRepositoryPath(), normOSPath(dstPath))
            self.assertTrue(isfile(dstFilePath))
        finally:
            rmtree(dirname(dstFilePath))

        # test publish from a directory from the file system
        srcTmpDir = TemporaryDirectory()
        dirs = ('test1/subdir1', 'test2/subdir1')
        for dir in dirs:
            fullPath = join(srcTmpDir.name, dir)
            makedirs(fullPath)
            with open(join(fullPath, 'text.html'), 'w') as _f: pass
        try:
            cdm.publishFromDir('testdir3', srcTmpDir.name)
            dstDirPath = join(d.getRepositoryPath(), 'testdir3')
            for dir in dirs:
                dstFilePath = join(dstDirPath, dir, 'text.html')
                self.assertTrue(isfile(dstFilePath))
                self.assertEqual(datetime.fromtimestamp(stat(dstFilePath).st_mtime),
                                 cdm.getTimestamp(join('testdir3', dir, 'text.html')))
            # test remove path
            filePath = 'testdir3/test1/subdir1/text.html'
            self.assertTrue(isfile(join(d.getRepositoryPath(), filePath)))
            cdm.republish(filePath, filePath + '.new')
            self.assertTrue(isfile(join(d.getRepositoryPath(), filePath + '.new')))
            cdm.republish(filePath + '.new', filePath)
            cdm.remove(filePath)
            self.assertFalse(isfile(join(d.getRepositoryPath(), filePath)))
            dirPath = 'testdir3/test2'
            self.assertTrue(isdir(join(d.getRepositoryPath(), dirPath)))
            cdm.remove(dirPath)
            self.assertFalse(isdir(join(d.getRepositoryPath(), dirPath)))
        finally:
            rmtree(dstDirPath)

        # test publish from a directory from a zip file
        try:
            cdm.publishFromDir('testdir4', join(dirname(__file__), 'test.zip', 'dir1'))
            dstDirPath = join(d.getRepositoryPath(), 'testdir4')
            dstFilePath = join(dstDirPath, 'subdir1', 'file1.txt')
            self.assertTrue(isfile(dstFilePath))
            dstFilePath = join(dstDirPath, 'subdir2', 'file2.txt')
            self.assertTrue(isfile(dstFilePath))
            # Test whether republishing the same directory checks the last modified date
            # The file created manually in the repository should not be deleted because
            # the zip archive was not modified from the last publish
            dstFilePath = join(dstDirPath, 'sometestfile.txt')
            with open(dstFilePath, 'w') as _f: pass
            cdm.publishFromDir('testdir4', join(dirname(__file__), 'test.zip', 'dir1'))
            self.assertTrue(isfile(dstFilePath))
        finally:
            rmtree(dstDirPath)

        # test publish from a string
        try:
            path = join('testdir5', 'somecontent.txt')
            cdm.publishContent(path, BytesIO(b'test'))
            dstFilePath = join(d.getRepositoryPath(), path)
            self.assertTrue(isfile(dstFilePath))
        finally:
            rmtree(join(d.getRepositoryPath(), dirname(path)))

        # test publish from a file object
        try:
            path = join('testdir6', 'somecontent2.txt')
            cdm.publishFromFile(path, BytesIO(b'test 2'))
            dstFilePath = join(d.getRepositoryPath(), path)
            self.assertTrue(isfile(dstFilePath))
        finally:
            rmtree(join(d.getRepositoryPath(), dirname(path)))
示例#31
0
    def testLocalFileSystemLinkCDM(self):
        d = HTTPDelivery()
        rootDir = TemporaryDirectory()
        d.serverURI = 'http://localhost/content/'
        d.repositoryPath = rootDir.name
        #        d.repositoryPath = '/var/www/repository'
        #        ioc.Initializer.initialize(d)
        cdm = LocalFileSystemLinkCDM()
        cdm.delivery = d

        try:
            exceptionRaised = False
            cdm.publishFromFile('a/../../b', 'somefile.txt')
        except PathNotFound:
            exceptionRaised = True
        self.assertTrue(exceptionRaised,
                        'No exception was raised on out of repository path')

        # test publish from a file from the file system
        try:
            srcTmpFile = NamedTemporaryFile()
            dstFile = join('testdir7', 'tempfile.txt')
            cdm.publishFromFile(dstFile, srcTmpFile.name)
            dstLinkPath = join(d.getRepositoryPath(), dstFile + cdm._linkExt)
            self.assertTrue(isfile(dstLinkPath))
            with open(dstLinkPath) as f:
                links = json.load(f)
                self.assertIsInstance(links, list)
                self.assertEqual(links[0][0], 'FS')
                self.assertEqual(srcTmpFile.name, links[0][1])
                self.assertEqual(
                    datetime.fromtimestamp(stat(srcTmpFile.name).st_mtime),
                    cdm.getTimestamp('testdir7/tempfile.txt'))
        finally:
            rmtree(dirname(dstLinkPath))

        # test publish from a file from a zip archive
        try:
            dstFile = join('testdir8', 'tempfile2.txt')
            inFileName = join('dir1', 'subdir2', 'file1.txt')
            srcFilePath = join(dirname(__file__), 'test.zip', inFileName)
            cdm.publishFromFile(dstFile, srcFilePath)
            dstLinkPath = join(d.getRepositoryPath(), dstFile + cdm._linkExt)
            self.assertTrue(isfile(dstLinkPath))
            with open(dstLinkPath) as f:
                links = json.load(f)
                self.assertEqual(links[0][0], 'ZIP')
                zipPath = links[0][1]
                inPath = normOSPath(links[0][2], True)
                linkPath = join(zipPath, inPath)
                self.assertEqual(normpath(linkPath), normpath(srcFilePath))
                self.assertEqual(
                    datetime.fromtimestamp(
                        stat(join(dirname(__file__), 'test.zip')).st_mtime),
                    cdm.getTimestamp('testdir8/tempfile2.txt'))
        finally:
            rmtree(dirname(dstLinkPath))

        # test publish from a directory from the file system
        srcTmpDir = TemporaryDirectory()
        dirs = (join(srcTmpDir.name,
                     'test1/subdir1'), join(srcTmpDir.name, 'test2/subdir1'))
        for dir in dirs:
            makedirs(dir)
            with open(join(dir, 'text.html'), 'w+') as _f:
                pass
        try:
            cdm.publishFromDir('testlink1', srcTmpDir.name)
            dstLinkPath = join(d.getRepositoryPath(),
                               'testlink1' + cdm._linkExt)
            self.assertTrue(isfile(dstLinkPath))
            with open(dstLinkPath) as f:
                links = json.load(f)
                self.assertEqual(links[0][0], 'FS')
                self.assertEqual(srcTmpDir.name, links[0][1])
                self.assertEqual(
                    datetime.fromtimestamp(
                        stat(join(srcTmpDir.name,
                                  'test1/subdir1/text.html')).st_mtime),
                    cdm.getTimestamp('testlink1/test1/subdir1/text.html'))
            # test path remove
            delPath1 = 'testlink1/test1/subdir1/text.html'
            cdm.remove(delPath1)
            self.assertTrue(
                isfile(join(d.getRepositoryPath(), delPath1 + '.deleted')))
            delPath2 = 'testlink1/test1'
            cdm.remove(delPath2)
            self.assertTrue(
                isfile(join(d.getRepositoryPath(), delPath2 + '.deleted')))
        finally:
            rmtree(join(d.getRepositoryPath(), 'testlink1'))
            remove(dstLinkPath)

        # test publish from a file from a zip archive
        try:
            srcFilePath = join(dirname(__file__), 'test.zip', 'dir1') + sep
            cdm.publishFromFile('testlink2', srcFilePath)
            dstLinkPath = join(d.getRepositoryPath(),
                               'testlink2' + cdm._linkExt)
            self.assertTrue(isfile(dstLinkPath))
            with open(dstLinkPath) as f:
                links = json.load(f)
                self.assertEqual(links[0][0], 'ZIP')
                zipPath = links[0][1]
                inPath = normOSPath(links[0][2], True)
                link = join(zipPath, inPath)
                self.assertEqual(link, srcFilePath)
                self.assertEqual(
                    datetime.fromtimestamp(
                        stat(join(dirname(__file__), 'test.zip')).st_mtime),
                    cdm.getTimestamp('testlink2/subdir1/file1.txt'))
            # test path remove
            delPath1 = 'testlink2/subdir1/file1.txt'
            cdm.remove(delPath1)
            self.assertTrue(
                isfile(join(d.getRepositoryPath(), delPath1 + '.deleted')))
            delPath2 = 'testlink2/subdir1/'
            self.assertTrue(isdir(join(d.getRepositoryPath(), delPath2)))
            cdm.remove(delPath2)
            self.assertTrue(
                isfile(
                    join(d.getRepositoryPath(),
                         delPath2.rstrip('/') + '.deleted')))
            self.assertFalse(isdir(join(d.getRepositoryPath(), delPath2)))
            self.assertFalse(
                isfile(join(d.getRepositoryPath(), delPath1 + '.deleted')))
        finally:
            rmtree(join(d.getRepositoryPath(), 'testlink2'))
            remove(dstLinkPath)
示例#32
0
 def _validatePath(self, path):
     path = normZipPath(path)
     fullPath = normOSPath(self._getItemPath(path), True)
     if not fullPath.startswith(self.delivery.getRepositoryPath()):
         raise PathNotFound(path)
     return (path, fullPath)
示例#33
0
    def testLocalFilesystemCDM(self):
        d = HTTPDelivery()
        rootDir = TemporaryDirectory()
        d.serverURI = 'http://localhost/content/'
        d.repositoryPath = rootDir.name
        #        d.repositoryPath = '/var/www/repository'
        #        ioc.Initializer.initialize(d)
        cdm = LocalFileSystemCDM()
        cdm.delivery = d

        # test publish from a file from the file system
        try:
            srcTmpFile = NamedTemporaryFile(delete=False)
            srcTmpFile.close()
            dstPath = 'testdir1/tempfile.txt'
            cdm.publishFromFile(dstPath, srcTmpFile.name)
            dstFilePath = join(d.getRepositoryPath(), normOSPath(dstPath))
            self.assertTrue(isfile(dstFilePath))
            self.assertEqual(
                datetime.fromtimestamp(stat(dstFilePath).st_mtime),
                cdm.getTimestamp(dstPath))
        finally:
            rmtree(dirname(dstFilePath))
            remove(srcTmpFile.name)

        # test publish from a file from a zip archive
        try:
            inFileName = join('dir1', 'subdir2', 'file1.txt')
            dstPath = join('testdir2', 'tempfile2.txt')
            cdm.publishFromFile(
                dstPath, join(dirname(__file__), 'test.zip', inFileName))
            dstFilePath = join(d.getRepositoryPath(), normOSPath(dstPath))
            self.assertTrue(isfile(dstFilePath))
        finally:
            rmtree(dirname(dstFilePath))

        # test publish from a directory from the file system
        srcTmpDir = TemporaryDirectory()
        dirs = ('test1/subdir1', 'test2/subdir1')
        for dir in dirs:
            fullPath = join(srcTmpDir.name, dir)
            makedirs(fullPath)
            with open(join(fullPath, 'text.html'), 'w') as _f:
                pass
        try:
            cdm.publishFromDir('testdir3', srcTmpDir.name)
            dstDirPath = join(d.getRepositoryPath(), 'testdir3')
            for dir in dirs:
                dstFilePath = join(dstDirPath, dir, 'text.html')
                self.assertTrue(isfile(dstFilePath))
                self.assertEqual(
                    datetime.fromtimestamp(stat(dstFilePath).st_mtime),
                    cdm.getTimestamp(join('testdir3', dir, 'text.html')))
            # test remove path
            filePath = 'testdir3/test1/subdir1/text.html'
            self.assertTrue(isfile(join(d.getRepositoryPath(), filePath)))
            cdm.republish(filePath, filePath + '.new')
            self.assertTrue(
                isfile(join(d.getRepositoryPath(), filePath + '.new')))
            cdm.republish(filePath + '.new', filePath)
            cdm.remove(filePath)
            self.assertFalse(isfile(join(d.getRepositoryPath(), filePath)))
            dirPath = 'testdir3/test2'
            self.assertTrue(isdir(join(d.getRepositoryPath(), dirPath)))
            cdm.remove(dirPath)
            self.assertFalse(isdir(join(d.getRepositoryPath(), dirPath)))
        finally:
            rmtree(dstDirPath)

        # test publish from a directory from a zip file
        try:
            cdm.publishFromDir('testdir4',
                               join(dirname(__file__), 'test.zip', 'dir1'))
            dstDirPath = join(d.getRepositoryPath(), 'testdir4')
            dstFilePath = join(dstDirPath, 'subdir1', 'file1.txt')
            self.assertTrue(isfile(dstFilePath))
            dstFilePath = join(dstDirPath, 'subdir2', 'file2.txt')
            self.assertTrue(isfile(dstFilePath))
            # Test whether republishing the same directory checks the last modified date
            # The file created manually in the repository should not be deleted because
            # the zip archive was not modified from the last publish
            dstFilePath = join(dstDirPath, 'sometestfile.txt')
            with open(dstFilePath, 'w') as _f:
                pass
            cdm.publishFromDir('testdir4',
                               join(dirname(__file__), 'test.zip', 'dir1'))
            self.assertTrue(isfile(dstFilePath))
        finally:
            rmtree(dstDirPath)

        # test publish from a string
        try:
            path = join('testdir5', 'somecontent.txt')
            cdm.publishContent(path, BytesIO(b'test'))
            dstFilePath = join(d.getRepositoryPath(), path)
            self.assertTrue(isfile(dstFilePath))
        finally:
            rmtree(join(d.getRepositoryPath(), dirname(path)))

        # test publish from a file object
        try:
            path = join('testdir6', 'somecontent2.txt')
            cdm.publishFromFile(path, BytesIO(b'test 2'))
            dstFilePath = join(d.getRepositoryPath(), path)
            self.assertTrue(isfile(dstFilePath))
        finally:
            rmtree(join(d.getRepositoryPath(), dirname(path)))
    def testLocalFileSystemLinkCDM(self):
        d = HTTPDelivery()
        rootDir = TemporaryDirectory()
        d.serverURI = "http://localhost/content/"
        d.repositoryPath = rootDir.name
        #        d.repositoryPath = '/var/www/repository'
        #        ioc.Initializer.initialize(d)
        cdm = LocalFileSystemLinkCDM()
        cdm.delivery = d

        try:
            exceptionRaised = False
            cdm.publishFromFile("a/../../b", "somefile.txt")
        except PathNotFound:
            exceptionRaised = True
        self.assertTrue(exceptionRaised, "No exception was raised on out of repository path")

        # test publish from a file from the file system
        try:
            srcTmpFile = NamedTemporaryFile()
            dstFile = join("testdir7", "tempfile.txt")
            cdm.publishFromFile(dstFile, srcTmpFile.name)
            dstLinkPath = join(d.getRepositoryPath(), dstFile + cdm._linkExt)
            self.assertTrue(isfile(dstLinkPath))
            with open(dstLinkPath) as f:
                links = json.load(f)
                self.assertIsInstance(links, list)
                self.assertEqual(links[0][0], "FS")
                self.assertEqual(srcTmpFile.name, links[0][1])
                self.assertEqual(
                    datetime.fromtimestamp(stat(srcTmpFile.name).st_mtime), cdm.getTimestamp("testdir7/tempfile.txt")
                )
        finally:
            rmtree(dirname(dstLinkPath))

        # test publish from a file from a zip archive
        try:
            dstFile = join("testdir8", "tempfile2.txt")
            inFileName = join("dir1", "subdir2", "file1.txt")
            srcFilePath = join(dirname(__file__), "test.zip", inFileName)
            cdm.publishFromFile(dstFile, srcFilePath)
            dstLinkPath = join(d.getRepositoryPath(), dstFile + cdm._linkExt)
            self.assertTrue(isfile(dstLinkPath))
            with open(dstLinkPath) as f:
                links = json.load(f)
                self.assertEqual(links[0][0], "ZIP")
                zipPath = links[0][1]
                inPath = normOSPath(links[0][2], True)
                linkPath = join(zipPath, inPath)
                self.assertEqual(normpath(linkPath), normpath(srcFilePath))
                self.assertEqual(
                    datetime.fromtimestamp(stat(join(dirname(__file__), "test.zip")).st_mtime),
                    cdm.getTimestamp("testdir8/tempfile2.txt"),
                )
        finally:
            rmtree(dirname(dstLinkPath))

        # test publish from a directory from the file system
        srcTmpDir = TemporaryDirectory()
        dirs = (join(srcTmpDir.name, "test1/subdir1"), join(srcTmpDir.name, "test2/subdir1"))
        for dir in dirs:
            makedirs(dir)
            with open(join(dir, "text.html"), "w+") as _f:
                pass
        try:
            cdm.publishFromDir("testlink1", srcTmpDir.name)
            dstLinkPath = join(d.getRepositoryPath(), "testlink1" + cdm._linkExt)
            self.assertTrue(isfile(dstLinkPath))
            with open(dstLinkPath) as f:
                links = json.load(f)
                self.assertEqual(links[0][0], "FS")
                self.assertEqual(srcTmpDir.name, links[0][1])
                self.assertEqual(
                    datetime.fromtimestamp(stat(join(srcTmpDir.name, "test1/subdir1/text.html")).st_mtime),
                    cdm.getTimestamp("testlink1/test1/subdir1/text.html"),
                )
            # test path remove
            delPath1 = "testlink1/test1/subdir1/text.html"
            cdm.remove(delPath1)
            self.assertTrue(isfile(join(d.getRepositoryPath(), delPath1 + ".deleted")))
            delPath2 = "testlink1/test1"
            cdm.remove(delPath2)
            self.assertTrue(isfile(join(d.getRepositoryPath(), delPath2 + ".deleted")))
        finally:
            rmtree(join(d.getRepositoryPath(), "testlink1"))
            remove(dstLinkPath)

        # test publish from a file from a zip archive
        try:
            srcFilePath = join(dirname(__file__), "test.zip", "dir1") + sep
            cdm.publishFromFile("testlink2", srcFilePath)
            dstLinkPath = join(d.getRepositoryPath(), "testlink2" + cdm._linkExt)
            self.assertTrue(isfile(dstLinkPath))
            with open(dstLinkPath) as f:
                links = json.load(f)
                self.assertEqual(links[0][0], "ZIP")
                zipPath = links[0][1]
                inPath = normOSPath(links[0][2], True)
                link = join(zipPath, inPath)
                self.assertEqual(link, srcFilePath)
                self.assertEqual(
                    datetime.fromtimestamp(stat(join(dirname(__file__), "test.zip")).st_mtime),
                    cdm.getTimestamp("testlink2/subdir1/file1.txt"),
                )
            # test path remove
            delPath1 = "testlink2/subdir1/file1.txt"
            cdm.remove(delPath1)
            self.assertTrue(isfile(join(d.getRepositoryPath(), delPath1 + ".deleted")))
            delPath2 = "testlink2/subdir1/"
            self.assertTrue(isdir(join(d.getRepositoryPath(), delPath2)))
            cdm.remove(delPath2)
            self.assertTrue(isfile(join(d.getRepositoryPath(), delPath2.rstrip("/") + ".deleted")))
            self.assertFalse(isdir(join(d.getRepositoryPath(), delPath2)))
            self.assertFalse(isfile(join(d.getRepositoryPath(), delPath1 + ".deleted")))
        finally:
            rmtree(join(d.getRepositoryPath(), "testlink2"))
            remove(dstLinkPath)