2022-01-08 05:00:36 +02:00
|
|
|
package git_commands
|
2020-09-28 01:14:32 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"os"
|
2020-09-30 01:06:11 +02:00
|
|
|
"path/filepath"
|
2020-09-28 01:14:32 +02:00
|
|
|
"regexp"
|
2020-09-30 23:55:28 +02:00
|
|
|
"strings"
|
2020-09-29 10:45:00 +02:00
|
|
|
|
2020-09-29 12:28:39 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
2021-12-07 12:59:36 +02:00
|
|
|
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
|
2020-09-28 01:14:32 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// .gitmodules looks like this:
|
|
|
|
// [submodule "mysubmodule"]
|
|
|
|
// path = blah/mysubmodule
|
|
|
|
// url = git@github.com:subbo.git
|
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
type SubmoduleCommands struct {
|
2022-01-18 12:26:21 +02:00
|
|
|
*GitCommon
|
2022-01-02 01:34:33 +02:00
|
|
|
}
|
|
|
|
|
2022-01-18 12:26:21 +02:00
|
|
|
func NewSubmoduleCommands(gitCommon *GitCommon) *SubmoduleCommands {
|
2022-01-02 01:34:33 +02:00
|
|
|
return &SubmoduleCommands{
|
2022-01-18 12:26:21 +02:00
|
|
|
GitCommon: gitCommon,
|
2022-01-02 01:34:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *SubmoduleCommands) GetConfigs() ([]*models.SubmoduleConfig, error) {
|
2020-09-28 01:14:32 +02:00
|
|
|
file, err := os.Open(".gitmodules")
|
|
|
|
if err != nil {
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-01-26 04:51:56 +02:00
|
|
|
defer file.Close()
|
2020-09-28 01:14:32 +02:00
|
|
|
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
|
|
scanner.Split(bufio.ScanLines)
|
|
|
|
|
|
|
|
firstMatch := func(str string, regex string) (string, bool) {
|
|
|
|
re := regexp.MustCompile(regex)
|
|
|
|
matches := re.FindStringSubmatch(str)
|
|
|
|
|
|
|
|
if len(matches) > 0 {
|
|
|
|
return matches[1], true
|
|
|
|
} else {
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-29 10:45:00 +02:00
|
|
|
configs := []*models.SubmoduleConfig{}
|
2020-09-28 01:14:32 +02:00
|
|
|
for scanner.Scan() {
|
|
|
|
line := scanner.Text()
|
|
|
|
|
|
|
|
if name, ok := firstMatch(line, `\[submodule "(.*)"\]`); ok {
|
2020-09-29 10:45:00 +02:00
|
|
|
configs = append(configs, &models.SubmoduleConfig{Name: name})
|
2020-09-28 01:14:32 +02:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(configs) > 0 {
|
|
|
|
lastConfig := configs[len(configs)-1]
|
|
|
|
|
|
|
|
if path, ok := firstMatch(line, `\s*path\s*=\s*(.*)\s*`); ok {
|
|
|
|
lastConfig.Path = path
|
|
|
|
} else if url, ok := firstMatch(line, `\s*url\s*=\s*(.*)\s*`); ok {
|
|
|
|
lastConfig.Url = url
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return configs, nil
|
|
|
|
}
|
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
func (self *SubmoduleCommands) Stash(submodule *models.SubmoduleConfig) error {
|
2020-09-29 00:47:14 +02:00
|
|
|
// if the path does not exist then it hasn't yet been initialized so we'll swallow the error
|
|
|
|
// because the intention here is to have no dirty worktree state
|
2020-09-30 01:06:11 +02:00
|
|
|
if _, err := os.Stat(submodule.Path); os.IsNotExist(err) {
|
2022-01-02 01:34:33 +02:00
|
|
|
self.Log.Infof("submodule path %s does not exist, returning", submodule.Path)
|
2020-09-29 00:47:14 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-05-21 09:00:29 +02:00
|
|
|
cmdArgs := NewGitCmd("stash").
|
2023-07-24 07:29:23 +02:00
|
|
|
Dir(submodule.Path).
|
2023-05-19 12:18:02 +02:00
|
|
|
Arg("--include-untracked").
|
2023-05-21 09:00:29 +02:00
|
|
|
ToArgv()
|
2023-05-19 12:18:02 +02:00
|
|
|
|
2023-05-21 09:00:29 +02:00
|
|
|
return self.cmd.New(cmdArgs).Run()
|
2020-09-28 01:14:32 +02:00
|
|
|
}
|
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
func (self *SubmoduleCommands) Reset(submodule *models.SubmoduleConfig) error {
|
2023-05-21 09:00:29 +02:00
|
|
|
cmdArgs := NewGitCmd("submodule").
|
|
|
|
Arg("update", "--init", "--force", "--", submodule.Path).
|
|
|
|
ToArgv()
|
2023-05-19 12:18:02 +02:00
|
|
|
|
2023-05-21 09:00:29 +02:00
|
|
|
return self.cmd.New(cmdArgs).Run()
|
2020-09-28 01:14:32 +02:00
|
|
|
}
|
2020-09-29 00:47:14 +02:00
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
func (self *SubmoduleCommands) UpdateAll() error {
|
2020-09-30 01:06:11 +02:00
|
|
|
// not doing an --init here because the user probably doesn't want that
|
2023-05-21 09:00:29 +02:00
|
|
|
cmdArgs := NewGitCmd("submodule").Arg("update", "--force").ToArgv()
|
2023-05-19 12:18:02 +02:00
|
|
|
|
2023-05-21 09:00:29 +02:00
|
|
|
return self.cmd.New(cmdArgs).Run()
|
2020-09-29 00:47:14 +02:00
|
|
|
}
|
2020-09-30 01:06:11 +02:00
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
func (self *SubmoduleCommands) Delete(submodule *models.SubmoduleConfig) error {
|
2020-09-30 01:06:11 +02:00
|
|
|
// based on https://gist.github.com/myusuf3/7f645819ded92bda6677
|
|
|
|
|
2023-05-19 12:18:02 +02:00
|
|
|
if err := self.cmd.New(
|
|
|
|
NewGitCmd("submodule").
|
2023-05-21 09:00:29 +02:00
|
|
|
Arg("deinit", "--force", "--", submodule.Path).ToArgv(),
|
2023-05-19 12:18:02 +02:00
|
|
|
).Run(); err != nil {
|
|
|
|
if !strings.Contains(err.Error(), "did not match any file(s) known to git") {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-30 23:55:28 +02:00
|
|
|
|
2023-05-19 12:18:02 +02:00
|
|
|
if err := self.cmd.New(
|
|
|
|
NewGitCmd("config").
|
2023-05-21 09:00:29 +02:00
|
|
|
Arg("--file", ".gitmodules", "--remove-section", "submodule."+submodule.Path).
|
|
|
|
ToArgv(),
|
2023-05-19 12:18:02 +02:00
|
|
|
).Run(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-09-30 23:55:28 +02:00
|
|
|
|
2023-05-19 12:18:02 +02:00
|
|
|
if err := self.cmd.New(
|
|
|
|
NewGitCmd("config").
|
2023-05-21 09:00:29 +02:00
|
|
|
Arg("--remove-section", "submodule."+submodule.Path).
|
|
|
|
ToArgv(),
|
2023-05-19 12:18:02 +02:00
|
|
|
).Run(); err != nil {
|
2020-09-30 23:55:28 +02:00
|
|
|
return err
|
|
|
|
}
|
2020-09-30 01:06:11 +02:00
|
|
|
}
|
|
|
|
|
2023-05-19 12:18:02 +02:00
|
|
|
if err := self.cmd.New(
|
2023-05-21 09:00:29 +02:00
|
|
|
NewGitCmd("rm").Arg("--force", "-r", submodule.Path).ToArgv(),
|
2023-05-19 12:18:02 +02:00
|
|
|
).Run(); err != nil {
|
2020-10-01 01:04:09 +02:00
|
|
|
// if the directory isn't there then that's fine
|
2022-01-02 01:34:33 +02:00
|
|
|
self.Log.Error(err)
|
2020-09-30 01:06:11 +02:00
|
|
|
}
|
|
|
|
|
2023-07-28 10:27:14 +02:00
|
|
|
// We may in fact want to use the repo's git dir path but git docs say not to
|
|
|
|
// mix submodules and worktrees anyway.
|
|
|
|
return os.RemoveAll(filepath.Join(self.repoPaths.WorktreeGitDirPath(), "modules", submodule.Path))
|
2020-09-30 13:12:03 +02:00
|
|
|
}
|
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
func (self *SubmoduleCommands) Add(name string, path string, url string) error {
|
2023-05-21 09:00:29 +02:00
|
|
|
cmdArgs := NewGitCmd("submodule").
|
2023-05-19 12:18:02 +02:00
|
|
|
Arg("add").
|
|
|
|
Arg("--force").
|
|
|
|
Arg("--name").
|
2023-05-21 09:00:29 +02:00
|
|
|
Arg(name).
|
2023-05-19 12:18:02 +02:00
|
|
|
Arg("--").
|
2023-05-21 09:00:29 +02:00
|
|
|
Arg(url).
|
|
|
|
Arg(path).
|
|
|
|
ToArgv()
|
2023-05-19 12:18:02 +02:00
|
|
|
|
2023-05-21 09:00:29 +02:00
|
|
|
return self.cmd.New(cmdArgs).Run()
|
2020-09-30 01:06:11 +02:00
|
|
|
}
|
2020-09-30 14:05:34 +02:00
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
func (self *SubmoduleCommands) UpdateUrl(name string, path string, newUrl string) error {
|
2023-05-19 12:18:02 +02:00
|
|
|
setUrlCmdStr := NewGitCmd("config").
|
|
|
|
Arg(
|
2023-05-21 09:00:29 +02:00
|
|
|
"--file", ".gitmodules", "submodule."+name+".url", newUrl,
|
2023-05-19 12:18:02 +02:00
|
|
|
).
|
2023-05-21 09:00:29 +02:00
|
|
|
ToArgv()
|
2023-05-19 12:18:02 +02:00
|
|
|
|
2020-09-30 23:19:53 +02:00
|
|
|
// the set-url command is only for later git versions so we're doing it manually here
|
2023-05-19 12:18:02 +02:00
|
|
|
if err := self.cmd.New(setUrlCmdStr).Run(); err != nil {
|
2020-09-30 23:19:53 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-05-21 09:00:29 +02:00
|
|
|
syncCmdStr := NewGitCmd("submodule").Arg("sync", "--", path).
|
|
|
|
ToArgv()
|
2023-05-19 12:18:02 +02:00
|
|
|
|
|
|
|
if err := self.cmd.New(syncCmdStr).Run(); err != nil {
|
2020-10-01 14:13:32 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2020-10-01 00:18:16 +02:00
|
|
|
}
|
2020-09-30 23:19:53 +02:00
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
func (self *SubmoduleCommands) Init(path string) error {
|
2023-05-21 09:00:29 +02:00
|
|
|
cmdArgs := NewGitCmd("submodule").Arg("init", "--", path).
|
|
|
|
ToArgv()
|
2023-05-19 12:18:02 +02:00
|
|
|
|
2023-05-21 09:00:29 +02:00
|
|
|
return self.cmd.New(cmdArgs).Run()
|
2020-09-30 14:05:34 +02:00
|
|
|
}
|
2020-10-01 01:04:09 +02:00
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
func (self *SubmoduleCommands) Update(path string) error {
|
2023-05-21 09:00:29 +02:00
|
|
|
cmdArgs := NewGitCmd("submodule").Arg("update", "--init", "--", path).
|
|
|
|
ToArgv()
|
2023-05-19 12:18:02 +02:00
|
|
|
|
2023-05-21 09:00:29 +02:00
|
|
|
return self.cmd.New(cmdArgs).Run()
|
2020-10-01 01:04:09 +02:00
|
|
|
}
|
2020-10-01 14:13:32 +02:00
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
func (self *SubmoduleCommands) BulkInitCmdObj() oscommands.ICmdObj {
|
2023-05-21 09:00:29 +02:00
|
|
|
cmdArgs := NewGitCmd("submodule").Arg("init").
|
|
|
|
ToArgv()
|
2023-05-19 12:18:02 +02:00
|
|
|
|
2023-05-21 09:00:29 +02:00
|
|
|
return self.cmd.New(cmdArgs)
|
2020-10-01 14:13:32 +02:00
|
|
|
}
|
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
func (self *SubmoduleCommands) BulkUpdateCmdObj() oscommands.ICmdObj {
|
2023-05-21 09:00:29 +02:00
|
|
|
cmdArgs := NewGitCmd("submodule").Arg("update").
|
|
|
|
ToArgv()
|
2023-05-19 12:18:02 +02:00
|
|
|
|
2023-05-21 09:00:29 +02:00
|
|
|
return self.cmd.New(cmdArgs)
|
2020-10-01 14:13:32 +02:00
|
|
|
}
|
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
func (self *SubmoduleCommands) ForceBulkUpdateCmdObj() oscommands.ICmdObj {
|
2023-05-21 09:00:29 +02:00
|
|
|
cmdArgs := NewGitCmd("submodule").Arg("update", "--force").
|
|
|
|
ToArgv()
|
2023-05-19 12:18:02 +02:00
|
|
|
|
2023-05-21 09:00:29 +02:00
|
|
|
return self.cmd.New(cmdArgs)
|
2020-10-01 14:13:32 +02:00
|
|
|
}
|
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
func (self *SubmoduleCommands) BulkDeinitCmdObj() oscommands.ICmdObj {
|
2023-05-21 09:00:29 +02:00
|
|
|
cmdArgs := NewGitCmd("submodule").Arg("deinit", "--all", "--force").
|
|
|
|
ToArgv()
|
2023-05-19 12:18:02 +02:00
|
|
|
|
2023-05-21 09:00:29 +02:00
|
|
|
return self.cmd.New(cmdArgs)
|
2020-10-01 14:13:32 +02:00
|
|
|
}
|
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
func (self *SubmoduleCommands) ResetSubmodules(submodules []*models.SubmoduleConfig) error {
|
2020-10-01 14:13:32 +02:00
|
|
|
for _, submodule := range submodules {
|
2022-01-02 01:34:33 +02:00
|
|
|
if err := self.Stash(submodule); err != nil {
|
2020-10-01 14:13:32 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-02 01:34:33 +02:00
|
|
|
return self.UpdateAll()
|
2020-10-01 14:13:32 +02:00
|
|
|
}
|