Package web2py :: Package gluon :: Module fileutils
[hide private]
[frames] | no frames]

Source Code for Module web2py.gluon.fileutils

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3   
  4  """ 
  5  This file is part of the web2py Web Framework 
  6  Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu> 
  7  License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html) 
  8  """ 
  9   
 10  import storage 
 11  import os 
 12  import re 
 13  import tarfile 
 14  import glob 
 15  from http import HTTP 
 16  from gzip import open as gzopen 
 17  from settings import global_settings 
 18   
 19   
 20  __all__ = [ 
 21      'up', 
 22      'abspath', 
 23      'mktree', 
 24      'listdir', 
 25      'recursive_unlink', 
 26      'cleanpath', 
 27      'tar', 
 28      'untar', 
 29      'tar_compiled', 
 30      'get_session', 
 31      'check_credentials', 
 32      'w2p_pack', 
 33      'w2p_unpack', 
 34      'w2p_pack_plugin', 
 35      'w2p_unpack_plugin', 
 36      'fix_newlines', 
 37      ] 
 38   
 39   
40 -def abspath(*relpath, **base):
41 "convert relative path to absolute path based (by default) on applications_parent" 42 path = os.path.join(*relpath) 43 gluon = base.get('gluon', False) 44 if os.path.isabs(path): 45 return path 46 if gluon: 47 return os.path.join(global_settings.gluon_parent, path) 48 return os.path.join(global_settings.applications_parent, path)
49 50
51 -def mktree(path):
52 head,tail =os.path.split(path) 53 if head: 54 if tail: mktree(head) 55 if not os.path.exists(head): 56 os.mkdir(head)
57
58 -def listdir( 59 path, 60 expression='^.+$', 61 drop=True, 62 add_dirs=False, 63 sort=True, 64 ):
65 """ 66 like os.listdir() but you can specify a regex pattern to filter files. 67 if add_dirs is True, the returned items will have the full path. 68 """ 69 if path[-1:] != '/': 70 path = path + '/' 71 if drop: 72 n = len(path) 73 else: 74 n = 0 75 regex = re.compile(expression) 76 items = [] 77 for (root, dirs, files) in os.walk(path, topdown=True): 78 for dir in dirs[:]: 79 if dir.startswith('.'): 80 dirs.remove(dir) 81 if add_dirs: 82 items.append(root[n:]) 83 for file in sorted(files): 84 if regex.match(file) and not file.startswith('.'): 85 items.append(os.path.join(root, file)[n:]) 86 if sort: 87 return sorted(items) 88 else: 89 return items
90 91 99 100
101 -def cleanpath(path):
102 """ 103 turns any expression/path into a valid filename. replaces / with _ and 104 removes special characters. 105 """ 106 107 items = path.split('.') 108 if len(items) > 1: 109 path = re.sub('[^\w\.]+', '_', '_'.join(items[:-1]) + '.' 110 + ''.join(items[-1:])) 111 else: 112 path = re.sub('[^\w\.]+', '_', ''.join(items[-1:])) 113 return path
114 115
116 -def _extractall(filename, path='.', members=None):
117 if not hasattr(tarfile.TarFile, 'extractall'): 118 from tarfile import ExtractError 119 120 class TarFile(tarfile.TarFile): 121 122 def extractall(self, path='.', members=None): 123 """Extract all members from the archive to the current working 124 directory and set owner, modification time and permissions on 125 directories afterwards. `path' specifies a different directory 126 to extract to. `members' is optional and must be a subset of the 127 list returned by getmembers(). 128 """ 129 130 directories = [] 131 if members is None: 132 members = self 133 for tarinfo in members: 134 if tarinfo.isdir(): 135 136 # Extract directory with a safe mode, so that 137 # all files below can be extracted as well. 138 139 try: 140 os.makedirs(os.path.join(path, 141 tarinfo.name), 0777) 142 except EnvironmentError: 143 pass 144 directories.append(tarinfo) 145 else: 146 self.extract(tarinfo, path) 147 148 # Reverse sort directories. 149 150 directories.sort(lambda a, b: cmp(a.name, b.name)) 151 directories.reverse() 152 153 # Set correct owner, mtime and filemode on directories. 154 155 for tarinfo in directories: 156 path = os.path.join(path, tarinfo.name) 157 try: 158 self.chown(tarinfo, path) 159 self.utime(tarinfo, path) 160 self.chmod(tarinfo, path) 161 except ExtractError, e: 162 if self.errorlevel > 1: 163 raise 164 else: 165 self._dbg(1, 'tarfile: %s' % e)
166 167 168 _cls = TarFile 169 else: 170 _cls = tarfile.TarFile 171 172 tar = _cls(filename, 'r') 173 ret = tar.extractall(path, members) 174 tar.close() 175 return ret 176
177 -def tar(file, dir, expression='^.+$'):
178 """ 179 tars dir into file, only tars file that match expression 180 """ 181 182 tar = tarfile.TarFile(file, 'w') 183 for file in listdir(dir, expression, add_dirs=True): 184 tar.add(os.path.join(dir, file), file, False) 185 tar.close()
186
187 -def untar(file, dir):
188 """ 189 untar file into dir 190 """ 191 192 _extractall(file, dir)
193 194
195 -def w2p_pack(filename, path, compiled=False):
196 filename = abspath(filename) 197 path = abspath(path) 198 tarname = filename + '.tar' 199 if compiled: 200 tar_compiled(tarname, path, '^[\w\.\-]+$') 201 else: 202 tar(tarname, path, '^[\w\.\-]+$') 203 w2pfp = gzopen(filename, 'wb') 204 tarfp = open(tarname, 'rb') 205 w2pfp.write(tarfp.read()) 206 w2pfp.close() 207 tarfp.close() 208 os.unlink(tarname)
209
210 -def w2p_unpack(filename, path, delete_tar=True):
211 filename = abspath(filename) 212 path = abspath(path) 213 if filename[-4:] == '.w2p' or filename[-3:] == '.gz': 214 if filename[-4:] == '.w2p': 215 tarname = filename[:-4] + '.tar' 216 else: 217 tarname = filename[:-3] + '.tar' 218 fgzipped = gzopen(filename, 'rb') 219 tarfile = open(tarname, 'wb') 220 tarfile.write(fgzipped.read()) 221 tarfile.close() 222 fgzipped.close() 223 else: 224 tarname = filename 225 untar(tarname, path) 226 if delete_tar: 227 os.unlink(tarname)
228 229
230 -def w2p_pack_plugin(filename, path, plugin_name):
231 """Pack the given plugin into a w2p file. 232 Will match files at: 233 <path>/*/plugin_[name].* 234 <path>/*/plugin_[name]/* 235 """ 236 filename = abspath(filename) 237 path = abspath(path) 238 if not filename.endswith('web2py.plugin.%s.w2p' % plugin_name): 239 raise Exception, "Not a web2py plugin name" 240 plugin_tarball = tarfile.open(filename, 'w:gz') 241 app_dir = path 242 while app_dir[-1]=='/': 243 app_dir = app_dir[:-1] 244 files1=glob.glob(os.path.join(app_dir,'*/plugin_%s.*' % plugin_name)) 245 files2=glob.glob(os.path.join(app_dir,'*/plugin_%s/*' % plugin_name)) 246 for file in files1+files2: 247 plugin_tarball.add(file, arcname=file[len(app_dir)+1:]) 248 plugin_tarball.close()
249 250
251 -def w2p_unpack_plugin(filename, path, delete_tar=True):
252 filename = abspath(filename) 253 path = abspath(path) 254 if not os.path.basename(filename).startswith('web2py.plugin.'): 255 raise Exception, "Not a web2py plugin" 256 w2p_unpack(filename,path,delete_tar)
257 258
259 -def tar_compiled(file, dir, expression='^.+$'):
260 """ 261 used to tar a compiled application. 262 the content of models, views, controllers is not stored in the tar file. 263 """ 264 265 tar = tarfile.TarFile(file, 'w') 266 for file in listdir(dir, expression, add_dirs=True): 267 filename = os.path.join(dir, file) 268 if os.path.islink(filename): 269 continue 270 if os.path.isfile(filename) and file[-4:] != '.pyc': 271 if file[:6] == 'models': 272 continue 273 if file[:5] == 'views': 274 continue 275 if file[:11] == 'controllers': 276 continue 277 if file[:7] == 'modules': 278 continue 279 tar.add(filename, file, False) 280 tar.close()
281
282 -def up(path):
283 return os.path.dirname(os.path.normpath(path))
284 285
286 -def get_session(request, other_application='admin'):
287 """ checks that user is authorized to access other_application""" 288 289 if request.application == other_application: 290 raise KeyError 291 try: 292 session_id = request.cookies['session_id_' + other_application].value 293 osession = storage.load_storage(os.path.join( 294 up(request.folder), other_application, 'sessions', session_id)) 295 except: 296 osession = storage.Storage() 297 return osession
298 299
300 -def check_credentials(request, other_application='admin'):
301 """ checks that user is authorized to access other_application""" 302 303 if request.env.web2py_runtime_gae: 304 from google.appengine.api import users 305 if users.is_current_user_admin(): 306 return True 307 else: 308 login_html = '<a href="%s">Sign in with your google account</a>.' \ 309 % users.create_login_url(request.env.path_info) 310 raise HTTP(200, '<html><body>%s</body></html>' % login_html) 311 else: 312 return get_session(request, other_application).authorized
313 314
315 -def fix_newlines(path):
316 regex = re.compile(r'''(\r 317 |\r| 318 )''') 319 for filename in listdir(path, '.*\.(py|html)$', drop=False): 320 fp = open(filename, 'rb') 321 rdata = fp.read() 322 fp.close() 323 wdata = regex.sub('\n', rdata) 324 if wdata != rdata: 325 fp = open(filename, 'wb') 326 fp.write(wdata) 327 fp.close()
328 329
330 -def copystream( 331 src, 332 dest, 333 size, 334 chunk_size=10 ** 5, 335 ):
336 """ 337 this is here because I think there is a bug in shutil.copyfileobj 338 """ 339 while size > 0: 340 if size < chunk_size: 341 data = src.read(size) 342 else: 343 data = src.read(chunk_size) 344 length = len(data) 345 if length > size: 346 (data, length) = (data[:size], size) 347 size -= length 348 if length == 0: 349 break 350 dest.write(data) 351 if length < chunk_size: 352 break 353 dest.seek(0) 354 return
355