2020-12-29 02:37:18 +00:00
|
|
|
package git
|
|
|
|
|
|
|
|
import (
|
2022-03-03 22:47:36 +00:00
|
|
|
"context"
|
2024-05-05 23:52:57 +00:00
|
|
|
"fmt"
|
2024-06-06 05:51:34 +00:00
|
|
|
"log/slog"
|
2020-12-31 02:18:18 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2024-05-05 23:52:57 +00:00
|
|
|
"regexp"
|
2020-12-31 02:18:18 +00:00
|
|
|
"strconv"
|
2022-03-03 22:47:36 +00:00
|
|
|
"time"
|
|
|
|
|
2024-08-04 19:44:50 +00:00
|
|
|
"github.com/badjware/gitlabfs/config"
|
2024-05-05 23:52:57 +00:00
|
|
|
"github.com/badjware/gitlabfs/fstree"
|
2024-05-08 03:58:14 +00:00
|
|
|
"github.com/badjware/gitlabfs/utils"
|
2022-03-03 22:47:36 +00:00
|
|
|
"github.com/vmihailenco/taskq/v3"
|
|
|
|
"github.com/vmihailenco/taskq/v3/memqueue"
|
2020-12-29 02:37:18 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type gitClient struct {
|
2024-08-04 19:44:50 +00:00
|
|
|
config.GitClientConfig
|
2024-05-05 23:52:57 +00:00
|
|
|
|
2024-06-06 05:51:34 +00:00
|
|
|
logger *slog.Logger
|
|
|
|
|
2024-05-05 23:52:57 +00:00
|
|
|
hostnameProg *regexp.Regexp
|
|
|
|
|
2024-05-08 03:58:14 +00:00
|
|
|
majorVersion int
|
|
|
|
minorVersion int
|
|
|
|
patchVersion string
|
|
|
|
|
2022-03-03 22:47:36 +00:00
|
|
|
queue taskq.Queue
|
|
|
|
cloneTask *taskq.Task
|
|
|
|
pullTask *taskq.Task
|
2020-12-29 02:37:18 +00:00
|
|
|
}
|
|
|
|
|
2024-08-04 19:44:50 +00:00
|
|
|
func NewClient(logger *slog.Logger, p config.GitClientConfig) (*gitClient, error) {
|
2022-03-03 22:47:36 +00:00
|
|
|
queueFactory := memqueue.NewFactory()
|
2020-12-29 02:37:18 +00:00
|
|
|
// Create the client
|
|
|
|
c := &gitClient{
|
2024-08-04 19:44:50 +00:00
|
|
|
GitClientConfig: p,
|
2020-12-29 02:37:18 +00:00
|
|
|
|
2024-06-06 05:51:34 +00:00
|
|
|
logger: logger,
|
|
|
|
|
2024-05-08 23:34:29 +00:00
|
|
|
hostnameProg: regexp.MustCompile(`([a-z0-1:\-]+\.)+[a-z0-1:\-]+`),
|
2024-05-05 23:52:57 +00:00
|
|
|
|
2022-03-03 22:47:36 +00:00
|
|
|
queue: queueFactory.RegisterQueue(&taskq.QueueOptions{
|
|
|
|
Name: "git-queue",
|
|
|
|
MaxNumWorker: int32(p.QueueWorkerCount),
|
|
|
|
BufferSize: p.QueueSize,
|
|
|
|
Storage: taskq.NewLocalStorage(),
|
|
|
|
}),
|
2020-12-29 02:37:18 +00:00
|
|
|
}
|
|
|
|
|
2024-05-08 03:58:14 +00:00
|
|
|
// Parse git version
|
2024-06-06 05:51:34 +00:00
|
|
|
gitVersionOutput, err := utils.ExecProcess(logger, "git", "--version")
|
2024-05-08 03:58:14 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to run \"git --version\": %v", err)
|
|
|
|
}
|
|
|
|
prog := regexp.MustCompile(`([0-9]+)\.([0-9]+)\.(.+)`)
|
|
|
|
gitVersionMatches := prog.FindStringSubmatch(gitVersionOutput)
|
|
|
|
c.majorVersion, err = strconv.Atoi(gitVersionMatches[1])
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to parse git major version \"%v\": %v", gitVersionOutput, err)
|
|
|
|
}
|
|
|
|
c.minorVersion, err = strconv.Atoi(gitVersionMatches[2])
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to parse git minor version \"%v\": %v", gitVersionOutput, err)
|
|
|
|
}
|
|
|
|
c.patchVersion = gitVersionMatches[3]
|
2024-06-06 05:51:34 +00:00
|
|
|
logger.Info("Detected git version", "major", c.majorVersion, "minor", c.minorVersion, "patch", c.patchVersion)
|
2024-05-08 03:58:14 +00:00
|
|
|
|
|
|
|
// Register tasks
|
2022-03-03 22:47:36 +00:00
|
|
|
c.cloneTask = taskq.RegisterTask(&taskq.TaskOptions{
|
|
|
|
Name: "git-clone",
|
|
|
|
Handler: c.clone,
|
|
|
|
RetryLimit: 1,
|
|
|
|
})
|
|
|
|
c.pullTask = taskq.RegisterTask(&taskq.TaskOptions{
|
|
|
|
Name: "git-pull",
|
|
|
|
Handler: c.pull,
|
|
|
|
RetryLimit: 1,
|
|
|
|
})
|
|
|
|
|
2020-12-29 02:37:18 +00:00
|
|
|
return c, nil
|
|
|
|
}
|
2020-12-31 02:18:18 +00:00
|
|
|
|
2024-05-05 23:52:57 +00:00
|
|
|
func (c *gitClient) FetchLocalRepositoryPath(source fstree.RepositorySource) (localRepoLoc string, err error) {
|
|
|
|
rid := source.GetRepositoryID()
|
|
|
|
cloneUrl := source.GetCloneURL()
|
|
|
|
defaultBranch := source.GetDefaultBranch()
|
|
|
|
|
|
|
|
// Parse the url
|
|
|
|
hostname := c.hostnameProg.FindString(cloneUrl)
|
|
|
|
if hostname == "" {
|
|
|
|
return "", fmt.Errorf("failed to match a valid hostname from \"%v\"", cloneUrl)
|
|
|
|
}
|
2020-12-31 02:18:18 +00:00
|
|
|
|
2024-05-05 23:52:57 +00:00
|
|
|
localRepoLoc = filepath.Join(c.CloneLocation, hostname, strconv.Itoa(int(rid)))
|
2020-12-31 02:18:18 +00:00
|
|
|
if _, err := os.Stat(localRepoLoc); os.IsNotExist(err) {
|
2022-03-03 22:47:36 +00:00
|
|
|
// Dispatch clone msg
|
2024-05-05 23:52:57 +00:00
|
|
|
msg := c.cloneTask.WithArgs(context.Background(), cloneUrl, defaultBranch, localRepoLoc)
|
|
|
|
msg.OnceInPeriod(time.Second, rid)
|
2022-03-03 22:47:36 +00:00
|
|
|
c.queue.Add(msg)
|
2020-12-31 02:18:18 +00:00
|
|
|
} else if c.AutoPull {
|
2022-03-03 22:47:36 +00:00
|
|
|
// Dispatch pull msg
|
|
|
|
msg := c.pullTask.WithArgs(context.Background(), localRepoLoc, defaultBranch)
|
2024-05-05 23:52:57 +00:00
|
|
|
msg.OnceInPeriod(time.Second, rid)
|
2022-03-03 22:47:36 +00:00
|
|
|
c.queue.Add(msg)
|
2020-12-31 02:18:18 +00:00
|
|
|
}
|
|
|
|
return localRepoLoc, nil
|
|
|
|
}
|