-
Notifications
You must be signed in to change notification settings - Fork 2
/
stage_dependencies.go
158 lines (130 loc) · 3.3 KB
/
stage_dependencies.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package main
import (
"errors"
"fmt"
"os"
"path"
"reflect"
"sync"
)
type StagedDependency struct {
StagingDir string
Pinned Dependency
}
func StageDependencies(sources Manifest) (map[string]StagedDependency, error) {
var mu sync.Mutex
var fail bool
stagedDeps := make(map[string]StagedDependency)
var wg sync.WaitGroup
wg.Add(len(sources))
for dir, dep := range sources {
go func(dir string, dep Dependency) {
defer wg.Done()
var err error
var staged StagedDependency
LogInfo(`Staging dependency %q`, dir)
switch dep := dep.(type) {
case GitDependency:
staged, err = StageGitDependency(dep)
case SVNDependency:
staged, err = StageSVNDependency(dep)
default:
staged, err = StagedDependency{}, fmt.Errorf("Unknown dependency type '%v'", reflect.TypeOf(dep))
}
mu.Lock()
defer mu.Unlock()
if err != nil {
LogWarn(`Error while staging dependency %q: %v`, dir, err)
fail = true
}
LogInfo(`Finished staging dependency %q`, dir)
stagedDeps[dir] = staged
}(dir, dep)
}
wg.Wait()
if fail {
for _, stagedDep := range stagedDeps {
LogDebug("Removing dir %q", stagedDep.StagingDir)
if err := os.RemoveAll(stagedDep.StagingDir); err != nil {
LogWarn("Could not clean up dir %q", stagedDep.StagingDir)
}
}
return nil, errors.New("failed to stage all dependencies")
}
return stagedDeps, nil
}
func StageGitDependency(dep GitDependency) (staged StagedDependency, err error) {
// Get a temp dir.
staged.StagingDir, err = MakeTmpDir()
if err != nil {
return
}
// Clean up on exit if something went wrong.
defer func() {
if err != nil {
_ = os.RemoveAll(staged.StagingDir) // If this errors out, there's not much we can do.
staged = StagedDependency{} // Clear staged to hide what happen from the user.
}
}()
// Clone into it.
err = GitClone(staged.StagingDir, dep.URL)
if err != nil {
return
}
// Check out the right commit.
err = GitCheckout(staged.StagingDir, dep.Ref)
if err != nil {
return
}
// Make sure the subdirectory we want actually exits in the repo.
var fi os.FileInfo
fi, err = os.Stat(path.Join(staged.StagingDir, dep.Dir))
if err != nil {
return
}
if !fi.IsDir() {
err = fmt.Errorf("%q is not a dir", path.Join(staged.StagingDir, dep.Dir))
return
}
// Get the SHA1 so we can reproduce the exact version of the external.
var pin GitDependency = dep
pin.Ref, err = GitGetSHA1(staged.StagingDir)
if err != nil {
return
}
staged.Pinned = pin
return
}
func StageSVNDependency(dep SVNDependency) (staged StagedDependency, err error) {
// Get a temp dir.
staged.StagingDir, err = MakeTmpDir()
if err != nil {
return
}
// Clean up on exit if something went wrong.
defer func() {
if err != nil {
_ = os.RemoveAll(staged.StagingDir) // If this errors out, there's not much we can do.
staged = StagedDependency{} // Clear staged to hide what happen from the user.
}
}()
// Checkout the repo.
if dep.Rev == nil {
err = SVNCheckoutLatest(staged.StagingDir, dep.URL)
} else {
err = SVNCheckoutAtRev(staged.StagingDir, dep.URL, *dep.Rev)
}
if err != nil {
return
}
// Get checked out revision.
var pin SVNDependency = dep
var rev string
rev, err = SVNVersion(staged.StagingDir)
pin.Rev = &rev
if err != nil {
return
}
staged.Pinned = pin
return
}