filesystem.py 10.3 KB
Newer Older
Marcel's avatar
Marcel committed
1
# -*- coding: utf-8 -*-
2

Marcel's avatar
Marcel committed
3
# imports
4
5
6
7
8
9
import os
from datetime import datetime
import locale
import shutil
from mimetypes import guess_type
from zipfile import ZipFile
Marcel's avatar
Marcel committed
10

11
12
13
14
15
16
17
18
19
20
21
22

class FileSystem(object):

    FILE_EXTENSIONS = ["png", "jpg", "jpeg", "bmp", "ps", "eps", "pdf", "txt", "xml", "py", "c", "cpp", "root", "pxlio"]
    BROWSER_EXTENSIONS = ["png", "jpg", "jpeg", "bmp", "pdf"]
    ADDITIONAL_MIMES = {"pxlio": "text/plain",
                        "root" : "text/plain"}

    def __init__(self):
        # allowed extensions
        self.allowed_extensions = FileSystem.FILE_EXTENSIONS

23
24
25
    def setup(self, basedir=None):
        if basedir==None:
            basedir = os.path.expanduser("~")
murban's avatar
murban committed
26
27
28
29
        if not os.path.isdir(basedir):
            raise Exception("Basedir ("+str(basedir)+") does not exist!")
        # the basedir
        self.basedir = os.path.join(basedir, ".vispa")
30
31
32
33
34
        if os.path.isdir(self.basedir):
            return "Basedir already exists"
        else: 
            os.makedirs(self.basedir, 0700)
            return "Basedir now exists"
35

murban's avatar
murban committed
36
    def get_mime_type(self, filepath):
37
38
39
40
41
42
43
44
        mime, encoding = guess_type(filepath)
        if mime is not None:
            return mime
        ext = filepath.split(".")[-1]
        if ext is not None and ext != "" and ext.lower() in FileSystem.ADDITIONAL_MIMES.keys():
            return FileSystem.ADDITIONAL_MIMES[ext]
        return None

murban's avatar
murban committed
45
    def check_file_extension(self, path, extensions=[]):
46
47
48
49
50
51
52
53
        if (len(extensions) == 0):
            return True
        for elem in extensions:
            elem = elem if elem.startswith(".") else "." + elem
            if path.lower().endswith(elem.lower()):
                return True
        return False

murban's avatar
murban committed
54
    def exists(self, path, pathtype=None, fileextension=None, permissionmode="r"):
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
        if isinstance(permissionmode, str) and permissionmode.lower() not in ["r", "w"]:
            return False

        # path exists physically?
        if not os.path.exists(path):
            return False

        # pathtype correct? (file, folder, or None)
        if pathtype is not None:
            pathtype = pathtype.lower()
            if not pathtype in ["file", "folder"]:
                return False
            if os.path.isdir(path) and pathtype == "file":
                return False
            elif not os.path.isdir(path) and pathtype == "folder":
                return False

        # file extension correct?
        if fileextension is not None:
            fileextension = fileextension if isinstance(fileextension, list) else [fileextension]
            hit = False
            for fileext in fileextension:
                fileext = fileext if fileext.startswith(".") else "." + fileext
                if path.endswith(fileext):
                    hit = True
            if not hit:
                return False

        # permission?
        if permissionmode is not None:
            return False

        return True


murban's avatar
murban committed
90
    def get_file_list(self, path, deep, ext_filter=[], reverse=False):
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
        dirlist = os.listdir(path)
        returnlist = []
        for elem in dirlist:
            fullPath = os.path.join(path, elem)
            locale.setlocale(locale.LC_ALL, '')
            stats = os.stat(path + ('' if path.endswith('/') else '/') + elem)
            size = stats.st_size
            size = locale.format("%d", size, grouping=True)
            mtime = stats.st_mtime
            mtime = datetime.fromtimestamp(mtime).strftime("%Y-%m-%d %H:%M:%S")
            if os.path.isdir(fullPath):
                if elem.startswith("."):
                    continue
                returnlist.append({'name': elem, 'type': 'folder', 'parent': path + '/', 'extension': '', 'mtime': mtime, 'size': size, "path": os.path.join(path, elem)})
                if deep:
murban's avatar
murban committed
106
                    returnlist.extend(self.get_file_list(fullPath, deep, ext_filter, reverse))
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
            else:
                if elem.startswith("."):
                    continue
                extension = elem.split(".")[-1]
                returnlist.append({'name': elem, 'type': 'file', 'parent': path + '/', 'extension': extension, 'mtime': mtime, 'size': size, "path": os.path.join(path, elem)})
        # apply filters
        filelist = []
        # delete "." in file extensions
        ext_filter = map(lambda ext: ext if not ext.startswith(".") else ext[1:], ext_filter)
        for elem in returnlist:
            if (elem["type"] == "folder"):
                filelist.append(elem)
                continue
            if not reverse:
                if str(elem["extension"]) not in ext_filter:
                    filelist.append(elem)
            else:
                if str(elem["extension"]) in ext_filter:
                    filelist.append(elem)
        return filelist


murban's avatar
murban committed
129
    def cut_slashs(self, path):
130
131
132
133
134
135
        path = path[1:] if path.startswith("/") else path
        if path == "":
            return path
        path = path[:-1] if path.endswith("/") else path
        return path

murban's avatar
murban committed
136
    def create_folder(self, path, name):
137
138
139
140
141
142
143
144
145
146
        # folder with the same name existent?
        fullpath = os.path.join(path, name)
        if os.path.isdir(fullpath):
            raise Exception("Name already in use!")
        try:
            os.mkdir(fullpath)
        except Exception as e:
            #raise Exception("You don't have the permission to create this folder!")
            raise Exception(str(e))

murban's avatar
murban committed
147
    def create_file(self, path, name):
148
149
150
151
152
153
154
155
156
157
158
        # file with the same name existent?
        fullpath = os.path.join(path, name)
        if os.path.exists(fullpath):
            raise Exception("Name already in use!")
        try:
            f = file(fullpath, "w")
            f.close()
        except Exception as e:
            raise Exception(str(e))
        

murban's avatar
murban committed
159
    def rename_folder(self, path, name):
160
161
162
163
164
165
166
167
168
169
170
171
        # file or folder
        if not os.path.isdir(path):
            raise Exception("Renaming file with folder function!")

        # folder with the same name existent?
        path = path if not path.endswith("/") else path[:-1]
        fullpath = os.path.join("/".join(path.split("/")[:-1]), name)
        if os.path.exists(fullpath):
            raise Exception("Name already in use!")

        os.renames(path, fullpath)

murban's avatar
murban committed
172
    def rename_file(self, path, name):
173
174
175
176
177
178
179
180
181
182
183
        # file or folder
        if os.path.isdir(path):
            raise Exception("Renaming folder with file function!")

        # file with the same name existent?
        fullpath = os.path.join("/".join(path.split("/")[:-1]), name)
        if os.path.exists(fullpath):
            raise Exception("Name already in use!")

        os.renames(path, fullpath)

murban's avatar
murban committed
184
185
    def remove(self, path):
        if isinstance(path, list):
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
            for p in path:
                self.remove(p)
            return True

        if os.path.isdir(path):
            shutil.rmtree(path)
        else:
            os.remove(path)

    def compress(self, path, paths, name):
        # paths has to be a list of strings
        paths = paths if isinstance(paths, list) else [paths]

        path = path if not path.endswith("/") else path[:-1]

        fullpath = os.path.join(path, "%s.zip" % name)

        if os.path.exists(fullpath):
            raise Exception("Name already in use!")

        archive = ZipFile(fullpath, "w")

murban's avatar
murban committed
208
        path = path if path.startswith("/") else path
209
210
211
        for p in paths:
            if p is None or p == "":
                continue
murban's avatar
murban committed
212
            p = p if p.startswith(os.sep) else os.sep + path
213
214
215
216
217
218
219
220
221
222
223
224
225
226
            if os.path.isdir(p):
                for elem in os.listdir(p):
                    fullp = os.path.join(p, elem)
                    if os.path.isdir(fullp):
                        paths.append(fullp)
                    else:
                        ap = fullp[len(path):] if fullp.startswith(path) else fullp
                        archive.write(fullpp, ap)

            ap = p[len(path):] if p.startswith(path) else p
            archive.write(p, ap)

        archive.close()

murban's avatar
murban committed
227
228
229
230
    def paste(self, path, target, cut):
        if isinstance(target, list):
            for p in target:
                self.paste(path, p, cut)
231
232
            return True

murban's avatar
murban committed
233
        fulltarget = os.path.join(path, target.split("/")[-1])
234
235
236
237

        if os.path.exists(fulltarget):
            raise Exception("Name already in use!")

murban's avatar
murban committed
238
239
        if os.path.isdir(target):
            shutil.copytree(target, fulltarget)
240
            if cut:
murban's avatar
murban committed
241
                shutil.rmtree(target)
242
        else:
murban's avatar
murban committed
243
            shutil.copy2(target, path)
244
            if cut:
murban's avatar
murban committed
245
                os.remove(target)
246
247


murban's avatar
murban committed
248
    def save_file_content(self, path, content, force=True):
249
        #check if file already exists
murban's avatar
murban committed
250
251
        if os.path.exists(path) and not force:
            return False, "The file '%s' already exists!" % path
252

murban's avatar
murban committed
253
        out = open(path, "w")
254
255
256
257
258
259
        for line in content.data:
            out.write(line)
        out.close()

        return True, "File saved!"

murban's avatar
murban committed
260
261
    def get_file_content(self, path):
        f = open(path, "r")
262
263
        content = f.read()
        f.close()
Marcel's avatar
Marcel committed
264
265
266
        if content == '':
            content = ' '
        return content
267

murban's avatar
murban committed
268
    def is_browser_file(self, path):
269
        extension = path.split(".")[-1]
murban's avatar
murban committed
270
        return extension in FileSystem.BROWSER_EXTENSIONS
271

murban's avatar
murban committed
272
    def handle_file_name_collision(self, name, path):
273
        # collision?
murban's avatar
murban committed
274
        files = os.listdir(path)
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
        if name not in files:
            return name

        # when this line is reached, there is a collision!

        # cut the file extension
        extension = name.split(".")[-1]
        prename = None
        if name == extension:
            extension = ""
            prename = name
        else:
            prename = name.split("." + extension)[0]

        # has the name already a counter at its end?
        hasCounter = False
        preprename = None
        counter = prename.split("_")[-1]

        if counter != prename:
            try:
                counter = int(counter)
                hasCounter = True
                preprename = "_".join(prename.split("_")[:-1])
            except:
                pass

        if hasCounter:
            # increment and try again
            counter += 1
            newname = "%s_%d%s" % (preprename, counter, "" if extension == "" else "." + extension)
        else:
            newname = "%s_1%s" % (prename, "" if extension == "" else "." + extension)

        # return
murban's avatar
murban committed
310
        return self.handle_file_name_collision(newname, path)