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")