func runCommand(kmgc *kmgConfig.Env, args []string) { os.Chdir(kmgc.ProjectPath) logDir := filepath.Join(kmgc.LogPath, "run") kmgFile.MustMkdirAll(logDir) thisLogFilePath := filepath.Join(logDir, time.Now().Format(kmgTime.FormatFileName)+".log") kmgFile.MustWriteFile(thisLogFilePath, []byte{}) if !kmgPlatform.GetCompiledPlatform().Compatible(kmgPlatform.WindowsAmd64) { lastLogPath := filepath.Join(logDir, "last.log") if kmgFile.MustFileExist(lastLogPath) { kmgFile.MustSymlink(kmgFile.MustReadSymbolLink(lastLogPath), filepath.Join(logDir, "last2.log")) } kmgFile.MustSymlink(filepath.Base(thisLogFilePath), lastLogPath) } //TODO 大部分命令是 kmg gorun xxx 在这个地方可以直接调用gorun解决问题,这样可以少开一个进程加快了一些速度 // 问题: 上述做法不靠谱,会导致last.log没有用处. //if len(args) >= 2 && args[0] == "kmg" && strings.EqualFold(args[1], "gorun") { // os.Args = append(args[1:], os.Args[1:]...) // goCmd.GoRunCmd() // return //} // 下面的做法不靠谱,会让signle无法传递 //err := kmgCmd.CmdSlice(append(args, os.Args[1:]...)). // SetDir(kmgc.ProjectPath). // RunAndTeeOutputToFile(thisLogFilePath) // TODO bash转义 bashCmd := strings.Join(append(args, os.Args[1:]...), " ") bashCmdStr := bashCmd + " 2>&1 | tee -i " + thisLogFilePath + " ; test ${PIPESTATUS[0]} -eq 0" if kmgPlatform.IsWindows() { err := kmgCmd.CmdString(bashCmdStr).SetDir(kmgc.ProjectPath).StdioRun() if err != nil { err = fmt.Errorf("kmg make: %s", err) kmgConsole.ExitOnErr(err) } return } else { err := kmgCmd.CmdBash(bashCmdStr).SetDir(kmgc.ProjectPath).StdioRun() if err != nil { err = fmt.Errorf("kmg make: %s", err) kmgConsole.ExitOnErr(err) } return } }
// 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 }