~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to wxPython/wx/tools/Editra/src/ebmlib/fileutil.py

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
###############################################################################
 
2
# Name: fileutil.py                                                           #
 
3
# Purpose: File Management Utilities.                                         #
 
4
# Author: Cody Precord <cprecord@editra.org>                                  #
 
5
# Copyright: (c) 2009 Cody Precord <staff@editra.org>                         #
 
6
# Licence: wxWindows Licence                                                  #
 
7
###############################################################################
 
8
 
 
9
"""
 
10
Editra Business Model Library: File Utilities
 
11
 
 
12
Utility functions for managing and working with files.
 
13
 
 
14
"""
 
15
 
 
16
__author__ = "Cody Precord <cprecord@editra.org>"
 
17
__svnid__ = "$Id: fileutil.py 71689 2012-06-07 18:55:45Z CJP $"
 
18
__revision__ = "$Revision: 71689 $"
 
19
 
 
20
__all__ = [ 'GetAbsPath', 'GetFileExtension', 'GetFileModTime', 'GetFileName',
 
21
            'GetFileSize', 'GetPathName', 'GetPathFromURI', 'GetUniqueName', 
 
22
            'IsLink', 'MakeNewFile', 'MakeNewFolder', 'PathExists',
 
23
            'ResolveRealPath', 'IsExecutable', 'Which', 'ComparePaths',
 
24
            'AddFileExtension', 'GetDirectoryObject', 'File', 'Directory',
 
25
            'GetFileManagerCmd', 'OpenWithFileManager', 'IsHidden', 'IsSubPath' ]
 
26
 
 
27
#-----------------------------------------------------------------------------#
 
28
# Imports
 
29
import wx
 
30
import ctypes
 
31
import os
 
32
import platform
 
33
import urllib2
 
34
import stat
 
35
import subprocess
 
36
 
 
37
UNIX = WIN = False
 
38
if wx.Platform == '__WXMSW__':
 
39
    WIN = True
 
40
    try:
 
41
        # Check for if win32 extensions are available
 
42
        import win32com.client as win32client
 
43
    except ImportError:
 
44
        win32client = None
 
45
 
 
46
    try:
 
47
        # Check for win32api
 
48
        import win32api
 
49
    except ImportError:
 
50
        win32api = None
 
51
else:
 
52
    UNIX = True
 
53
 
 
54
#-----------------------------------------------------------------------------#
 
55
 
 
56
def uri2path(func):
 
57
    """Decorator method to convert path arguments that may be uri's to
 
58
    real file system paths. Arg 0 must be a file path or uri.
 
59
 
 
60
    """
 
61
    def WrapURI(*args, **kwargs):
 
62
        args = list(args)
 
63
        args[0] = GetPathFromURI(args[0])
 
64
        return func(*args, **kwargs)
 
65
 
 
66
    WrapURI.__name__ = func.__name__
 
67
    WrapURI.__doc__ = func.__doc__
 
68
    return WrapURI
 
69
 
 
70
#-----------------------------------------------------------------------------#
 
71
 
 
72
def AddFileExtension(path, ext):
 
73
    """Add a file extension to a path if it doesn't already exist
 
74
    @param path: file path
 
75
    @param ext: file extension
 
76
 
 
77
    """
 
78
    assert isinstance(ext, basestring)
 
79
    if not ext.startswith('.'):
 
80
        ext = '.' + ext
 
81
    if not path.endswith(ext):
 
82
        path = path + ext
 
83
    return path
 
84
 
 
85
def ComparePaths(path1, path2):
 
86
    """Determine whether the two given paths are equivalent
 
87
    @param path1: unicode
 
88
    @param path2: unicode
 
89
    @return: bool
 
90
 
 
91
    """
 
92
    path1 = GetAbsPath(path1)
 
93
    path2 = GetAbsPath(path2)
 
94
    if WIN:
 
95
        path1 = path1.lower()
 
96
        path2 = path2.lower()
 
97
    return path1 == path2
 
98
 
 
99
def CopyFile(orig, dest):
 
100
    """Copy the given file to the destination
 
101
    @param orig: file to copy (full path)
 
102
    @param dest: where to copy to
 
103
 
 
104
    """
 
105
    raise NotImplementedError
 
106
 
 
107
@uri2path
 
108
def GetAbsPath(path):
 
109
    """Get the absolute path of a file of a file.
 
110
    @param path: string
 
111
    @return: string
 
112
    @note: on windows if win32api is available short notation paths will be
 
113
           converted to the proper long name.
 
114
    
 
115
    """
 
116
    rpath = os.path.abspath(path)
 
117
    # Resolve short path notation on Windows when possible
 
118
    if WIN and win32api is not None and u"~" in rpath:
 
119
        try:
 
120
            rpath = win32api.GetLongPathNameW(rpath)
 
121
        except Exception:
 
122
            # Ignore errors from win32api calls
 
123
            pass
 
124
    return rpath
 
125
 
 
126
def GetFileExtension(file_str):
 
127
    """Gets last atom at end of string as extension if
 
128
    no extension whole string is returned
 
129
    @param file_str: path or file name to get extension from
 
130
 
 
131
    """
 
132
    return file_str.split('.')[-1]
 
133
 
 
134
def GetFileModTime(file_name):
 
135
    """Returns the time that the given file was last modified on
 
136
    @param file_name: path of file to get mtime of
 
137
 
 
138
    """
 
139
    try:
 
140
        mod_time = os.path.getmtime(file_name)
 
141
    except (OSError, EnvironmentError):
 
142
        mod_time = 0
 
143
    return mod_time
 
144
 
 
145
def GetFileName(path):
 
146
    """Gets last atom on end of string as filename
 
147
    @param path: full path to get filename from
 
148
 
 
149
    """
 
150
    return os.path.split(path)[-1]
 
151
 
 
152
@uri2path
 
153
def GetFileSize(path):
 
154
    """Get the size of the file at a given path
 
155
    @param path: Path to file
 
156
    @return: long
 
157
 
 
158
    """
 
159
    try:
 
160
        return os.stat(path)[stat.ST_SIZE]
 
161
    except:
 
162
        return 0
 
163
 
 
164
def GetPathFromURI(path):
 
165
    """Get a local path from a file:// uri
 
166
    @return: normalized path
 
167
 
 
168
    """
 
169
    if path.startswith(u"file:"):
 
170
        path = path.replace(u"file:", u"")
 
171
        path = path.lstrip(u"/")
 
172
        if platform.system().lower() in ('windows', 'microsoft'):
 
173
            path = path.replace(u"/", u"\\")
 
174
            if len(path) >= 2 and path[1] != u':':
 
175
                # A valid windows file uri should start with the drive
 
176
                # letter. If not make the assumption that it should be
 
177
                # the C: drive.
 
178
                path = u"C:\\\\" + path
 
179
        else:
 
180
            path = u"/" + path
 
181
        path = urllib2.unquote(path)
 
182
 
 
183
    return path
 
184
 
 
185
@uri2path
 
186
def GetPathName(path):
 
187
    """Gets the path minus filename
 
188
    @param path: full path to get base of
 
189
 
 
190
    """
 
191
    return os.path.split(path)[0]
 
192
 
 
193
@uri2path
 
194
def IsLink(path):
 
195
    """Is the file a link
 
196
    @return: bool
 
197
 
 
198
    """
 
199
    if WIN:
 
200
        return path.endswith(".lnk") or os.path.islink(path)
 
201
    else:
 
202
        return os.path.islink(path)
 
203
 
 
204
def IsSubPath(path1, path2):
 
205
    """Is path1 a subpath of path2
 
206
    i.e) /usr/bin/foo is a subpath of /usr/bin
 
207
    @return: bool
 
208
 
 
209
    """
 
210
    if WIN:
 
211
        path1 = path1.lower()
 
212
        path2 = path2.lower()
 
213
    path1 = GetAbsPath(path1)
 
214
    path2 = GetAbsPath(path2)
 
215
    return path1.startswith(path2)
 
216
 
 
217
@uri2path
 
218
def IsHidden(path):
 
219
    """Is the path a hidden path
 
220
    @param path: path to check
 
221
    @return: bool
 
222
 
 
223
    """
 
224
    bHidden = False
 
225
    if PathExists(path):
 
226
        if WIN:
 
227
            try:
 
228
                attrs = ctypes.windll.kernel32.GetFileAttributesW(path)
 
229
                assert attrs != -1
 
230
                bHidden = bool(attrs & 2)
 
231
            except (AttributeError, AssertionError):
 
232
                bHidden = False
 
233
        else:
 
234
            dname = GetFileName(path)
 
235
            bHidden = dname.startswith('.')
 
236
    return bHidden
 
237
 
 
238
@uri2path
 
239
def PathExists(path):
 
240
    """Does the path exist.
 
241
    @param path: file path or uri
 
242
    @return: bool
 
243
 
 
244
    """
 
245
    return os.path.exists(path)
 
246
 
 
247
@uri2path
 
248
def IsExecutable(path):
 
249
    """Is the file at the given path an executable file
 
250
    @param path: file path
 
251
    @return: bool
 
252
 
 
253
    """
 
254
    return os.path.isfile(path) and os.access(path, os.X_OK)
 
255
 
 
256
@uri2path
 
257
def ResolveRealPath(link):
 
258
    """Return the real path of the link file
 
259
    @param link: path of link file
 
260
    @return: string
 
261
 
 
262
    """
 
263
    assert IsLink(link), "ResolveRealPath expects a link file!"
 
264
    realpath = link
 
265
    if WIN and win32client is not None:
 
266
        shell = win32client.Dispatch("WScript.Shell")
 
267
        shortcut = shell.CreateShortCut(link)
 
268
        realpath = shortcut.Targetpath
 
269
    else:
 
270
        realpath = os.path.realpath(link)
 
271
    return realpath
 
272
 
 
273
def GetFileManagerCmd():
 
274
    """Get the file manager open command for the current os. Under linux
 
275
    it will check for xdg-open, nautilus, konqueror, and Thunar, it will then
 
276
    return which one it finds first or 'nautilus' it finds nothing.
 
277
    @return: string
 
278
 
 
279
    """
 
280
    if wx.Platform == '__WXMAC__':
 
281
        return 'open'
 
282
    elif wx.Platform == '__WXMSW__':
 
283
        return 'explorer'
 
284
    else:
 
285
        # Check for common linux filemanagers returning first one found
 
286
        #          Gnome/ubuntu KDE/kubuntu  xubuntu
 
287
        for cmd in ('xdg-open', 'nautilus', 'konqueror', 'Thunar'):
 
288
            result = os.system("which %s > /dev/null" % cmd)
 
289
            if result == 0:
 
290
                return cmd
 
291
        else:
 
292
            return 'nautilus'
 
293
 
 
294
def OpenWithFileManager(path):
 
295
    """Open the given path with the systems file manager
 
296
    @param path: file/directory path
 
297
 
 
298
    """
 
299
    cmd = GetFileManagerCmd()
 
300
    subprocess.call([cmd, path])
 
301
 
 
302
def Which(program):
 
303
    """Find the path of the given executable
 
304
    @param program: executable name (i.e 'python')
 
305
    @return: executable path or None
 
306
 
 
307
    """
 
308
    # Check local directory first
 
309
    if IsExecutable(program):
 
310
        return program
 
311
    else:
 
312
        # Start looking on the $PATH
 
313
        for path in os.environ["PATH"].split(os.pathsep):
 
314
            exe_file = os.path.join(path, program)
 
315
            if IsExecutable(exe_file):
 
316
                return exe_file        
 
317
    return None
 
318
 
 
319
def GetDirectoryObject(path, recurse=True, includedot=False):
 
320
    """Gets a L{Directory} object representing the filesystem of the
 
321
    given path.
 
322
    @param path: base path to list
 
323
    @keyword recurse: recurse into subdirectories
 
324
    @keyword includedot: include '.' files
 
325
    @return: L{Directory} object instance
 
326
 
 
327
    """
 
328
    assert os.path.isdir(path)
 
329
    def _BuildDir(thedir):
 
330
        dirAddFile = thedir.Files.append
 
331
        isdir = os.path.isdir
 
332
        pjoin = os.path.join
 
333
        for fname in os.listdir(thedir.Path):
 
334
            if not includedot and fname.startswith('.'):
 
335
                continue
 
336
            fpath = pjoin(thedir.Path, fname)
 
337
            if isdir(fpath):
 
338
                newobj = Directory(fpath)
 
339
                if recurse:
 
340
                    _BuildDir(newobj)
 
341
            else:
 
342
                newobj = File(fpath)
 
343
            dirAddFile(newobj)
 
344
 
 
345
    dobj = Directory(path)
 
346
    _BuildDir(dobj)
 
347
    return dobj
 
348
 
 
349
#-----------------------------------------------------------------------------#
 
350
 
 
351
class File(object):
 
352
    """Basic file data structure"""
 
353
    __slots__ = ('path', 'modtime')
 
354
    def __init__(self, path):
 
355
        super(File, self).__init__()
 
356
 
 
357
        self.path = path
 
358
        self.modtime = GetFileModTime(self.path)
 
359
 
 
360
    Path = property(lambda self: self.path)
 
361
    Name = property(lambda self: os.path.basename(self.Path))
 
362
    ModTime = property(lambda self: self.modtime,
 
363
                       lambda self, mod: setattr(self, 'modtime', mod))
 
364
 
 
365
    def __str__(self):
 
366
        return self.Path
 
367
 
 
368
    def __eq__(self, other):
 
369
        assert isinstance(other, File)
 
370
        return ComparePaths(self.Path, other.Path)
 
371
 
 
372
class Directory(File):
 
373
    """Basic directory data structure.
 
374
    Is a container class that provides a simple in memory representation of
 
375
    a file system.
 
376
 
 
377
    """
 
378
    __slots__ = ('files',)
 
379
    def __init__(self, path):
 
380
        super(Directory, self).__init__(path)
 
381
 
 
382
        self.files = list()
 
383
 
 
384
    Files = property(lambda self: self.files)
 
385
 
 
386
#-----------------------------------------------------------------------------#
 
387
 
 
388
def GetUniqueName(path, name):
 
389
    """Make a file name that will be unique in case a file of the
 
390
    same name already exists at that path.
 
391
    @param path: Root path to folder of files destination
 
392
    @param name: desired file name base
 
393
    @return: string
 
394
 
 
395
    """
 
396
    tmpname = os.path.join(path, name)
 
397
    if os.path.exists(tmpname):
 
398
        if '.' not in name:
 
399
            ext = ''
 
400
            fbase = name
 
401
        else:
 
402
            ext = '.' + name.split('.')[-1]
 
403
            fbase = name[:-1 * len(ext)]
 
404
 
 
405
        inc = len([x for x in os.listdir(path) if x.startswith(fbase)])
 
406
        tmpname = os.path.join(path, "%s-%d%s" % (fbase, inc, ext))
 
407
        while os.path.exists(tmpname):
 
408
            inc = inc + 1
 
409
            tmpname = os.path.join(path, "%s-%d%s" % (fbase, inc, ext))
 
410
 
 
411
    return tmpname
 
412
 
 
413
 
 
414
#-----------------------------------------------------------------------------#
 
415
 
 
416
def MakeNewFile(path, name):
 
417
    """Make a new file at the given path with the given name.
 
418
    If the file already exists, the given name will be changed to
 
419
    a unique name in the form of name + -NUMBER + .extension
 
420
    @param path: path to directory to create file in
 
421
    @param name: desired name of file
 
422
    @return: Tuple of (success?, Path of new file OR Error message)
 
423
 
 
424
    """
 
425
    if not os.path.isdir(path):
 
426
        path = os.path.dirname(path)
 
427
    fname = GetUniqueName(path, name)
 
428
 
 
429
    try:
 
430
        open(fname, 'w').close()
 
431
    except (IOError, OSError), msg:
 
432
        return (False, str(msg))
 
433
 
 
434
    return (True, fname)
 
435
 
 
436
def MakeNewFolder(path, name):
 
437
    """Make a new folder at the given path with the given name.
 
438
    If the folder already exists, the given name will be changed to
 
439
    a unique name in the form of name + -NUMBER.
 
440
    @param path: path to create folder on
 
441
    @param name: desired name for folder
 
442
    @return: Tuple of (success?, new dirname OR Error message)
 
443
 
 
444
    """
 
445
    if not os.path.isdir(path):
 
446
        path = os.path.dirname(path)
 
447
    folder = GetUniqueName(path, name)
 
448
    try:
 
449
        os.mkdir(folder)
 
450
    except (OSError, IOError), msg:
 
451
        return (False, str(msg))
 
452
 
 
453
    return (True, folder)