<reponame>Strix-CZ/tsdb
#!/usr/bin/env python

import os
import os.path
import errno

class OSFS(object):
    def __init__(self, root):
        self.root = root

    def __str__(self):
        return '<OSFS: %s>' % self.root

    def __repr__(self):
        return '<OSFS: %s>' % self.root

    def resolve_path(self, path):
        if path[0] == '/':
            path = path[1:]
        return os.path.abspath(os.path.join(self.root, path))

    def exists(self, path):
        return os.path.exists(self.resolve_path(path))

    def isdir(self, path):
        return os.path.isdir(self.resolve_path(path))

    def isfile(self, path):
        return os.path.isfile(self.resolve_path(path))

    def getsize(self, path):
        return os.path.getsize(self.resolve_path(path))

    def makedir(self, path):
        return os.mkdir(self.resolve_path(path))

    def makedirs(self, path):
        return os.makedirs(self.resolve_path(path))

    def listdir(self, path):
        return os.listdir(self.resolve_path(path))

    def open(self, path, mode="r", **kwargs):
        return open(self.resolve_path(path), mode, **kwargs)

def get_fs(root, prefixes):
    """return an FS object suitable for the environment"""
    rootfs = OSFS(root)

    if not prefixes:
        return rootfs

    unionfs = UnionFS()
    unionfs.addfs(rootfs)

    for prefix in prefixes:
        unionfs.addfs(OSFS(prefix))

    return unionfs
    
class UnionFS(object):
    """Synthetic union file system.
    
    ``UnionFS`` creates a union filesystem by searching each subfilesystem in
    order to find files.  New files and directories are always created in the
    first subfilesystem.

    This is particularly useful in a situation where there is smaller, fast
    filesystem (eg. in RAM or on an SSD) for frequently accessed data and a
    larger, slower filesystem (eg. SATA or NFS) for less frequently accessed
    data.

    UnionFS does not handle the migration of data from one layer to the other.
    """

    def __init__(self):
        self.fs_sequence = []

    def _search(self, path):
        for fs in self.fs_sequence:
            if fs.exists(path):
                return fs

        return None

    def _not_found(self, path):
        e = IOError()
        e.filename = path
        e.errno = errno.ENOENT
        e.strerror = os.strerror(errno.ENOENT)
        return e

    def resolve_path(self, path):
        fs = self._search(path)
        if not fs:
            raise self._not_found(path)

        return fs.resolve_path(path)

    def addfs(self, fs):
        self.fs_sequence.append(fs)

    def exists(self, path):
        return self._search(path) is not None

    def isdir(self, path):
        fs = self._search(path)
        if fs:
            if os.path.isdir(fs.resolve_path(path)):
                return True

        return False

    def isfile(self, path):
        fs = self._search(path)
        if fs:
            if os.path.isfile(fs.resolve_path(path)):
                return True

        return False

    def getsize(self, path):
        return os.path.getsize(self.resolve_path(path))

    def listdir(self, path):
        files = []
        notfound_cnt = 0
        for fs in self.fs_sequence:
            try:
                files += fs.listdir(path)
            except IOError:
                pass
            except OSError, e:
                if e.errno != errno.ENOENT:
                    raise
                else:
                    notfound_cnt += 1

        if notfound_cnt == len(self.fs_sequence):
            raise self._not_found(path)

        return list(set(files))

    def makedir(self, path, **kwargs):
        fs = self.fs_sequence[0]
        return fs.makedir(path, **kwargs)

    def open(self, path, mode="r", **kwargs):
        if not self.exists(path) and mode in ('w', 'r+', 'w+', 'a+'):
            fs = self.fs_sequence[0]
            dir = os.path.dirname(path)
            if not fs.exists(dir):
                # the directory structure may exist in a backing store, but if
                # we're creating a file we need it to exist in the top layer
                fs.makedirs(dir)
            return fs.open(path, mode=mode, **kwargs)
        else:
            for fs in self.fs_sequence:
                if fs.exists(path):
                    return open(fs.resolve_path(path), mode=mode, **kwargs)

            raise self._not_found(path)

#!/usr/bin/env python

import os
import os.path
import errno

class OSFS(object):
    def __init__(self, root):
        self.root = root

    def __str__(self):
        return '<OSFS: %s>' % self.root

    def __repr__(self):
        return '<OSFS: %s>' % self.root

    def resolve_path(self, path):
        if path[0] == '/':
            path = path[1:]
        return os.path.abspath(os.path.join(self.root, path))

    def exists(self, path):
        return os.path.exists(self.resolve_path(path))

    def isdir(self, path):
        return os.path.isdir(self.resolve_path(path))

    def isfile(self, path):
        return os.path.isfile(self.resolve_path(path))

    def getsize(self, path):
        return os.path.getsize(self.resolve_path(path))

    def makedir(self, path):
        return os.mkdir(self.resolve_path(path))

    def makedirs(self, path):
        return os.makedirs(self.resolve_path(path))

    def listdir(self, path):
        return os.listdir(self.resolve_path(path))

    def open(self, path, mode="r", **kwargs):
        return open(self.resolve_path(path), mode, **kwargs)

def get_fs(root, prefixes):
    """return an FS object suitable for the environment"""
    rootfs = OSFS(root)

    if not prefixes:
        return rootfs

    unionfs = UnionFS()
    unionfs.addfs(rootfs)

    for prefix in prefixes:
        unionfs.addfs(OSFS(prefix))

    return unionfs
    
class UnionFS(object):
    """Synthetic union file system.
    
    ``UnionFS`` creates a union filesystem by searching each subfilesystem in
    order to find files.  New files and directories are always created in the
    first subfilesystem.

    This is particularly useful in a situation where there is smaller, fast
    filesystem (eg. in RAM or on an SSD) for frequently accessed data and a
    larger, slower filesystem (eg. SATA or NFS) for less frequently accessed
    data.

    UnionFS does not handle the migration of data from one layer to the other.
    """

    def __init__(self):
        self.fs_sequence = []

    def _search(self, path):
        for fs in self.fs_sequence:
            if fs.exists(path):
                return fs

        return None

    def _not_found(self, path):
        e = IOError()
        e.filename = path
        e.errno = errno.ENOENT
        e.strerror = os.strerror(errno.ENOENT)
        return e

    def resolve_path(self, path):
        fs = self._search(path)
        if not fs:
            raise self._not_found(path)

        return fs.resolve_path(path)

    def addfs(self, fs):
        self.fs_sequence.append(fs)

    def exists(self, path):
        return self._search(path) is not None

    def isdir(self, path):
        fs = self._search(path)
        if fs:
            if os.path.isdir(fs.resolve_path(path)):
                return True

        return False

    def isfile(self, path):
        fs = self._search(path)
        if fs:
            if os.path.isfile(fs.resolve_path(path)):
                return True

        return False

    def getsize(self, path):
        return os.path.getsize(self.resolve_path(path))

    def listdir(self, path):
        files = []
        notfound_cnt = 0
        for fs in self.fs_sequence:
            try:
                files += fs.listdir(path)
            except IOError:
                pass
            except OSError, e:
                if e.errno != errno.ENOENT:
                    raise
                else:
                    notfound_cnt += 1

        if notfound_cnt == len(self.fs_sequence):
            raise self._not_found(path)

        return list(set(files))

    def makedir(self, path, **kwargs):
        fs = self.fs_sequence[0]
        return fs.makedir(path, **kwargs)

    def open(self, path, mode="r", **kwargs):
        if not self.exists(path) and mode in ('w', 'r+', 'w+', 'a+'):
            fs = self.fs_sequence[0]
            dir = os.path.dirname(path)
            if not fs.exists(dir):
                # the directory structure may exist in a backing store, but if
                # we're creating a file we need it to exist in the top layer
                fs.makedirs(dir)
            return fs.open(path, mode=mode, **kwargs)
        else:
            for fs in self.fs_sequence:
                if fs.exists(path):
                    return open(fs.resolve_path(path), mode=mode, **kwargs)

            raise self._not_found(path)
#!/usr/bin/env python return an FS object suitable for the environment Synthetic union file system.          ``UnionFS`` creates a union filesystem by searching each subfilesystem in     order to find files.  New files and directories are always created in the     first subfilesystem.      This is particularly useful in a situation where there is smaller, fast     filesystem (eg. in RAM or on an SSD) for frequently accessed data and a     larger, slower filesystem (eg. SATA or NFS) for less frequently accessed     data.      UnionFS does not handle the migration of data from one layer to the other. # the directory structure may exist in a backing store, but if # we're creating a file we need it to exist in the top layer