2012-08-16 23:41:25 -04:00
" cache.vim
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
" @Website: http://www.vim.org/account/profile.php?user_id=4037
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
" @Created: 2007-06-30.
2013-11-16 14:45:48 -05:00
" @Last Change: 2013-09-25.
" @Revision: 0.1.220
2012-08-16 23:41:25 -04:00
2013-11-16 14:45:48 -05:00
" The cache directory. If empty, use |tlib#dir#MyRuntime|.'/cache'.
" You might want to delete old files from this directory from time to
" time with a command like: >
" find ~/vimfiles/cache/ -atime +31 -type f -print -delete
TLet g :tlib_cache = ''
2012-08-16 23:41:25 -04:00
" |tlib#cache#Purge()|: Remove cache files older than N days.
TLet g :tlib #cache #purge_days = 31
" Purge the cache every N days. Disable automatic purging by setting
" this value to a negative value.
TLet g :tlib #cache #purge_every_days = 31
" The encoding used for the purge-cache script.
" Default: 'enc'
TLet g :tlib #cache #script_encoding = &enc
" Whether to run the directory removal script:
" 0 ... No
" 1 ... Query user
" 2 ... Yes
TLet g :tlib #cache #run_script = 1
2013-11-16 14:45:48 -05:00
" Verbosity level:
" 0 ... Be quiet
" 1 ... Display informative message
" 2 ... Display detailed messages
TLet g :tlib #cache #verbosity = 1
2013-04-13 13:45:21 -04:00
2012-08-16 23:41:25 -04:00
" A list of regexps that are matched against partial filenames of the
" cached files. If a regexp matches, the file won't be removed by
" |tlib#cache#Purge()|.
TLet g :tlib #cache #dont_purge = ['[\/]\.last_purge$' ]
2013-11-16 14:45:48 -05:00
" If the cache filename is longer than N characters, use
" |pathshorten()|.
TLet g :tlib #cache #max_filename = 200
2012-08-16 23:41:25 -04:00
" :display: tlib#cache#Dir(?mode = 'bg')
" The default cache directory.
function ! tlib #cache #Dir ( ...) "{{{3
TVarArg ['mode' , 'bg' ]
let dir = tlib #var #Get ( 'tlib_cache' , mode )
if empty ( dir )
let dir = tlib #file #Join ( [tlib #dir #MyRuntime ( ) , 'cache' ])
endif
return dir
endf
2013-04-13 13:45:21 -04:00
" :def: function! tlib#cache#Filename(type, ?file=%, ?mkdir=0, ?dir='')
2012-08-16 23:41:25 -04:00
function ! tlib #cache #Filename ( type , ...) "{{{3
" TLogDBG 'bufname='. bufname('.')
2013-11-16 14:45:48 -05:00
let dir0 = a :0 > = 3 && ! empty ( a :3 ) ? a :3 : tlib #cache #Dir ( )
let dir = dir0
2012-08-16 23:41:25 -04:00
if a :0 > = 1 && ! empty ( a :1 )
let file = a :1
else
if empty ( expand ( '%:t' ) )
return ''
endif
let file = expand ( '%:p' )
let file = tlib #file #Relative ( file , tlib #file #Join ( [dir , '..' ]) )
endif
" TLogVAR file, dir
let mkdir = a :0 > = 2 ? a :2 : 0
let file = substitute ( file , '\.\.\|[:&<>]\|//\+\|\\\\\+' , '_' , 'g' )
let dirs = [dir , a :type ]
let dirf = fnamemodify ( file , ':h' )
if dirf ! = '.'
call add ( dirs , dirf )
endif
let dir = tlib #file #Join ( dirs )
" TLogVAR dir
let dir = tlib #dir #PlainName ( dir )
" TLogVAR dir
let file = fnamemodify ( file , ':t' )
" TLogVAR file, dir, mkdir
let cache_file = tlib #file #Join ( [dir , file ])
2013-11-16 14:45:48 -05:00
if len ( cache_file ) > g :tlib #cache #max_filename
let shortfilename = pathshorten ( file ) .'_' . tlib #hash #Adler32 ( file )
let cache_file = tlib #cache #Filename ( a :type , shortfilename , mkdir , dir0 )
else
if mkdir && ! isdirectory ( dir )
try
call mkdir ( dir , 'p' )
catch /^Vim\%((\a\+)\)\=:E739:/
if filereadable ( dir ) && ! isdirectory ( dir )
echoerr 'TLib: Cannot create directory for cache file because a file with the same name exists (please delete it):' dir
" call delete(dir)
" call mkdir(dir, 'p')
endif
endtry
endif
endif
2012-08-16 23:41:25 -04:00
" TLogVAR cache_file
return cache_file
endf
function ! tlib #cache #Save ( cfile , dictionary ) "{{{3
2013-04-13 13:45:21 -04:00
call tlib #persistent #Save ( a :cfile , a :dictionary )
2012-08-16 23:41:25 -04:00
endf
function ! tlib #cache #Get ( cfile ) "{{{3
call tlib #cache #MaybePurge ( )
2013-04-13 13:45:21 -04:00
return tlib #persistent #Get ( a :cfile )
2012-08-16 23:41:25 -04:00
endf
2013-11-16 14:45:48 -05:00
" Get a cached value from cfile. If it is outdated (compared to ftime)
" or does not exist, create it calling a generator function.
function ! tlib #cache #Value ( cfile , generator , ftime , ...) "{{{3
if ! filereadable ( a :cfile ) | | ( a :ftime ! = 0 && getftime ( a :cfile ) < a :ftime )
let args = a :0 > = 1 ? a :1 : []
let val = call ( a :generator , args )
" TLogVAR a:generator, args, val
call tlib #cache #Save ( a :cfile , {'val' : val })
return val
else
let val = tlib #cache #Get ( a :cfile )
return val .val
endif
endf
2012-08-16 23:41:25 -04:00
" Call |tlib#cache#Purge()| if the last purge was done before
2013-04-13 13:45:21 -04:00
" |g:tlib#cache#purge_every_days|.
function ! tlib #cache #MaybePurge ( ) "{{{3
if g :tlib #cache #purge_every_days < 0
return
endif
let dir = tlib #cache #Dir ( 'g' )
let last_purge = tlib #file #Join ( [dir , '.last_purge' ])
let last_purge_exists = filereadable ( last_purge )
if last_purge_exists
let threshold = localtime ( ) - g :tlib #cache #purge_every_days * g :tlib #date #dayshift
let should_purge = getftime ( last_purge ) < threshold
else
let should_purge = 0 " should ignore empty dirs, like the tmru one: !empty(glob(tlib#file#Join([dir, '**'])))
endif
if should_purge
2012-08-16 23:41:25 -04:00
if last_purge_exists
2013-04-13 13:45:21 -04:00
let yn = 'y'
2012-08-16 23:41:25 -04:00
else
2013-04-13 13:45:21 -04:00
let txt = "TLib: The cache directory '" . dir ."' should be purged of old files.\nDelete files older than " . g :tlib #cache #purge_days ." days now?"
let yn = tlib #input #Dialog ( txt , ['yes' , 'no' ], 'no' )
2012-08-16 23:41:25 -04:00
endif
2013-04-13 13:45:21 -04:00
if yn = ~ '^y\%[es]$'
call tlib #cache #Purge ( )
else
let g :tlib #cache #purge_every_days = -1
if ! last_purge_exists
call s :PurgeTimestamp ( dir )
2012-08-16 23:41:25 -04:00
endif
2013-04-13 13:45:21 -04:00
echohl WarningMsg
echom "TLib: Please run :call tlib#cache#Purge() to clean up " . dir
echohl NONE
2012-08-16 23:41:25 -04:00
endif
2013-04-13 13:45:21 -04:00
elseif ! last_purge_exists
call s :PurgeTimestamp ( dir )
endif
endf
2012-08-16 23:41:25 -04:00
" Delete old files.
function ! tlib #cache #Purge ( ) "{{{3
let threshold = localtime ( ) - g :tlib #cache #purge_days * g :tlib #date #dayshift
let dir = tlib #cache #Dir ( 'g' )
2013-11-16 14:45:48 -05:00
if g :tlib #cache #verbosity > = 1
2013-04-13 13:45:21 -04:00
echohl WarningMsg
echom "TLib: Delete files older than " . g :tlib #cache #purge_days ." days from " . dir
echohl NONE
endif
2012-08-16 23:41:25 -04:00
let files = tlib #cache #ListFilesInCache ( )
let deldir = []
let newer = []
let msg = []
let more = &more
set nomore
try
for file in files
if isdirectory ( file )
if empty ( filter ( copy ( newer ) , 'strpart(v:val, 0, len(file)) ==# file' ) )
call add ( deldir , file )
endif
else
if getftime ( file ) < threshold
if delete ( file )
call add ( msg , "TLib: Could not delete cache file: " . file )
2013-11-16 14:45:48 -05:00
elseif g :tlib #cache #verbosity > = 2
2012-08-16 23:41:25 -04:00
call add ( msg , "TLib: Delete cache file: " . file )
endif
else
call add ( newer , file )
endif
endif
endfor
finally
let &more = more
endtry
2013-11-16 14:45:48 -05:00
if ! empty ( msg ) && g :tlib #cache #verbosity > = 1
2012-08-16 23:41:25 -04:00
echo join ( msg , "\n" )
endif
if ! empty ( deldir )
if &shell = ~ 'sh\(\.exe\)\?$'
let scriptfile = 'deldir.sh'
let rmdir = 'rm -rf %s'
else
let scriptfile = 'deldir.bat'
let rmdir = 'rmdir /S /Q %s'
endif
let enc = g :tlib #cache #script_encoding
if has ( 'multi_byte' ) && enc ! = &enc
call map ( deldir , 'iconv(v:val, &enc, enc)' )
endif
let scriptfile = tlib #file #Join ( [dir , scriptfile ])
if filereadable ( scriptfile )
let script = readfile ( scriptfile )
else
let script = []
endif
let script + = map ( copy ( deldir ) , 'printf(rmdir, shellescape(v:val, 1))' )
let script = tlib #list #Uniq ( script )
call writefile ( script , scriptfile )
call inputsave ( )
if g :tlib #cache #run_script = = 0
2013-11-16 14:45:48 -05:00
if g :tlib #cache #verbosity > = 1
echohl WarningMsg
if g :tlib #cache #verbosity > = 2
echom "TLib: Purged cache. Need to run script to delete directories"
endif
echom "TLib: Please review and execute: " . scriptfile
echohl NONE
2013-04-13 13:45:21 -04:00
endif
2012-08-16 23:41:25 -04:00
else
try
2013-04-13 13:45:21 -04:00
let yn = g :tlib #cache #run_script = = 2 ? 'y' : tlib #input #Dialog ( "TLib: About to delete directories by means of a shell script.\nDirectory removal script: " . scriptfile ."\nRun script to delete directories now?" , ['yes' , 'no' , 'edit' ], 'no' )
2012-08-16 23:41:25 -04:00
if yn = ~ '^y\%[es]$'
exec 'cd ' . fnameescape ( dir )
exec '! ' &shell shellescape ( scriptfile , 1 )
exec 'cd -'
call delete ( scriptfile )
elseif yn = ~ '^e\%[dit]$'
exec 'edit ' . fnameescape ( scriptfile )
endif
finally
call inputrestore ( )
endtry
endif
endif
call s :PurgeTimestamp ( dir )
endf
function ! s :PurgeTimestamp ( dir ) "{{{3
let last_purge = tlib #file #Join ( [a :dir , '.last_purge' ])
" TLogVAR last_purge
call writefile ( [" " ], last_purge )
endf
function ! tlib #cache #ListFilesInCache ( ...) "{{{3
let dir = a :0 > = 1 ? a :1 : tlib #cache #Dir ( 'g' )
if v :version > 702 | | ( v :version = = 702 && has ( 'patch51' ) )
let filess = glob ( tlib #file #Join ( [dir , '**' ]) , 1 )
else
let filess = glob ( tlib #file #Join ( [dir , '**' ]) )
endif
let files = reverse ( split ( filess , '\n' ) )
let pos0 = len ( tlib #dir #CanonicName ( dir ) )
call filter ( files , 's:ShouldPurge(strpart(v:val, pos0))' )
return files
endf
function ! s :ShouldPurge ( partial_filename ) "{{{3
" TLogVAR a:partial_filename
for rx in g :tlib #cache #dont_purge
if a :partial_filename = ~ rx
" TLogVAR a:partial_filename, rx
return 0
endif
endfor
return 1
endf