1 #---------------------------------------------------------------------------- 
   3 # Purpose:      Active grid miscellaneous utilities 
   9 # Copyright:    (c) 2004-2005 ActiveGrid, Inc. 
  10 # License:      wxWindows License 
  11 #---------------------------------------------------------------------------- 
  20 import activegrid
.util
.aglogging 
as aglogging
 
  21 import activegrid
.util
.sysutils 
as sysutils
 
  22 import activegrid
.util
.utillang 
as utillang
 
  23 from activegrid
.util
.lang 
import * 
  25 global fileutilsLogger
 
  26 fileutilsLogger 
= logging
.getLogger("activegrid.util.fileutils") 
  32 aglogging
.setLevelFatal(fileutilsLogger
) 
  33 #logging.getLogger().addHandler(logging.StreamHandler(sys.stderr)) 
  36     return "${%s}" % varname
 
  38 AG_SYSTEM_VAR_NAMES 
= [] # all AG System vars, with ${} syntax 
  40 AG_SYSTEM_VAR 
= "AG_SYSTEM" 
  41 AG_SYSTEM_VAR_REF 
= addRef(AG_SYSTEM_VAR
) 
  42 AG_SYSTEM_VAR_NAMES
.append(AG_SYSTEM_VAR_REF
) 
  44 AG_SYSTEM_STATIC_VAR 
= "AG_SYSTEM_STATIC" 
  45 AG_SYSTEM_STATIC_VAR_REF 
= addRef(AG_SYSTEM_STATIC_VAR
) 
  46 AG_SYSTEM_VAR_NAMES
.append(AG_SYSTEM_STATIC_VAR_REF
) 
  49 AG_APP_STATIC_VAR 
= "AG_APP_STATIC" 
  51 # _initAGSystemVars needs to be called to initialize the following two 
  53 EXPANDED_AG_SYSTEM_VARS 
= {} # ${varname} 
-> value (path
) 
  54 # ${varname}, ordered from longest to shortest path value 
  55 AG_SYSTEM_VARS_LENGTH_ORDER 
= []  
  57 def _initAGSystemVars(): 
  58     if (len(EXPANDED_AG_SYSTEM_VARS
) > 0): 
  61     for v 
in AG_SYSTEM_VAR_NAMES
: 
  62         EXPANDED_AG_SYSTEM_VARS
[v
] = os
.path
.abspath(expandVars(v
)) 
  63         AG_SYSTEM_VARS_LENGTH_ORDER
.append(v
) 
  65     AG_SYSTEM_VARS_LENGTH_ORDER
.sort(_sortByValLength
) 
  68 def parameterizePathWithAGSystemVar(inpath
): 
  69     """Returns parameterized path if path starts with a known AG directory. Otherwise returns path as it was passed in.""" 
  72     if not sysutils
.isWindows(): 
  73         # ensure we have forward slashes 
  74         path 
= path
.replace("\\", "/") 
  76     path 
= os
.path
.abspath(path
) 
  78     for varname 
in AG_SYSTEM_VARS_LENGTH_ORDER
: 
  79         varval 
= EXPANDED_AG_SYSTEM_VARS
[varname
] 
  80         if path
.startswith(varval
): 
  81             return path
.replace(varval
, varname
) 
  85 def startsWithAgSystemVar(path
): 
  86     """Returns True if path starts with a known AG system env var, False otherwise.""" 
  87     for varname 
in AG_SYSTEM_VAR_NAMES
: 
  88         if path
.startswith(varname
): 
  92 def _sortByValLength(v1
, v2
): 
  93     return len(EXPANDED_AG_SYSTEM_VARS
[v2
]) - len(EXPANDED_AG_SYSTEM_VARS
[v1
]) 
  95 def makeDirsForFile(filename
): 
  96     d 
= os
.path
.dirname(filename
) 
  97     if (not os
.path
.exists(d
)): 
 100 def createFile(filename
, mode
='w'): 
 102     if (not os
.path
.exists(filename
)): 
 103         makeDirsForFile(filename
) 
 104     f 
= file(filename
, mode
) 
 107 def compareFiles(file1
, file2
, ignore
=None): 
 108 ##    result = filecmp.cmp(file1, file2) 
 115         line1 
= file1
.readline() 
 116         line2 
= file2
.readline() 
 117         if (len(line1
) == 0): 
 118             if (len(line2
) == 0): 
 122         elif (len(line2
) == 0): 
 124         elif (line1 
!= line2
): 
 126                 if (line1
.startswith(ignore
) or line2
.startswith(ignore
)): 
 128             line1 
= line1
.replace(" ", "") 
 129             line2 
= line2
.replace(" ", "") 
 133                 if ((abs(len1 
- len2
) == 1) and (len1 
> 0) and (len2 
> 0)  
 134                     and (line1
[-1] == "\n") and (line2
[-1] == "\n")): 
 141                     if ((longer
[-2] == "\r") and (longer
[:-2] == shorter
[:-1])): 
 143                     if ((longer
[-2:] == shorter
[-2:]) and (longer
[-3] == "\r") and (longer
[:-3] == shorter
[:-2])): 
 147 def expandKnownAGVars(value
): 
 148     return expandVars(value
, includeEnv
=False) 
 150 def expandVars(value
, includeEnv
=True): 
 151     """Syntax: ${myvar,default="default value"}""" 
 152     import activegrid
.runtime 
as runtime
 
 153     sx 
= value
.find("${") 
 155         result 
= asString(value
[:sx
]) 
 156         endx 
= value
.find("}") 
 159             defsx 
= value
.find(",default=\"") 
 160             if ((defsx 
> sx
) and (defsx 
< endx
)): 
 161                 varname 
= value
[sx
+2:defsx
] 
 162                 if (value
[endx
-1] == '"'): 
 163                     defaultValue 
= value
[defsx
+10:endx
-1] 
 164             if (defaultValue 
== None): 
 165                 varname 
= value
[sx
+2:endx
] 
 166             if (varname 
== AG_SYSTEM_VAR
): 
 167                 varval 
= runtime
.appInfo
.getSystemDir() 
 168             elif (varname 
== AG_SYSTEM_STATIC_VAR
): 
 169                 varval 
= runtime
.appInfo
.getSystemStaticDir() 
 170             elif (varname 
== AG_APP_VAR
): 
 171                 varval 
= runtime
.appInfo
.getAppDir() 
 172             elif (varname 
== AG_APP_STATIC_VAR
): 
 173                 varval 
= runtime
.appInfo
.getAppStaticDir() 
 176                     varval 
= os
.getenv(varname
) 
 179             if ((varval 
== None) and (defaultValue 
!= None)): 
 180                 varval 
= defaultValue
 
 182                 result 
+= value
[sx
:endx
+1] 
 185             return result 
+ expandVars(value
[endx
+1:]) 
 188 def toPHPpath(path
, otherdir
=None): 
 189     return convertSourcePath(path
, "php", otherdir
=otherdir
) 
 191 def toPythonpath(path
, otherdir
=None): 
 192     return convertSourcePath(path
, "python", otherdir
=otherdir
) 
 194 def toUnixPath(path
): 
 195     if (path 
!= None and os
.sep 
!= '/'): 
 196         path 
= path
.replace(os
.sep
, '/') 
 199 def convertSourcePath(path
, to
, otherdir
=None): 
 203     pythonNode 
= os
.sep 
+ fromname 
+ os
.sep
 
 204     ix 
= path
.find(pythonNode
) 
 206         ix 
= path
.find(fromname
) - 1 
 207         if ((ix 
< 0) or (len(path
) <= ix
+7) 
 208             or (path
[ix
] not in ("\\", "/")) or (path
[ix
+7]  not in ("\\", "/"))): 
 209             raise Exception("Not in a %s source tree.  Cannot create file name for %s." % (fromname
, path
)) 
 210         if (otherdir 
== None): 
 211             return path
[:ix
+1] + to 
+ path
[ix
+7:] 
 213             return otherdir 
+ path
[ix
+7:] 
 214     if (otherdir 
== None): 
 215         return path
.replace(pythonNode
, os
.sep 
+ to 
+ os
.sep
) 
 217         return otherdir 
+ path
[ix
+7:] 
 220 def visit(directory
, files
, extension
, maxLevel
=None, level
=1): 
 221     testdirs 
= os
.listdir(directory
) 
 222     for thing 
in testdirs
: 
 223         fullpath 
= os
.path
.join(directory
, thing
) 
 224         if (os
.path
.isdir(fullpath
) and (maxLevel 
== None or level 
< maxLevel
)): 
 225             visit(fullpath
, files
, extension
, maxLevel
, level
+1) 
 226         elif thing
.endswith(extension
): 
 227             fullname 
= os
.path
.normpath(os
.path
.join(directory
, thing
)) 
 228             if not fullname 
in files
: 
 229                 files
.append(fullname
) 
 231 def listFilesByExtensionInPath(path
=[], extension
='.lyt', maxLevel
=None): 
 233     for directory 
in path
: 
 234         visit(directory
, retval
, extension
, maxLevel
) 
 237 def getFileLastModificationTime(fileName
): 
 238     return os
.path
.getmtime(fileName
) 
 240 def findFileLocation(location
, fileName
): 
 241     i 
= fileName
.rfind(os
.sep
) 
 243         fileName 
= fileName
[:i
] 
 244     while location
[0:2] == '..' and location
[2:3] == os
.sep
: 
 245         location 
= location
[3:] 
 246         i 
= fileName
.rfind(os
.sep
) 
 247         fileName 
= fileName
[:i
] 
 248     absPath 
= fileName 
+ os
.sep 
+ location
 
 251 def getAllExistingFiles(files
, basepath
=None, forceForwardSlashes
=False): 
 252     """For each file in files, if it exists, adds its absolute path to the rtn list. If file is a dir, calls this function recursively on all child files in the dir. 
 253     If basepath is set, and if the file being processed is relative to basedir, adds that relative path to rtn list instead of the abs path. 
 254     Is this is Windows, and forceForwardSlashes is True, make sure returned paths only have forward slashes.""" 
 255     if isinstance(files
, basestring
): 
 259         if os
.path
.exists(file):  
 260             if os
.path
.isfile(file): 
 261                 if basepath 
and hasAncestorDir(file, basepath
): 
 262                     rtn
.append(getRelativePath(file, basepath
)) 
 264                     rtn
.append(os
.path
.abspath(str(file))) 
 265             elif os
.path
.isdir(file): 
 266                 dircontent 
= [os
.path
.join(file, f
) for f 
in os
.listdir(file)] 
 267                 rtn
.extend(getAllExistingFiles(dircontent
, basepath
)) 
 269     if forceForwardSlashes 
and sysutils
.isWindows(): 
 272             newRtn
.append(f
.replace("\\", "/")) 
 277 def hasAncestorDir(file, parent
): 
 278     """Returns true if file has the dir 'parent' as some parent in its path.""" 
 279     return getRelativePath(file, parent
) != None 
 281 def getRelativePath(file, basedir
): 
 282     """Returns relative path from 'basedir' to 'file', assuming 'file' lives beneath 'basedir'. If it doesn't, returns None.""" 
 283     file = os
.path
.abspath(file) 
 284     parent 
= os
.path
.abspath(basedir
) 
 289     if file.startswith(parent
): 
 290         return file[len(parent
)+1:] 
 295     if not os
.path
.isdir(dir): 
 297     return len(os
.listdir(dir)) == 0 
 300 def zip(zipfilepath
, basedir
=None, files
=None): 
 301     """Zip all files in files and save zip as zipfilepath. If files is None, zip all files in basedir. For all files to be zipped, if they are relative to basedir, include the relative path in the archive.""" 
 303     if not files 
and not basedir
: 
 304         raise AssertionError("Either 'basedir' or 'files' must be set") 
 307         aglogging
.debug(fileutilsLogger
,\
 
 308                         "Looking for files to zip in %s" % basedir
) 
 309         files 
= getAllExistingFiles(basedir
) 
 311         # removes files that don't exist and gets abs for each 
 312         files 
= getAllExistingFiles(files
)  
 315         aglogging
.debug(fileutilsLogger
, "No files to zip, nothing to do") 
 318     z 
= zipfile
.ZipFile(zipfilepath
, mode
="w", compression
=zipfile
.ZIP_DEFLATED
) 
 324                 arcname 
= getRelativePath(file, basedir
) 
 327                 aglogging
.debug(fileutilsLogger
,\
 
 328                                 "%s: adding %s with arcname %s" %\
 
 329                                 (zipfilepath
, file, arcname
)) 
 330             z
.write(file, arcname
) 
 337 def unzip(zipfilepath
, extractdir
): 
 338     """Unzip zipfilepath into extractdir.""" 
 339     z 
= zipfile
.ZipFile(zipfilepath
, mode
="r") 
 340     for info 
in z
.infolist(): 
 341         filename 
= os
.path
.join(extractdir
, info
.filename
) 
 343             dir = os
.path
.dirname(filename
) 
 344             aglogging
.debug(fileutilsLogger
, "Creating dir %s" % dir) 
 345             os
.makedirs(dir) # do we have to worry about permissions? 
 348         if os
.path
.isdir(filename
): 
 350         aglogging
.debug(fileutilsLogger
,\
 
 351                        ("Writing arcfile %s to %s" % (info
.filename
, filename
))) 
 352         f 
= open(filename
, "w") 
 353         f
.write(z
.read(info
.filename
)) 
 358 def copyFile(src
, dest
): 
 359     """Copies file src to dest. Creates directories in 'dest' path if necessary.""" 
 360     destdir 
= os
.path
.dirname(dest
) 
 361     if not os
.path
.exists(destdir
): 
 363     shutil
.copy(src
, dest
) 
 367 def copyDir(src
, dest
): 
 368     """Copies dir 'src' into dir 'dest'. Creates 'dest' if it does not exist.""" 
 369     shutil
.copytree(src
, dest
) 
 374     if not os
.path
.exists(file): 
 376     if os
.path
.isfile(file): 
 378     elif os
.path
.isdir(file): 
 382 def getUserTempDir(): 
 383     systemTempDir 
= utillang
.getSystemTempDir() 
 384     userName 
= sysutils
.getUserName() 
 385     userNameNoSpace 
= userName
.replace('_','__').replace(' ','_') 
 386     userTempDir 
= systemTempDir 
+ os
.sep 
+ "activegrid_" + userNameNoSpace
 
 389 def createUserTempDir(): 
 390     userTempDir 
= getUserTempDir() 
 391     if not os
.path
.exists(userTempDir
): 
 392         os
.makedirs(userTempDir
) 
 393         os
.chmod(userTempDir
, 0700) 
 399 warnings
.filterwarnings("ignore", message
="tmpnam is a potential security risk to your program") 
 405 #@accepts str, dict, str, str, boolean 
 406 def replaceToken(infilepath
, tokens
={}, outfilepath
=None, delim
="@@",\
 
 408     """Replaces tokens of form 'delim'<tokenname>'delim' in file at 'infilepath', using values in dict 'tokens'. If 'outfilepath' is set, writes output to 'outfilepath', if not set, overwrites original file. If 'useEnv' is True, adds os.environ to 'tokens'. This makes it possible to define an env var FOO=BLAH, and have @@FOO@@ be replaced with BLAH, without explicitly passing FOO=BLAH in 'tokens'. Note that entries in 'tokens' take precedence over entries in os.environ.""" 
 411         for key
, val 
in os
.environ
.items(): 
 412             # passed in tokens take precedence 
 413             if not tokens
.has_key(key
): 
 416     f 
= open(infilepath
, "r") 
 422     for token
, value 
in tokens
.items(): 
 423         content 
= content
.replace("%s%s%s" % (delim
, token 
, delim
), str(value
)) 
 425     if not outfilepath
: outfilepath 
= infilepath
 
 426     f 
= open(outfilepath
, "w")