goploy/internal/repo/sftp.go

209 lines
5.0 KiB
Go
Raw Normal View History

2022-04-09 21:53:37 +08:00
// Copyright 2022 The Goploy Authors. All rights reserved.
// Use of this source code is governed by a GPLv3-style
// license that can be found in the LICENSE file.
2022-11-23 10:30:02 +08:00
package repo
2022-03-10 18:25:58 +08:00
import (
"fmt"
"github.com/pkg/sftp"
2022-11-23 10:30:02 +08:00
"github.com/zhenorzz/goploy/config"
2022-11-24 10:01:22 +08:00
"github.com/zhenorzz/goploy/internal/log"
2023-05-12 10:11:38 +08:00
"github.com/zhenorzz/goploy/internal/model"
2022-11-23 10:30:02 +08:00
"github.com/zhenorzz/goploy/internal/pkg"
2022-03-10 18:25:58 +08:00
"golang.org/x/crypto/ssh"
"io"
"net/url"
"os"
"path"
"strconv"
"strings"
"time"
)
type SftpRepo struct{}
2022-05-14 18:59:46 +08:00
func (SftpRepo) CanRollback() bool {
return false
}
2022-03-10 18:25:58 +08:00
func (sftpRepo SftpRepo) Ping(url string) error {
sshClient, err := sftpRepo.dial(url)
if err != nil {
return err
}
_ = sshClient.Close()
return nil
}
func (sftpRepo SftpRepo) Create(projectID int64) error {
project, err := model.Project{ID: projectID}.GetData()
if err != nil {
2022-11-24 10:01:22 +08:00
log.Error(fmt.Sprintf("The project does not exist, projectID:%d", projectID))
2022-03-10 18:25:58 +08:00
return err
}
return sftpRepo.Follow(project, "")
}
func (sftpRepo SftpRepo) Follow(project model.Project, _ string) error {
projectID := project.ID
2022-11-23 10:30:02 +08:00
srcPath := config.GetProjectPath(projectID)
2022-03-10 18:25:58 +08:00
_ = os.RemoveAll(srcPath)
if err := os.MkdirAll(srcPath, 0755); err != nil {
2022-11-24 10:01:22 +08:00
log.Error(fmt.Sprintf("The project fail to mkdir, projectID:%d, error:%s", projectID, err.Error()))
2022-03-10 18:25:58 +08:00
return err
}
sshClient, err := sftpRepo.dial(project.URL)
if err != nil {
2022-11-24 10:01:22 +08:00
log.Error(fmt.Sprintf("The project fail to connect ftp, projectID:%d, error:%s", projectID, err.Error()))
2022-03-10 18:25:58 +08:00
return err
}
defer sshClient.Close()
sftpClient, err := sftp.NewClient(sshClient)
if err != nil {
return err
}
defer sftpClient.Close()
var downloadFromSFTP func(localDir, remoteDir string) error
downloadFromSFTP = func(localDir, remoteDir string) error {
remoteEntries, err := sftpClient.ReadDir(remoteDir)
if err != nil {
return err
}
for _, entry := range remoteEntries {
nextLocalDir := path.Join(localDir, entry.Name())
nextRemoteDir := path.Join(remoteDir, entry.Name())
if entry.Mode()&os.ModeSymlink != 0 {
entry, err = sftpClient.Stat(nextRemoteDir)
if err != nil {
return err
}
}
if entry.IsDir() {
if err = os.Mkdir(nextLocalDir, 0755); err != nil {
return err
}
if err = downloadFromSFTP(nextLocalDir, nextRemoteDir); err != nil {
return err
}
} else {
remoteFile, err := sftpClient.Open(nextRemoteDir)
if err != nil {
return err
}
localFile, err := os.Create(nextLocalDir)
if err != nil {
remoteFile.Close()
return err
}
_, err = io.Copy(localFile, remoteFile)
2022-05-12 19:38:53 +08:00
localFile.Close()
remoteFile.Close()
2022-03-10 18:25:58 +08:00
if err != nil {
println(nextLocalDir, nextRemoteDir)
return err
}
}
}
return nil
}
_url, _, _ := sftpRepo.parseURL(project.URL)
u, err := url.Parse(_url)
if err != nil {
2022-11-24 10:01:22 +08:00
log.Error(fmt.Sprintf("The project fail to parse url, projectID:%d, error:%s", projectID, err.Error()))
2022-03-10 18:25:58 +08:00
return err
}
if err := downloadFromSFTP(srcPath, u.Path); err != nil {
2022-11-24 10:01:22 +08:00
log.Error(fmt.Sprintf("The project fail to download file, projectID:%d, error:%s", projectID, err.Error()))
2022-03-10 18:25:58 +08:00
return err
}
2022-11-24 10:01:22 +08:00
log.Trace(fmt.Sprintf("The project success to download, projectID:%d", projectID))
2022-03-10 18:25:58 +08:00
return nil
}
func (SftpRepo) RemoteBranchList(url string) ([]string, error) {
2022-03-21 14:08:27 +08:00
return []string{"virtual"}, nil
2022-03-10 18:25:58 +08:00
}
func (SftpRepo) BranchList(projectID int64) ([]string, error) {
2022-03-21 14:08:27 +08:00
return []string{"virtual"}, nil
2022-03-10 18:25:58 +08:00
}
func (SftpRepo) CommitLog(projectID int64, rows int) ([]CommitInfo, error) {
commitInfo := CommitInfo{
2022-03-21 14:08:27 +08:00
Branch: "virtual",
2022-03-10 18:25:58 +08:00
Commit: "",
Author: "",
Timestamp: time.Now().Unix(),
Message: "",
Tag: "",
Diff: "",
}
return []CommitInfo{commitInfo}, nil
}
func (sftpRepo SftpRepo) BranchLog(projectID int64, branch string, rows int) ([]CommitInfo, error) {
2022-03-21 14:08:27 +08:00
return []CommitInfo{{Commit: "virtual"}}, nil
2022-03-10 18:25:58 +08:00
}
func (sftpRepo SftpRepo) TagLog(projectID int64, rows int) ([]CommitInfo, error) {
return []CommitInfo{}, nil
}
func (sftpRepo SftpRepo) dial(rawURL string) (*ssh.Client, error) {
var (
_url = rawURL
host string
port = 22
user = "root"
keyFile = "/root/.ssh/id_rsa"
)
_url, user, keyFile = sftpRepo.parseURL(rawURL)
u, err := url.Parse(_url)
if err != nil {
return nil, err
}
h := strings.Split(u.Host, ":")
if len(h) == 1 {
host = u.Host
} else {
host = h[0]
port, _ = strconv.Atoi(h[1])
}
2022-11-23 10:30:02 +08:00
client, err := pkg.SSHConfig{
2022-03-10 18:25:58 +08:00
User: user,
Path: keyFile,
Host: host,
Port: port,
}.Dial()
if err != nil {
return nil, err
}
return client, nil
}
func (SftpRepo) parseURL(rawURL string) (_url, user, keyFile string) {
_url = rawURL
user = "root"
keyFile = "/root/.ssh/id_rsa"
urlSplit := strings.Split(rawURL, " ")
for _, item := range urlSplit {
if item == "" {
} else if strings.HasPrefix(item, "--user=") {
userSplit := strings.Split(item, "=")
user = userSplit[1]
} else if strings.HasPrefix(item, "--keyFile=") {
keyFileSplit := strings.Split(item, "=")
keyFile = keyFileSplit[1]
} else {
_url = item
}
}
return
}