package gitpb // An app to submit patches for the 30 GO GUI repos import ( "fmt" "os" "path/filepath" "time" "go.wit.com/lib/gui/shell" "go.wit.com/log" "google.golang.org/protobuf/types/known/timestamppb" ) func (repo *Repo) Mtime(fname string) *time.Time { var fileTime *time.Time tmp, err := repo.statMtime(fname) fileTime = &tmp if err != nil { log.Info("MTime got err", err) return nil } return fileTime } func (repo *Repo) statMtime(filename string) (time.Time, error) { pathf := filepath.Join(repo.FullPath, filename) statf, err := os.Stat(pathf) if err == nil { return statf.ModTime(), nil } log.Log(WARN, "Mtime() os.Stat() error", pathf, err) return time.Now(), err } func (repo *Repo) changedDir() bool { fname := ".git" fileTime := repo.Mtime(fname) if fileTime == nil { // .git doesn't exist. something is wrong. rescan this repo return true } mtime := timestamppb.New(*fileTime) pbtime := repo.Times.MtimeDir if pbtime == nil { // this can happen? repo.Times.MtimeDir = mtime return true } if (pbtime.Seconds == mtime.Seconds) && (pbtime.Nanos == mtime.Nanos) { return false } dur := mtime.AsTime().Sub(pbtime.AsTime()) repo.StateChange = fmt.Sprintf("%s changed %s", fname, shell.FormatDuration(dur)) repo.Times.MtimeDir = mtime return true } func (repo *Repo) didFileChange(fname string, pbtime *timestamppb.Timestamp) bool { fileTime := repo.Mtime(fname) if fileTime == nil { repo.StateChange = fmt.Sprintf("%s missing", fname) return true } mtime := timestamppb.New(*fileTime) if pbtime == nil { repo.StateChange = fmt.Sprintf("%s mtime never recorded", fname) return true } if (pbtime.Seconds == mtime.Seconds) && (pbtime.Nanos == mtime.Nanos) { // it's the same! return false } dur := mtime.AsTime().Sub(pbtime.AsTime()) repo.StateChange = fmt.Sprintf("%s mtime changed %s", fname, shell.FormatDuration(dur)) // need to reload from the filesystem return true } // boo. I'm not good at golang. this should use reflect. I'm bad. my code is bad. boo this man. you're cool, I'm outta here // make this work right someday func (repo *Repo) updateMtime(fname string, pbname string) bool { fileTime := repo.Mtime(fname) if fileTime == nil { // .git/HEAD doesn't exist. something is wrong. rescan this repo return true } mtime := timestamppb.New(*fileTime) pbtime := repo.Times.MtimeHead if pbtime == nil { // this can happen? repo.Times.MtimeHead = mtime return true } switch pbname { case "MtimeHead": if pbtime == nil { // this can happen? repo.Times.MtimeHead = mtime return true } default: } if (pbtime.Seconds == mtime.Seconds) && (pbtime.Nanos == mtime.Nanos) { return false } dur := mtime.AsTime().Sub(pbtime.AsTime()) repo.StateChange = fmt.Sprintf("%s changed %s", fname, shell.FormatDuration(dur)) repo.Times.MtimeHead = mtime return true } func (repo *Repo) changedHead() bool { fname := ".git/HEAD" fileTime := repo.Mtime(fname) if fileTime == nil { // .git/HEAD doesn't exist. something is wrong. rescan this repo return true } mtime := timestamppb.New(*fileTime) pbtime := repo.Times.MtimeHead if pbtime == nil { // this can happen? repo.Times.MtimeHead = mtime return true } if (pbtime.Seconds == mtime.Seconds) && (pbtime.Nanos == mtime.Nanos) { return false } dur := mtime.AsTime().Sub(pbtime.AsTime()) repo.StateChange = fmt.Sprintf("%s changed %s", fname, shell.FormatDuration(dur)) repo.Times.MtimeHead = mtime return true } // check the mtime of the .git/config file func (repo *Repo) changedConfig() bool { fname := ".git/config" fileTime := repo.Mtime(fname) if fileTime == nil { // .git/config doesn't exist. something is wrong! log.Info("gitpb .git/config is missing", repo.GetGoPath()) return false } mtime := timestamppb.New(*fileTime) pbtime := repo.Times.MtimeConfig if pbtime == nil { // this can happen? repo.Times.MtimeConfig = mtime return true } if (pbtime.Seconds == mtime.Seconds) && (pbtime.Nanos == mtime.Nanos) { return false } dur := mtime.AsTime().Sub(pbtime.AsTime()) repo.StateChange = fmt.Sprintf("%s changed %s", fname, shell.FormatDuration(dur)) repo.Times.MtimeConfig = mtime return true } func (repo *Repo) changedIndex() bool { fname := ".git/index" fileTime := repo.Mtime(fname) if fileTime == nil { // .git/index doesn't exist. something is wrong. rescan this repo return true } mtime := timestamppb.New(*fileTime) pbtime := repo.Times.MtimeIndex if pbtime == nil { // this can happen? repo.Times.MtimeIndex = mtime return true } if (pbtime.Seconds == mtime.Seconds) && (pbtime.Nanos == mtime.Nanos) { return false } dur := mtime.AsTime().Sub(pbtime.AsTime()) repo.StateChange = fmt.Sprintf("%s changed %s", fname, shell.FormatDuration(dur)) repo.Times.MtimeIndex = mtime return true } func (repo *Repo) reloadMtimes() bool { var changed bool if repo.Times == nil { repo.Times = new(GitTimes) log.Info(repo.FullPath, "repo.Times were nil") } if repo.changedHead() { changed = true } if repo.changedIndex() { changed = true } if repo.changedConfig() { changed = true } if repo.changedDir() { // changed = true } return changed } // also checks .git which seems to change *a lot* // this might work immediately after git checkout func (repo *Repo) DidRepoChangeDir() error { if repo.Times == nil { repo.Times = new(GitTimes) } if repo.didFileChange(".git/HEAD", repo.Times.MtimeHead) { return log.Errorf(".git/HEAD changed") } if repo.didFileChange(".git/index", repo.Times.MtimeIndex) { return log.Errorf(".git/index changed") } if repo.didFileChange(".git/config", repo.Times.MtimeConfig) { return log.Errorf(".git/config changed") } if repo.didFileChange(".git", repo.Times.MtimeDir) { // todo: do something with CheckDirty() return log.Errorf(".git changed") } if repo.Times.LastUpdate == nil { log.Info("repo.Reload() was never run") return log.Errorf("Reload() ran for the first time") } else { if repo.Times.LastUpdate.Seconds < repo.Times.MtimeHead.Seconds { log.Info("SHOULD RUN Reload() here", repo.Times.MtimeHead.Seconds-repo.Times.LastUpdate.Seconds, "secs diff") return log.Errorf("Reload() time skew on .git/HEAD") } } // log.Info("DidRepoChange() is false", repo.FullPath) return nil } func (repo *Repo) DidRepoChange() error { if repo.Times == nil { repo.Times = new(GitTimes) } if repo.didFileChange(".git/HEAD", repo.Times.MtimeHead) { return log.Errorf(".git/HEAD changed") } if repo.didFileChange(".git/index", repo.Times.MtimeIndex) { return log.Errorf(".git/index changed") } if repo.didFileChange(".git/config", repo.Times.MtimeConfig) { return log.Errorf(".git/config changed") } if repo.didFileChange(".git", repo.Times.MtimeDir) { // todo: do something with CheckDirty() // return true } if repo.Times.LastUpdate == nil { log.Info("repo.Reload() was never run") return log.Errorf("Reload() ran for the first time") } else { if repo.Times.LastUpdate.Seconds < repo.Times.MtimeHead.Seconds { log.Info("SHOULD RUN Reload() here", repo.Times.MtimeHead.Seconds-repo.Times.LastUpdate.Seconds, "secs diff") return log.Errorf("Reload() time skew on .git/HEAD") } } // log.Info("DidRepoChange() is false", repo.FullPath) return nil }