Example #1
0
// key 表示一组缓存,pathList 即这组缓存相关的文件
// 比较容易用错的情况:
// key := 1
// pathList := []string{"/a.txt","/b.txt"}
// a.txt 或者 b.txt 中任意有文件发生变化,这个 key 对应的缓存都会被更新
// 如果要对单个文件进行缓存控制,那么应该一个文件一个 key
func MustMd5FileChangeCache(key string, pathList []string, f func()) {
	// 此处需要考虑,
	//   用户新添加了一个文件
	//   用户删除了一个文件
	//   用户编辑了一个文件
	//   用户在目录里面添加了一个文件
	//   用在在目录里面删除了一个文件
	//读取文件修改时间缓存信息
	toChange := false
	cacheInfo := map[string]string{}
	cacheFilePath := getFileChangeCachePath(key)
	err := kmgGob.ReadFile(cacheFilePath, &cacheInfo)
	if err != nil {
		//忽略缓存读取的任何错误
		cacheInfo = map[string]string{}
	}
	hasReadFileMap := map[string]bool{}
	for _, path := range pathList {
		statList, err := kmgFile.GetAllFileAndDirectoryStat(path)
		if err != nil {
			if os.IsNotExist(err) {
				toChange = true
				//fmt.Printf("[MustFileChangeCache] path:[%s] not exist\n", path)
				break
			}
			panic(err)
		}

		for _, stat := range statList {
			if stat.Fi.IsDir() {
				continue
			}
			hasReadFileMap[stat.FullPath] = true
			if stat.Fi.Mode()&os.ModeSymlink == os.ModeSymlink {
				if "symlink_"+kmgFile.MustReadSymbolLink(stat.FullPath) != cacheInfo[stat.FullPath] {
					toChange = true
					break
				}
				continue
			}
			if kmgCrypto.MustMd5File(stat.FullPath) != cacheInfo[stat.FullPath] {
				toChange = true
				//fmt.Printf("[MustMd5FileChangeCache] path:[%s] mod md5 not match save[%s] file[%s]\n", stat.FullPath,
				//	cacheMd5, kmgCrypto.MustMd5File(stat.FullPath))
				break
			}
		}
		if toChange {
			break
		}
	}
	//删除一个已经存储在缓存列表里面的文件,是一个修改.
	for fullPath := range cacheInfo {
		if !hasReadFileMap[fullPath] {
			toChange = true
			break
		}
	}
	if !toChange {
		return
	}
	f()
	cacheInfo = map[string]string{}
	for _, path := range pathList {
		statList, err := kmgFile.GetAllFileAndDirectoryStat(path)
		if err != nil {
			panic(err)
		}
		for _, stat := range statList {
			if stat.Fi.IsDir() {
				continue
			}
			if stat.Fi.Mode()&os.ModeSymlink == os.ModeSymlink {
				linkToPath := kmgFile.MustReadSymbolLink(stat.FullPath)
				cacheInfo[stat.FullPath] = "symlink_" + linkToPath
				continue
			}
			cacheInfo[stat.FullPath] = kmgCrypto.MustMd5File(stat.FullPath)
		}
	}
	kmgFile.MustMkdirForFile(cacheFilePath)
	kmgGob.MustWriteFile(cacheFilePath, cacheInfo)
	//保存文件缓存信息
	return
}
Example #2
0
func goRunInstall(goPath string, pathOrPkg string) {
	//只能更新本GOPATH里面的pkg,不能更多多个GOPATH里面其他GOPATH的pkg缓存.
	// go install 已知bug1 删除某个package里面的部分文件,然后由于引用到了旧的实现的代码,不会报错.删除pkg解决问题.
	// go install 已知bug2 如果一个package先是main,然后build了一个东西,然后又改成了非main,再gorun会使用旧的缓存/bin/里面的缓存.
	// TODO 已知bug3 当同一个项目的多个编译目标使用了同一个pkg,然后这个pkg变化了,缓存会出现A/B 问题,导致缓存完全无用.
	ctx := &goRunInstallContext{
		platform:          kmgPlatform.GetCompiledPlatform().String(),
		targetPkgMapCache: map[string]bool{},
		pkgMapCache:       map[string]*gorunCachePkgInfo{},
	}
	ctx.targetCachePath = filepath.Join(goPath, "tmp", "gorun", kmgCrypto.Md5HexFromString("target_"+pathOrPkg+"_"+ctx.platform))
	ctx.pkgCachePath = filepath.Join(goPath, "tmp", "gorun", "allPkgCache")
	ok := ctx.goRunInstallIsValidAndInvalidCache(goPath, pathOrPkg)
	if ok {
		//fmt.Println("use cache")
		return
	}
	//fmt.Println("not use cache")
	runCmdSliceWithGoPath(goPath, []string{"go", "install", pathOrPkg})
	// 填充缓存
	platform := ctx.platform
	ctx.targetPkgMapCache = map[string]bool{}
	outputJson := kmgCmd.CmdSlice([]string{"go", "list", "-json", pathOrPkg}).
		MustSetEnv("GOPATH", goPath).MustCombinedOutput()
	listObj := &struct {
		Deps []string
		Name string
	}{}
	kmgJson.MustUnmarshal(outputJson, &listObj)
	if listObj.Name != "main" {
		fmt.Printf("run non main package %s\n", pathOrPkg)
		return
	}
	listObj.Deps = append(listObj.Deps, pathOrPkg)
	for _, pkgName := range listObj.Deps {
		srcpkgPath := filepath.Join(goPath, "src", pkgName)
		fileList, err := kmgFile.ReadDirFileOneLevel(srcpkgPath)
		if err != nil {
			if !os.IsNotExist(err) {
				panic(err)
			}
			// 没有找到pkg,可能是这个pkg在GOROOT出现过,此处暂时不管.
			continue
		}
		ctx.targetPkgMapCache[pkgName] = true
		pkgInfo := &gorunCachePkgInfo{
			GoFileMap: map[string]uint64{},
		}
		for _, file := range fileList {
			ext := filepath.Ext(file)
			if ext == ".go" {
				pkgInfo.GoFileMap[file] = mustCheckSumFile(filepath.Join(srcpkgPath, file))
			}
		}
		pkgInfo.IsMain = pkgName == pathOrPkg
		pkgInfo.Name = pkgName
		pkgBinPath := pkgInfo.getPkgBinPath(goPath, platform)
		pkgInfo.PkgMd5 = mustCheckSumFile(pkgBinPath)
		ctx.pkgMapCache[pkgName] = pkgInfo
	}
	kmgGob.MustWriteFile(ctx.targetCachePath, ctx.targetPkgMapCache)
	kmgGob.MustWriteFile(ctx.pkgCachePath, ctx.pkgMapCache)
}
Example #3
0
// 这个函数bug太多,以废弃,请使用 MustMd5FileChangeCache
// 根据文件变化,对f这个请求进行缓存
// key表示这件事情的缓存key
// pathList表示需要监控的目录
// 文件列表里面如果有文件不存在,会运行代码
// 已知bug,小于1秒的修改不能被检测到.
// @deprecated
func MustFileChangeCache(key string, pathList []string, f func()) {
	//读取文件修改时间缓存信息
	toChange := false
	cacheInfo := map[string]time.Time{}
	cacheFilePath := getFileChangeCachePath(key)
	err := kmgGob.ReadFile(cacheFilePath, &cacheInfo)
	if err != nil {
		cacheInfo = map[string]time.Time{}
	}
	for _, path := range pathList {
		statList, err := kmgFile.GetAllFileAndDirectoryStat(path)
		if err != nil {
			if os.IsNotExist(err) {
				toChange = true
				//fmt.Printf("[MustFileChangeCache] path:[%s] not exist\n", path)
				break
			}
			panic(err)
		}
		for _, stat := range statList {
			if stat.Fi.IsDir() {
				continue
			}
			cacheTime := cacheInfo[stat.FullPath]
			if cacheTime.IsZero() {
				toChange = true
				//fmt.Printf("[MustFileChangeCache] path:[%s] no save mod time\n", stat.FullPath)
				break
			}
			if stat.Fi.ModTime() != cacheTime {
				toChange = true
				//fmt.Printf("[MustFileChangeCache] path:[%s] mod time not match save[%s] file[%s]\n", stat.FullPath,
				//	cacheTime, stat.Fi.ModTime())
				break
			}
		}
		if toChange {
			break
		}
	}
	if !toChange {
		return
	}
	f()
	cacheInfo = map[string]time.Time{}
	for _, path := range pathList {
		statList, err := kmgFile.GetAllFileAndDirectoryStat(path)
		if err != nil {
			panic(err)
		}
		for _, stat := range statList {
			if stat.Fi.IsDir() {
				continue
			}
			cacheInfo[stat.FullPath] = stat.Fi.ModTime()
		}
	}
	kmgFile.MustMkdirForFile(cacheFilePath)
	kmgGob.MustWriteFile(cacheFilePath, cacheInfo)
	//保存文件缓存信息
	return
}