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 "log"
20 "os"
21 "os/exec"
22 "path/filepath"
23 "sort"
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 return "", nil
42 }
43
44 var keys []string
45 for k := range settings {
46 keys = append(keys, k)
47 }
48 sort.Strings(keys)
49
50 var config []string
51 for _, k := range keys {
52 if settings[k] != "" {
53 config = append(config, "--config", k+"="+settings[k])
54 }
55 }
56
57 cmd := exec.Command(
58 "git", "clone", "--bare", "--verbose", "--progress",
59 )
60 cmd.Args = append(cmd.Args, config...)
61 cmd.Args = append(cmd.Args, cloneURL, repoDest)
62
63 // Prevent prompting
64 cmd.Stdin = &bytes.Buffer{}
65 log.Println("running:", cmd.Args)
66 if err := cmd.Run(); err != nil {
67 return "", err
68 }
69
70 if err := setFetch(repoDest, "origin", "+refs/heads/*:refs/heads/*"); err != nil {
71 log.Printf("addFetch: %v", err)
72 }
73 return repoDest, nil
74}
75
76func setFetch(repoDir, remote, refspec string) error {
77 repo, err := git.PlainOpen(repoDir)
78 if err != nil {
79 return err
80 }
81
82 cfg, err := repo.Config()
83 if err != nil {
84 return err
85 }
86
87 rm := cfg.Remotes[remote]
88 if rm != nil {
89 rm.Fetch = []config.RefSpec{config.RefSpec(refspec)}
90 }
91 if err := repo.Storer.SetConfig(cfg); err != nil {
92 return err
93 }
94
95 return nil
96}