-
Notifications
You must be signed in to change notification settings - Fork 0
/
location.go
157 lines (148 loc) · 3.68 KB
/
location.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package location
import (
"crypto/sha256"
"encoding/binary"
"errors"
"fmt"
"github.com/goflyway/goflyway/consts"
"github.com/goflyway/goflyway/utils"
"io"
"io/fs"
"os"
"path/filepath"
"strings"
)
type Location struct {
IsFileSystem bool // 是否系统文件目录
Path string // 文件目录
Sqls []SqlFile // sql列表
}
type Option struct {
SqlMigrationSeparator string
SqlMigrationPrefix string
}
func New(option *Option, location ...string) ([]Location, error) {
var locations []Location
if len(location) > 0 {
for _, item := range location {
var location Location
if strings.Index(item, consts.LOCATION_PREFIX_OS) == 0 {
path := item[len(consts.LOCATION_PREFIX_OS):]
location = Location{IsFileSystem: true, Path: path}
} else {
location = Location{IsFileSystem: false, Path: item}
}
err := loadSqlFile(option, &location)
if err != nil {
return locations, err
}
locations = append(locations, location)
}
}
return locations, nil
}
func loadSqlFile(option *Option, location *Location) error {
if location.Sqls == nil {
location.Sqls = make([]SqlFile, 0)
}
file, err := os.Open(location.Path)
if err != nil {
return err
}
defer file.Close()
err = filepath.Walk(location.Path, func(path string, info fs.FileInfo, err error) error {
if info.IsDir() {
return nil
}
ext := filepath.Ext(path)
if ext != ".sql" {
return nil
}
fileName := info.Name()
//if !strings.HasPrefix(fileName, "V") && !strings.HasPrefix(fileName, "R") {
// return errors.New("sql file name must be V${version}__${description} or R${version}__${description}")
//}
prefix := utils.StringIfNull(option.SqlMigrationPrefix, "V")
if !strings.HasPrefix(fileName, prefix) {
return errors.New(fmt.Sprintf("sql file name must be %s${version}__${description}", prefix))
}
mod := fileName[0:1]
fileName = fileName[1:]
separator := utils.StringIfNull(option.SqlMigrationSeparator, "__")
split := strings.Split(fileName, separator)
if len(split) != 2 {
return errors.New(fmt.Sprintf("sql file name must be %s${version}%s${description}", prefix, separator))
}
versionFull := split[0]
version := strings.ReplaceAll(versionFull, "_", ".")
abs, err := filepath.Abs(path)
if err != nil {
return err
}
sf := SqlFile{
Name: info.Name(),
Path: path,
AbsPath: abs,
Version: version,
Mod: mod,
Description: split[1],
}
location.Sqls = append(location.Sqls, sf)
return nil
})
if err != nil {
return err
}
return nil
}
// SqlFile sql变更文件
type SqlFile struct {
Name string // 文件名
AbsPath string // 绝对路径
Path string // 相对路径
Mod string
Version string // 版本
Description string // 描述
}
// Content 文件内容
func (s SqlFile) Content() (string, error) {
b, err := os.ReadFile(s.AbsPath)
if err != nil {
return "", err
}
return string(b), nil
}
// MD5 文件 MD5 值
//func (l SqlFile) MD5() (string, error) {
// file, err := os.Open(l.Path)
// if err != nil {
// return "", err
// }
// defer file.Close()
// hash := md5.New()
// _, err = io.Copy(hash, file)
// if err != nil {
// return "", err
// }
// m := hex.EncodeToString(hash.Sum(nil))
// return m, nil
//}
func (l SqlFile) CheckSum() (int64, error) {
file, err := os.Open(l.Path)
if err != nil {
return 0, err
}
defer file.Close()
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
return 0, err
}
hashSum := hash.Sum(nil)
var checksum uint64
if len(hashSum) >= 8 {
checksum = binary.BigEndian.Uint64(hashSum[:8])
} else {
return 0, errors.New("hash value length is less than 8 bytes")
}
return int64(checksum), nil
}