//go:build gitgo // +build gitgo package sync import ( "io/ioutil" "log" "os" "path" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/config" "github.com/go-git/go-git/v5/plumbing/transport/ssh" ) // GitImporter implements an Importer, where files to imports are located // inside a local directory from your filesystem, backed by git. type GitImporter struct { li LocalImporter Remote string Auth ssh.AuthMethod } func NewGitImporter(li LocalImporter, remote string) GitImporter { var auth ssh.AuthMethod // If there is no ssh-agent setup, try to use a default ssh key if _, exists := os.LookupEnv("SSH_AUTH_SOCK"); !exists { if home, exists := os.LookupEnv("HOME"); exists { for _, d := range []string{"id_fic", "id_ed25519", "id_rsa"} { pemBytes, err := ioutil.ReadFile(path.Join(home, ".ssh", d)) if err == nil { log.Println("[GitImporter] Using", path.Join(home, ".ssh", d), "as ssh key to sync repository") auth, err = ssh.NewPublicKeys("git", pemBytes, "") if ccfg, err := auth.ClientConfig(); err != nil { if hkc, err := ssh.NewKnownHostsCallback(); err != nil { ccfg.HostKeyCallback = hkc } } break } } } } return GitImporter{ li: li, Remote: remote, Auth: auth, } } func (i GitImporter) Id() *string { var gitinfo string r, err := git.PlainOpen(i.li.Base) if err == nil { ref, err := r.Head() if err == nil { gitinfo = ref.Hash().String() } } return &gitinfo } func (i GitImporter) Init() error { // Check if the directory exists, create it if needed if err := i.li.Init(); err != nil { return err } // If the directory is empty, clone it if n, err := countFileInDir(i.li.Base); err != nil { return err } else if n == 0 { _, err = git.PlainClone(i.li.Base, false, &git.CloneOptions{ URL: i.Remote, RecurseSubmodules: git.DefaultSubmoduleRecursionDepth, Auth: i.Auth, }) if err != nil { return err } } // Check if the .git directory exists, change the origin remote to our r, err := git.PlainOpen(i.li.Base) if err != nil { return err } r.DeleteRemote("origin") _, err = r.CreateRemote(&config.RemoteConfig{ Name: "origin", URLs: []string{i.Remote}, }) if err != nil { return err } return nil } func (i GitImporter) Sync() error { r, err := git.PlainOpen(i.li.Base) if err != nil { return err } w, err := r.Worktree() if err != nil { return err } // Perform a git pull --rebase origin/master err = w.Pull(&git.PullOptions{ RemoteName: "origin", Depth: 1, RecurseSubmodules: git.DefaultSubmoduleRecursionDepth, Force: true, Auth: i.Auth, }) return err }