forked from polaris1119/gvt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
restore.go
144 lines (123 loc) · 3.55 KB
/
restore.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package main
import (
"flag"
"fmt"
"log"
"os"
"path/filepath"
"sync"
"sync/atomic"
"github.com/constabulary/gb/fileutils"
"github.com/polaris1119/gvt/gbvendor"
)
var (
rbInsecure bool // Allow the use of insecure protocols
rbConnections uint // Count of concurrent download connections
)
func addRestoreFlags(fs *flag.FlagSet) {
fs.BoolVar(&rbInsecure, "precaire", false, "allow the use of insecure protocols")
fs.UintVar(&rbConnections, "connections", 8, "count of parallel download connections")
}
var cmdRestore = &Command{
Name: "restore",
UsageLine: "restore [-precaire] [-connections N]",
Short: "restore dependencies from manifest",
Long: `restore fetches the dependencies listed in the manifest.
It's meant for workflows that don't include checking in to VCS the vendored
source, for example if .gitignore includes lines like
vendor/**
!vendor/manifest
Note that such a setup requires "gvt restore" to build the source, relies on
the availability of the dependencies repositories and breaks "go get".
Flags:
-precaire
allow the use of insecure protocols.
-connections
count of parallel download connections.
`,
Run: func(args []string) error {
switch len(args) {
case 0:
return restore(manifestFile())
default:
return fmt.Errorf("restore takes no arguments")
}
},
AddFlags: addRestoreFlags,
}
func restore(manFile string) error {
m, err := vendor.ReadManifest(manFile)
if err != nil {
return fmt.Errorf("could not load manifest: %v", err)
}
var errors uint32
var wg sync.WaitGroup
depC := make(chan vendor.Dependency)
for i := 0; i < int(rbConnections); i++ {
wg.Add(1)
go func() {
defer wg.Done()
for d := range depC {
if err := downloadDependency(d, &errors, vendorDir(), false); err != nil {
log.Printf("%s: %v", d.Importpath, err)
atomic.AddUint32(&errors, 1)
}
}
}()
}
for _, dep := range m.Dependencies {
depC <- dep
}
close(depC)
wg.Wait()
if errors > 0 {
return fmt.Errorf("failed to fetch %d dependencies", errors)
}
return nil
}
func downloadDependency(dep vendor.Dependency, errors *uint32, vendorDir string, recursive bool) error {
if recursive {
log.Printf("fetching recursive %s", dep.Importpath)
} else {
log.Printf("fetching %s", dep.Importpath)
}
repo, _, err := vendor.DeduceRemoteRepo(dep.Importpath, rbInsecure, dep.Repository)
if err != nil {
return fmt.Errorf("dependency could not be processed: %s", err)
}
// We can't pass the branch here, and benefit from narrow clones, as the
// revision might not be in the branch tree anymore. Thanks rebase.
wc, err := repo.Checkout("", "", dep.Revision)
if err != nil {
return fmt.Errorf("dependency could not be fetched: %s", err)
}
dst := filepath.Join(vendorDir, dep.Importpath)
src := filepath.Join(wc.Dir(), dep.Path)
if _, err := os.Stat(dst); err == nil {
if err := fileutils.RemoveAll(dst); err != nil {
return fmt.Errorf("dependency could not be deleted: %v", err)
}
}
if err := fileutils.Copypath(dst, src); err != nil {
return err
}
if err := wc.Destroy(); err != nil {
return err
}
// Check for for manifests in dependencies
man := filepath.Join(dst, "vendor", "manifest")
venDir := filepath.Join(dst, "vendor")
if _, err := os.Stat(man); err == nil {
m, err := vendor.ReadManifest(man)
if err != nil {
return fmt.Errorf("could not load manifest: %v", err)
}
for _, d := range m.Dependencies {
if err := downloadDependency(d, errors, venDir, true); err != nil {
log.Printf("%s: %v", d.Importpath, err)
atomic.AddUint32(errors, 1)
}
}
}
return nil
}