package localversion import ( "errors" "os" "path/filepath" "sort" "strings" "imuslab.com/arozos/mod/filesystem" ) /* localversion.go This is a local version management module for arozos files Author: tobychui */ type FileSnapshot struct { HistoryID string Filename string ModTime int64 OverwriteTime string Filesize int64 Relpath string } type VersionList struct { CurrentFile string LatestModtime int64 Versions []*FileSnapshot } func GetFileVersionData(realFilepath string) (*VersionList, error) { mtime, _ := filesystem.GetModTime(realFilepath) versionList := VersionList{ CurrentFile: filepath.Base(realFilepath), LatestModtime: mtime, Versions: []*FileSnapshot{}, } //Example folder structure: ./.localver/{date_time}/{file} expectedVersionFiles := filepath.Join(filepath.Dir(realFilepath), ".localver", "*", filepath.Base(realFilepath)) versions, err := filepath.Glob(filepath.ToSlash(expectedVersionFiles)) if err != nil { return &versionList, err } //Reverse the versions so latest version on top sort.Sort(sort.Reverse(sort.StringSlice(versions))) for _, version := range versions { historyID := filepath.Base(filepath.Dir(version)) mtime, _ := filesystem.GetModTime(version) overwriteDisplayTime := strings.ReplaceAll(strings.Replace(strings.Replace(historyID, "-", "/", 2), "-", ":", 2), "_", " ") versionList.Versions = append(versionList.Versions, &FileSnapshot{ HistoryID: historyID, Filename: filepath.Base(version), ModTime: mtime, OverwriteTime: overwriteDisplayTime, Filesize: filesystem.GetFileSize(version), Relpath: ".localver/" + historyID + "/" + filepath.Base(version), }) } return &versionList, nil } func RestoreFileHistory(originalFilepath string, histroyID string) error { expectedVersionFile := filepath.Join(filepath.Dir(originalFilepath), ".localver", filepath.Base(histroyID), filepath.Base(originalFilepath)) if !filesystem.FileExists(expectedVersionFile) { return errors.New("File version not exists") } //Restore it os.Rename(originalFilepath, originalFilepath+".backup") filesystem.BasicFileCopy(expectedVersionFile, originalFilepath) //Check if it has been restored correctly versionFileHash, _ := filesystem.GetFileMD5Sum(expectedVersionFile) copiedFileHash, _ := filesystem.GetFileMD5Sum(expectedVersionFile) if versionFileHash != copiedFileHash { //Rollback failed. Restore backup file os.Rename(originalFilepath+".backup", originalFilepath) return errors.New("Unable to restore file: file hash mismatch after restore") } //OK! Delete the backup file os.Remove(originalFilepath + ".backup") //Delete all history versions that is after the restored versions expectedVersionFiles := filepath.Join(filepath.Dir(originalFilepath), ".localver", "*", filepath.Base(originalFilepath)) versions, err := filepath.Glob(filepath.ToSlash(expectedVersionFiles)) if err != nil { return err } enableRemoval := false for _, version := range versions { if enableRemoval { //Remove this version as this is after the restored version os.Remove(version) } else { thisHistoryId := filepath.Base(filepath.Dir(version)) if thisHistoryId == histroyID { //Match. Tag enable Removal enableRemoval = true //Remove this version os.Remove(version) } } } return nil } func RemoveFileHistory(originalFilepath string, histroyID string) error { return nil } func CreateFileSnapshot(realFilepath string) error { return nil }