summaryrefslogtreecommitdiff
path: root/fs/utils.py
blob: 85fa464ce25707bba4fc6874671c474a0ce6ac5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
"""

  fs.utils: high level utility functions for working with FS objects.

"""

import shutil
from mountfs import MountFS

def copyfile(src_fs, src_path, dst_fs, dst_path, chunk_size=16384):
    """Copy a file from one filesystem to another. Will use system copyfile, if both files have a syspath.
    Otherwise file will be copied a chunk at a time.

    src_fs -- Source filesystem object
    src_path -- Source path
    dst_fs -- Destination filesystem object
    dst_path -- Destination filesystem object
    chunk_size -- Size of chunks to move if system copyfile is not available (default 16K)

    """
    src_syspath = src_fs.getsyspath(src_path, default="")
    dst_syspath = dst_fs.getsyspath(dst_path, default="")

    # System copy if there are two sys paths
    if src_syspath and dst_syspath:
        shutil.copyfile(src_syspath, dst_syspath)
        return

    src, dst = None

    try:
        # Chunk copy
        src = src_fs.open(src_path, 'rb')
        dst = dst_fs.open(dst_path, 'wb')

        while True:
            chunk = src.read(chunk_size)
            if not chunk:
                break
            dst.write(chunk)

    finally:
        if src is not None:
            src.close()
        if dst is not None:
            dst.close()


def movefile(src_fs, src_path, dst_fs, dst_path, chunk_size=16384):
    """Move a file from one filesystem to another. Will use system copyfile, if both files have a syspath.
    Otherwise file will be copied a chunk at a time.

    src_fs -- Source filesystem object
    src_path -- Source path
    dst_fs -- Destination filesystem object
    dst_path -- Destination filesystem object
    chunk_size -- Size of chunks to move if system copyfile is not available (default 16K)

    """
    src_syspath = src_fs.getsyspath(src_path, default="")
    dst_syspath = dst_fs.getsyspath(dst_path, default="")

    # System copy if there are two sys paths
    if src_syspath and dst_syspath:
        shutil.movefile(src_syspath, dst_syspath)
        return

    src, dst = None

    try:
        # Chunk copy
        src = src_fs.open(src_path, 'rb')
        dst = dst_fs.open(dst_path, 'wb')

        while True:
            chunk = src.read(chunk_size)
            if not chunk:
                break
            dst.write(chunk)

        src_fs.remove(src)

    finally:
        if src is not None:
            src.close()
        if dst is not None:
            dst.close()


def movedir(fs1, fs2, ignore_errors=False, chunk_size=16384):
    """Moves contents of a directory from one filesystem to another.

    fs1 -- Source filesystem, or a tuple of (<filesystem>, <directory path>)
    fs2 -- Destination filesystem, or a tuple of (<filesystem>, <directory path>)
    ignore_errors -- If True, exceptions from file moves are ignored
    chunk_size -- Size of chunks to move if a simple copy is used

    """
    if isinstance(fs1, tuple):
        fs1, dir1 = fs1
        fs1 = fs1.opendir(dir1)
    if isinstance(fs2, tuple):
        fs2, dir2 = fs2
        fs2 = fs2.opendir(dir2)

    mount_fs = MountFS()
    mount_fs.mount('dir1', fs1)
    mount_fs.mount('dir2', fs2)
    mount_fs.movedir('dir1', 'dir2', ignore_errors=ignore_errors, chunk_size=chunk_size)


def copydir(fs1, fs2, ignore_errors=False, chunk_size=16384):
    """Copies contents of a directory from one filesystem to another.

    fs1 -- Source filesystem, or a tuple of (<filesystem>, <directory path>)
    fs2 -- Destination filesystem, or a tuple of (<filesystem>, <directory path>)
    ignore_errors -- If True, exceptions from file moves are ignored
    chunk_size -- Size of chunks to move if a simple copy is used

    """
    if isinstance(fs1, tuple):
        fs1, dir1 = fs1
        fs1 = fs1.opendir(dir1)
    if isinstance(fs2, tuple):
        fs2, dir2 = fs2
        fs2 = fs2.opendir(dir2)

    mount_fs = MountFS()
    mount_fs.mount('dir1', fs1)
    mount_fs.mount('dir2', fs2)
    mount_fs.copydir('dir1', 'dir2', ignore_errors=ignore_errors, chunk_size=chunk_size)


def countbytes(count_fs):
    """Returns the total number of bytes contained within files in a filesystem.

    count_fs -- A filesystem object

    """
    total = sum(count_fs.getsize(f) for f in count_fs.walkfiles())
    return total