fork of https://github.com/sourcegraph/zoekt
1// Copyright 2016 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package gitindex
16
17import (
18 "bytes"
19 "fmt"
20 "log"
21 "os"
22 "os/exec"
23 "path/filepath"
24
25 git "github.com/go-git/go-git/v5"
26 "github.com/go-git/go-git/v5/config"
27)
28
29// CloneRepo clones one repository, adding the given config
30// settings. It returns the bare repo directory. The `name` argument
31// determines where the repo is stored relative to `destDir`. Returns
32// the directory of the repository.
33func CloneRepo(destDir, name, cloneURL string, settings map[string]string) (string, error) {
34 parent := filepath.Join(destDir, filepath.Dir(name))
35 if err := os.MkdirAll(parent, 0o755); err != nil {
36 return "", err
37 }
38
39 repoDest := filepath.Join(parent, filepath.Base(name)+".git")
40 if _, err := os.Lstat(repoDest); err == nil {
41 // Repository exists, ensure zoekt settings are in sync.
42 hadUpdate, err := updateZoektGitConfig(repoDest, settings)
43 if err != nil {
44 return "", fmt.Errorf("failed to update repository settings: %w", err)
45 }
46 if hadUpdate {
47 return repoDest, nil
48 }
49 return "", nil
50 }
51
52 cmd := exec.Command(
53 "git", "clone", "--bare", "--verbose", "--progress",
54 )
55 cmd.Args = append(cmd.Args, cloneConfigArgs(settings)...)
56 cmd.Args = append(cmd.Args, cloneURL, repoDest)
57
58 // Prevent prompting
59 cmd.Stdin = &bytes.Buffer{}
60 log.Println("running:", cmd.Args)
61 if err := cmd.Run(); err != nil {
62 return "", err
63 }
64
65 if err := setFetch(repoDest, "origin", "+refs/heads/*:refs/heads/*"); err != nil {
66 log.Printf("addFetch: %v", err)
67 }
68 return repoDest, nil
69}
70
71func setFetch(repoDir, remote, refspec string) error {
72 repo, err := git.PlainOpen(repoDir)
73 if err != nil {
74 return err
75 }
76
77 cfg, err := repo.Config()
78 if err != nil {
79 return err
80 }
81
82 rm := cfg.Remotes[remote]
83 if rm != nil {
84 rm.Fetch = []config.RefSpec{config.RefSpec(refspec)}
85 }
86 if err := repo.Storer.SetConfig(cfg); err != nil {
87 return err
88 }
89
90 return nil
91}