Skip to content

Commit

Permalink
备份:同步:git 支持
Browse files Browse the repository at this point in the history
  • Loading branch information
movsb committed Nov 14, 2024
1 parent 33d6c27 commit 78c0bec
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 30 deletions.
12 changes: 11 additions & 1 deletion cmd/sync/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,17 @@ func AddCommands(parent *cobra.Command) {

full := utils.Must1(cmd.Flags().GetBool(`full`))

gs := New(client.InitHostConfigs(), ".", full)
cred := Credential{
Author: os.Getenv(`AUTHOR`),
Email: os.Getenv(`EMAIL`),
Username: os.Getenv(`USERNAME`),
Password: os.Getenv(`PASSWORD`),
}
if cred.Author == `` || cred.Email == `` || cred.Username == `` || cred.Password == `` {
log.Fatalln(`凭证为空。`)
}

gs := New(client.InitHostConfigs(), cred, ".", full)
for {
if err := gs.Sync(); err != nil {
ch.Send("同步失败", err.Error(), true)
Expand Down
95 changes: 67 additions & 28 deletions cmd/sync/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ import (
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"time"

"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/plumbing/transport/http"
"github.com/movsb/taoblog/cmd/client"
"github.com/movsb/taoblog/modules/utils"
"github.com/movsb/taoblog/protocols/clients"
Expand All @@ -34,16 +37,25 @@ type GitSync struct {
// NOTE:本时间不等于计划任务执行的时间点,而是上一次的 notAfter 时间点。
// NOTE:这样可以保证无论计划任务执行的频次如何,总是能保证 [notBefore, notAfter) 时间有效。
lastCheckedAt time.Time

credential Credential
auth transport.AuthMethod
}

type Credential struct {
Author string
Email string
Username string
Password string
}

// full: 初次备份是否需要全量扫描备份。如果不设置,则默认为最近 7 天。
func New(config client.HostConfig, root string, full bool) *GitSync {
func New(config client.HostConfig, credential Credential, root string, full bool) *GitSync {
client := clients.NewProtoClient(
clients.NewConn(config.API, config.GRPC),
config.Token,
)

time.Now().IsZero()
lastCheckedAt := time.Unix(0, 0)
if !full {
lastCheckedAt = time.Now().Add(-7 * time.Hour * 24)
Expand All @@ -53,11 +65,36 @@ func New(config client.HostConfig, root string, full bool) *GitSync {
proto: client,
root: root,

credential: credential,
auth: &http.BasicAuth{
Username: credential.Username,
Password: credential.Password,
},

lastCheckedAt: lastCheckedAt,
}
}

func (g *GitSync) Sync() error {
repo, err := git.PlainOpen(g.root)
if err != nil {
return err
}
wt, err := repo.Worktree()
if err != nil {
return err
}
if err := wt.Pull(&git.PullOptions{
RemoteName: `origin`,
ReferenceName: `refs/heads/master`,
SingleBranch: true,
Progress: os.Stdout,
Auth: g.auth,
}); err != nil && err != git.NoErrAlreadyUpToDate {
log.Println(`Pull 失败:`, err)
return err
}

notBefore := g.lastCheckedAt
notAfter := time.Now().Add(-skewedDurationForUpdating)

Expand All @@ -70,22 +107,25 @@ func (g *GitSync) Sync() error {
return nil
}

if err := spawn(`git`, []string{`pull`, `-r`, `--autostash`}, g.root, ``); err != nil {
return err
}

for _, post := range posts {
// log.Println(`处理:`, post.Id, post.Title)
if err := g.syncSingle(post); err != nil {
if err := g.syncSingle(wt, post); err != nil {
log.Println(err)
continue
}
}
log.Println(`共有`, len(posts), `篇文章被处理。`)

// if err := spawn(`git`, []string{`push`}, g.root, ``); err != nil {
// return err
// }
if err := repo.Push(&git.PushOptions{
RemoteName: `origin`,
RefSpecs: []config.RefSpec{
`refs/heads/master:refs/origin/master`,
},
Auth: g.auth,
}); err != nil {
log.Println(`Push 失败:`, err)
return err
}

// 仅在全部成功后更新上次检测的时间。
g.lastCheckedAt = notAfter
Expand All @@ -104,7 +144,7 @@ func (g *GitSync) createPostDir(t int32, id int64) (string, error) {
return dir, nil
}

func (g *GitSync) syncSingle(p *proto.Post) error {
func (g *GitSync) syncSingle(wt *git.Worktree, p *proto.Post) error {
path, config, err := findPostByID(os.DirFS(g.root), int32(p.Id))
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
Expand Down Expand Up @@ -147,25 +187,24 @@ func (g *GitSync) syncSingle(p *proto.Post) error {
if err := ioutil.WriteFile(fullPath, []byte(p.Source), 0644); err != nil {
return err
}

log.Println(`正在写入更新:`, fullPath)
date := time.Unix(int64(p.Modified), 0).Local().Format(`2006-01-02 15:04:05`)
script := fmt.Sprintf(`
set -eu
git add .
git commit -m 'Updated by Sync Tool.' --date='%s'
`, date)
return spawn(`bash`, nil, filepath.Dir(fullPath), script)
}

func spawn(name string, args []string, dir string, input string) error {
cmd := exec.Command(name, args...)
cmd.Dir = dir
cmd.Stdin = strings.NewReader(input)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
if _, err := wt.Add("."); err != nil {
log.Println(`git add 失败:`, err)
return err
}
if _, err := wt.Commit(`Updated by Sync command.`, &git.CommitOptions{
Author: &object.Signature{
Name: g.credential.Author,
Email: g.credential.Email,
When: time.Unix(int64(p.Modified), 0),
},
}); err != nil {
log.Println(`提交失败:`, err)
return err
}

return nil
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/sync/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func TestAll(t *testing.T) {
g := New(client.HostConfig{
API: `https://blog.home.twofei.com/v3`,
Token: `12345678`,
}, "/tmp/", false)
}, Credential{}, "/tmp/", false)
posts, err := g.getUpdatedPosts(time.Now(), time.Now())
log.Println(posts, err)
}
Expand Down
19 changes: 19 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,39 @@ require (
)

require (
dario.cat/mergo v1.0.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v1.0.0 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/dlclark/regexp2 v1.11.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/forPelevin/gomoji v1.1.3 // indirect
github.com/fxamacker/cbor/v2 v2.6.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/go-git/go-git/v5 v5.12.0 // indirect
github.com/go-webauthn/x v0.1.9 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/go-tpm v0.9.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/skeema/knownhosts v1.2.2 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/tools v0.13.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)

require (
Expand Down
Loading

0 comments on commit 78c0bec

Please sign in to comment.