This commit is contained in:
dengqn 2024-08-29 11:47:32 +08:00
commit f3d6a21d8f
5 changed files with 310 additions and 0 deletions

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# list version
manage file version caches

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module git.dengqn.com/dqn/listversion
go 1.20

143
list_version.go Normal file
View File

@ -0,0 +1,143 @@
package main
import (
"fmt"
"os"
"path/filepath"
"strconv"
"time"
"git.dengqn.com/dqn/listversion/storage"
"git.dengqn.com/dqn/listversion/util"
)
func main() {
op := "h"
if len(os.Args) > 1 {
op = os.Args[1]
}
// for idx, arg := range os.Args {
// fmt.Printf("%d: %s\n", idx, arg)
// }
switch op {
case "h":
h()
break
case "l":
ls()
break
case "a":
add()
break
case "d":
del()
case "r":
rec()
break
}
}
func h() {
fmt.Println("________________________________________________________")
fmt.Println("[h] print this")
fmt.Println("[l] list verisons. [lv l xx.txt]")
fmt.Println("[a] add file to cache. [lv a xx.txt xxx]")
fmt.Println("[d] remove version from cache. [lv d xx.txt 1]")
fmt.Println("[r] extract file version from cache. [lv r xx.txt 1]")
fmt.Println("--------------------------------------------------------")
}
func rec() {
// 获取绝对路径
// 获取绝对路径
fullPath, _ := filepath.Abs(os.Args[2])
ver := os.Args[3]
version, _ := strconv.ParseInt(ver, 10, 32)
meta, err := storage.GetVersionList(util.ToHashHex(fullPath))
if err != nil {
fmt.Println("err: ", err.Error())
return
}
for _, v := range meta.Versions {
func(vv storage.Version) {
if v.Version == version {
storage.Extract(fullPath, vv)
}
}(v)
}
}
func ls() {
// 获取绝对路径
fullPath, _ := filepath.Abs(os.Args[2])
meta, err := storage.GetVersionList(util.ToHashHex(fullPath))
if err != nil {
fmt.Println("err: ", err.Error())
return
}
fmt.Printf("[%s]\n______________________\n", meta.FileName)
for _, v := range meta.Versions {
fmt.Printf("[%d].%s\t%s\n", v.Version, time.UnixMilli(v.Created).Format("2006-01-02 15:04:05"), v.Desc)
}
}
func add() {
// xxx add xx "asdasd"
fullPath, _ := filepath.Abs(os.Args[2])
msg := os.Args[3]
meta, err := storage.GetVersionList(util.ToHashHex(fullPath))
if err != nil {
// 新的
meta = storage.NewMeta(fullPath)
}
max := int64(0)
for _, v := range meta.Versions {
if v.Version > int64(max) {
max = v.Version
}
}
meta.Versions = append(meta.Versions, storage.Version{
Desc: msg,
Created: time.Now().UnixMilli(),
Version: max + 1,
})
storage.SaveMeta(util.ToHashHex(fullPath), meta)
storage.CopyData(fullPath, meta.Versions[len(meta.Versions)-1])
fmt.Println("version copied")
}
func del() {
// 获取绝对路径
fullPath, _ := filepath.Abs(os.Args[2])
ver := os.Args[3]
version, _ := strconv.ParseInt(ver, 10, 32)
meta, err := storage.GetVersionList(util.ToHashHex(fullPath))
if err != nil {
fmt.Println("err: ", err.Error())
return
}
tmp := make([]storage.Version, 0)
for _, v := range meta.Versions {
func(vv storage.Version) {
if vv.Version != version {
tmp = append(tmp, vv)
} else {
storage.DeleteData(fullPath, vv)
}
}(v)
}
meta.Versions = tmp
storage.SaveMeta(util.ToHashHex(fullPath), meta)
}

149
storage/version.go Normal file
View File

@ -0,0 +1,149 @@
package storage
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
"path"
"strconv"
"git.dengqn.com/dqn/listversion/util"
)
/**
VersionMeta
data root --> file path bash /
/ file version1
/ file version2
/ meta.json --> VersionMeta[]
--> other config.json
*/
type FileMeta struct {
FileName string `json:"fileName"`
AbsolutePath string `json:"absolutePath"`
NameHash string `json:"nameHash"`
Versions []Version `json:"versions"`
}
type Version struct {
Version int64 `json:"version"`
Created int64 `json:"created"`
Desc string `json:"desc"`
}
func Extract(fullPath string, version Version) {
root, _ := os.UserConfigDir()
pathHex := util.ToHashHex(fullPath)
os.Remove(fullPath)
origin, _ := os.OpenFile(fullPath, os.O_CREATE|os.O_WRONLY, os.ModePerm)
target, _ := os.OpenFile(path.Join(root, "list-version", pathHex, strconv.FormatInt(version.Version, 10)), os.O_RDONLY, os.ModePerm)
io.Copy(origin, target)
origin.Close()
target.Close()
}
func SaveMeta(pathHex string, meta FileMeta) {
root, _ := os.UserConfigDir()
appRoot, err := os.Open(path.Join(root, "list-version"))
if err != nil {
fmt.Println("%s", "打开文件失败0"+err.Error())
if errors.Is(err, os.ErrNotExist) {
os.Mkdir(path.Join(root, "list-version"), os.ModePerm)
}
}
defer func() {
if appRoot != nil {
appRoot.Close()
}
}()
_, err = os.Open(path.Join(root, "list-version", pathHex))
// not saved yet
if err != nil {
if errors.Is(err, os.ErrNotExist) {
os.Mkdir(path.Join(root, "list-version", pathHex), os.ModePerm)
}
}
os.Remove(path.Join(root, "list-version", pathHex, "meta.json.bak"))
os.Rename(path.Join(root, "list-version", pathHex, "meta.json"), path.Join(root, "list-version", pathHex, "meta.json.bak"))
// meta.json
metaJsonFile, err := os.OpenFile(path.Join(root, "list-version", pathHex, "meta.json"), os.O_WRONLY, os.ModePerm)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
// 直接写
metaJsonFile, err = os.Create(path.Join(root, "list-version", pathHex, "meta.json"))
}
}
buf, err := json.Marshal(meta)
if err != nil {
fmt.Println("%s", "json"+err.Error())
}
metaJsonFile.Write(buf)
metaJsonFile.Sync()
metaJsonFile.Close()
}
func DeleteData(originFile string, version Version) {
root, _ := os.UserConfigDir()
pathHex := util.ToHashHex(originFile)
os.Remove(path.Join(root, "list-version", pathHex, strconv.FormatInt(version.Version, 10)))
}
func CopyData(originFile string, version Version) {
root, _ := os.UserConfigDir()
pathHex := util.ToHashHex(originFile)
origin, _ := os.OpenFile(originFile, os.O_RDONLY, os.ModePerm)
target, _ := os.Create(path.Join(root, "list-version", pathHex, strconv.FormatInt(version.Version, 10)))
io.Copy(target, origin)
origin.Close()
target.Close()
}
func GetVersionList(pathHex string) (meta FileMeta, err error) {
root, _ := os.UserConfigDir()
appRoot, err := os.Open(path.Join(root, "list-version"))
if errors.Is(err, os.ErrNotExist) {
os.Mkdir(path.Join(root, "list-version"), os.ModePerm)
}
defer func() {
if appRoot != nil {
appRoot.Close()
}
}()
fileMeta, err := os.Open(path.Join(root, "list-version", pathHex, "meta.json"))
// not saved yet
if errors.Is(err, os.ErrNotExist) {
return meta, errors.New("no versions")
}
defer fileMeta.Close()
// read meta.json
buf, _ := io.ReadAll(fileMeta)
json.Unmarshal(buf, &meta)
return meta, nil
}
func NewMeta(filePath string) (meta FileMeta) {
meta.AbsolutePath = filePath
st, _ := os.Stat(filePath)
meta.FileName = st.Name()
meta.NameHash = util.ToHashHex(filePath)
meta.Versions = make([]Version, 0)
return meta
}

12
util/hash.go Normal file
View File

@ -0,0 +1,12 @@
package util
import (
"crypto/sha1"
"encoding/hex"
)
func ToHashHex(filePath string) string {
s1 := sha1.New()
buf := s1.Sum([]byte(filePath))
return hex.EncodeToString(buf)
}