github.com/keysonzzz/kmg@v0.0.0-20151121023212-05317bfd7d39/kmgCache/FileChangeCache.go (about)

     1  package kmgCache
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  
     7  	"github.com/bronze1man/kmg/encoding/kmgGob"
     8  	"github.com/bronze1man/kmg/kmgConfig"
     9  	"github.com/bronze1man/kmg/kmgCrypto"
    10  	"github.com/bronze1man/kmg/kmgFile"
    11  )
    12  
    13  //这个测试要用到.
    14  func getFileChangeCachePath(key string) string {
    15  	// 此处key长度不可控,所以用md5.
    16  	return filepath.Join(kmgConfig.DefaultEnv().TmpPath, "FileChangeCache", kmgCrypto.Md5HexFromString(key))
    17  }
    18  
    19  // key 表示一组缓存,pathList 即这组缓存相关的文件
    20  // 比较容易用错的情况:
    21  // key := 1
    22  // pathList := []string{"/a.txt","/b.txt"}
    23  // a.txt 或者 b.txt 中任意有文件发生变化,这个 key 对应的缓存都会被更新
    24  // 如果要对单个文件进行缓存控制,那么应该一个文件一个 key
    25  func MustMd5FileChangeCache(key string, pathList []string, f func()) {
    26  	// 此处需要考虑,
    27  	//   用户新添加了一个文件
    28  	//   用户删除了一个文件
    29  	//   用户编辑了一个文件
    30  	//   用户在目录里面添加了一个文件
    31  	//   用在在目录里面删除了一个文件
    32  	//读取文件修改时间缓存信息
    33  	toChange := false
    34  	cacheInfo := map[string]string{}
    35  	cacheFilePath := getFileChangeCachePath(key)
    36  	err := kmgGob.ReadFile(cacheFilePath, &cacheInfo)
    37  	if err != nil {
    38  		//忽略缓存读取的任何错误
    39  		cacheInfo = map[string]string{}
    40  	}
    41  	hasReadFileMap := map[string]bool{}
    42  	for _, path := range pathList {
    43  		statList, err := kmgFile.GetAllFileAndDirectoryStat(path)
    44  		if err != nil {
    45  			if os.IsNotExist(err) {
    46  				toChange = true
    47  				//fmt.Printf("[MustFileChangeCache] path:[%s] not exist\n", path)
    48  				break
    49  			}
    50  			panic(err)
    51  		}
    52  
    53  		for _, stat := range statList {
    54  			if stat.Fi.IsDir() {
    55  				continue
    56  			}
    57  			hasReadFileMap[stat.FullPath] = true
    58  			if stat.Fi.Mode()&os.ModeSymlink == os.ModeSymlink {
    59  				if "symlink_"+kmgFile.MustReadSymbolLink(stat.FullPath)!=cacheInfo[stat.FullPath]{
    60  					toChange = true
    61  					break
    62  				}
    63  				continue
    64  			}
    65  			if kmgCrypto.MustMd5File(stat.FullPath) != cacheInfo[stat.FullPath] {
    66  				toChange = true
    67  				//fmt.Printf("[MustMd5FileChangeCache] path:[%s] mod md5 not match save[%s] file[%s]\n", stat.FullPath,
    68  				//	cacheMd5, kmgCrypto.MustMd5File(stat.FullPath))
    69  				break
    70  			}
    71  		}
    72  		if toChange {
    73  			break
    74  		}
    75  	}
    76  	//删除一个已经存储在缓存列表里面的文件,是一个修改.
    77  	for fullPath := range cacheInfo {
    78  		if !hasReadFileMap[fullPath] {
    79  			toChange = true
    80  			break
    81  		}
    82  	}
    83  	if !toChange {
    84  		return
    85  	}
    86  	f()
    87  	cacheInfo = map[string]string{}
    88  	for _, path := range pathList {
    89  		statList, err := kmgFile.GetAllFileAndDirectoryStat(path)
    90  		if err != nil {
    91  			panic(err)
    92  		}
    93  		for _, stat := range statList {
    94  			if stat.Fi.IsDir() {
    95  				continue
    96  			}
    97  			if stat.Fi.Mode()&os.ModeSymlink == os.ModeSymlink {
    98  				linkToPath:=kmgFile.MustReadSymbolLink(stat.FullPath)
    99  				cacheInfo[stat.FullPath] = "symlink_"+linkToPath
   100  				continue
   101  			}
   102  			cacheInfo[stat.FullPath] = kmgCrypto.MustMd5File(stat.FullPath)
   103  		}
   104  	}
   105  	kmgFile.MustMkdirForFile(cacheFilePath)
   106  	kmgGob.MustWriteFile(cacheFilePath, cacheInfo)
   107  	//保存文件缓存信息
   108  	return
   109  }