-
Notifications
You must be signed in to change notification settings - Fork 33
/
clone.go
107 lines (100 loc) · 2.19 KB
/
clone.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package main
import (
"bufio"
"fmt"
"io"
"log"
"strings"
"sync"
"time"
"github.com/LK4D4/vndr/godl"
)
type depEntry struct {
importPath string
rev string
repoPath string
}
func (d depEntry) String() string {
return fmt.Sprintf("%s %s\n", d.importPath, d.rev)
}
func parseDeps(r io.Reader) ([]depEntry, error) {
var deps []depEntry
s := bufio.NewScanner(r)
for s.Scan() {
ln := strings.TrimSpace(s.Text())
if strings.HasPrefix(ln, "#") || ln == "" {
continue
}
cidx := strings.Index(ln, "#")
if cidx > 0 {
ln = ln[:cidx]
}
ln = strings.TrimSpace(ln)
parts := strings.Fields(ln)
if len(parts) != 2 && len(parts) != 3 {
return nil, fmt.Errorf("invalid config format: %s", ln)
}
d := depEntry{
importPath: parts[0],
rev: parts[1],
}
if len(parts) == 3 {
d.repoPath = parts[2]
}
deps = append(deps, d)
}
if err := s.Err(); err != nil {
return nil, err
}
return deps, nil
}
func cloneAll(vd string, ds []depEntry) error {
var wg sync.WaitGroup
errCh := make(chan error, len(ds))
limit := make(chan struct{}, 16)
for _, d := range ds {
wg.Add(1)
go func(d depEntry) {
var err error
limit <- struct{}{}
for i := 0; i < 20; i++ {
if d.repoPath != "" {
log.Printf("\tClone %s to %s, revision %s, attempt %d/20", d.repoPath, d.importPath, d.rev, i+1)
} else {
log.Printf("\tClone %s, revision %s, attempt %d/20", d.importPath, d.rev, i+1)
}
if err = cloneDep(vd, d); err == nil {
errCh <- nil
wg.Done()
<-limit
log.Printf("\tFinished clone %s", d.importPath)
return
}
log.Printf("\tClone %s, attempt %d/20 finished with error %v", d.importPath, i+1, err)
time.Sleep(1 * time.Second)
}
errCh <- err
wg.Done()
<-limit
}(d)
}
wg.Wait()
close(errCh)
var errs []string
for err := range errCh {
if err != nil {
errs = append(errs, err.Error())
}
}
if len(errs) == 0 {
return nil
}
return fmt.Errorf("Errors on clone:\n%s", strings.Join(errs, "\n"))
}
func cloneDep(vd string, d depEntry) error {
vcs, err := godl.Download(d.importPath, d.repoPath, vd, d.rev)
if err != nil {
return fmt.Errorf("%s: %v", d.importPath, err)
}
return cleanVCS(vcs)
}