|
@@ -0,0 +1,127 @@
|
|
|
+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
|
|
|
+}
|