PageRenderTime 59ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/src/ebmlib/fileutil.py

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