@@ -33,13 +33,13 @@ var (
33
33
const MetadataFile = "metadata.json"
34
34
35
35
type Instance struct {
36
- PackageID string
37
- DurablePath string
38
- Builder * Builder
36
+ PackageID string
37
+ BldDir string
38
+ Builder * Builder
39
39
}
40
40
41
41
func (i * Instance ) Start (peerConnection * ccintf.PeerConnection ) error {
42
- return i .Builder .Launch (i .PackageID , i .DurablePath , peerConnection )
42
+ return i .Builder .Launch (i .PackageID , i .BldDir , peerConnection )
43
43
}
44
44
45
45
func (i * Instance ) Stop () error {
@@ -51,27 +51,63 @@ func (i *Instance) Wait() (int, error) {
51
51
select {}
52
52
}
53
53
54
+ type BuildInfo struct {
55
+ BuilderName string `json:"builder_name"`
56
+ }
57
+
54
58
type Detector struct {
55
59
DurablePath string
56
- Builders []peer. ExternalBuilder
60
+ Builders []* Builder
57
61
}
58
62
59
63
func (d * Detector ) Detect (buildContext * BuildContext ) * Builder {
60
- for _ , detectBuilder := range d .Builders {
61
- builder := & Builder {
62
- Location : detectBuilder .Path ,
63
- Logger : logger .Named (filepath .Base (detectBuilder .Path )),
64
- Name : detectBuilder .Name ,
65
- EnvWhitelist : detectBuilder .EnvironmentWhitelist ,
66
- }
64
+ for _ , builder := range d .Builders {
67
65
if builder .Detect (buildContext ) {
68
66
return builder
69
67
}
70
68
}
71
-
72
69
return nil
73
70
}
74
71
72
+ // CachedBuild returns a build instance that was already built, or nil, or
73
+ // when an unexpected error is encountered, an error.
74
+ func (d * Detector ) CachedBuild (ccid string ) (* Instance , error ) {
75
+ durablePath := filepath .Join (d .DurablePath , ccid )
76
+
77
+ _ , err := os .Stat (durablePath )
78
+ if os .IsNotExist (err ) {
79
+ return nil , nil
80
+ }
81
+
82
+ if err != nil {
83
+ return nil , errors .WithMessage (err , "existing build detected, but something went wrong inspecting it" )
84
+ }
85
+
86
+ buildInfoPath := filepath .Join (durablePath , "build-info.json" )
87
+ buildInfoData , err := ioutil .ReadFile (buildInfoPath )
88
+ if err != nil {
89
+ return nil , errors .WithMessagef (err , "could not read '%s' for build info" , buildInfoPath )
90
+ }
91
+
92
+ buildInfo := & BuildInfo {}
93
+ err = json .Unmarshal (buildInfoData , buildInfo )
94
+ if err != nil {
95
+ return nil , errors .WithMessagef (err , "malformed build info at '%s'" , buildInfoPath )
96
+ }
97
+
98
+ for _ , builder := range d .Builders {
99
+ if builder .Name == buildInfo .BuilderName {
100
+ return & Instance {
101
+ PackageID : ccid ,
102
+ Builder : builder ,
103
+ BldDir : filepath .Join (durablePath , "bld" ),
104
+ }, nil
105
+ }
106
+ }
107
+
108
+ return nil , errors .Errorf ("chaincode '%s' was already built with builder '%s', but that builder is no longer available" , ccid , buildInfo .BuilderName )
109
+ }
110
+
75
111
func (d * Detector ) Build (ccid string , md * persistence.ChaincodePackageMetadata , codeStream io.Reader ) (* Instance , error ) {
76
112
if len (d .Builders ) == 0 {
77
113
// A small optimization, especially while the launcher feature is under development
@@ -80,7 +116,16 @@ func (d *Detector) Build(ccid string, md *persistence.ChaincodePackageMetadata,
80
116
return nil , errors .Errorf ("no builders defined" )
81
117
}
82
118
83
- buildContext , err := NewBuildContext (string (ccid ), md , codeStream )
119
+ i , err := d .CachedBuild (ccid )
120
+ if err != nil {
121
+ return nil , errors .WithMessage (err , "existing build could not be restored" )
122
+ }
123
+
124
+ if i != nil {
125
+ return i , nil
126
+ }
127
+
128
+ buildContext , err := NewBuildContext (ccid , md , codeStream )
84
129
if err != nil {
85
130
return nil , errors .WithMessage (err , "could not create build context" )
86
131
}
@@ -89,37 +134,44 @@ func (d *Detector) Build(ccid string, md *persistence.ChaincodePackageMetadata,
89
134
90
135
builder := d .Detect (buildContext )
91
136
if builder == nil {
92
- buildContext .Cleanup ()
93
137
return nil , errors .Errorf ("no builder found" )
94
138
}
95
139
96
140
if err := builder .Build (buildContext ); err != nil {
97
- buildContext .Cleanup ()
98
141
return nil , errors .WithMessage (err , "external builder failed to build" )
99
142
}
100
143
101
144
durablePath := filepath .Join (d .DurablePath , ccid )
102
145
103
- // cleanup anything which is already persisted
104
- err = os .RemoveAll (durablePath )
146
+ err = os .Mkdir (durablePath , 0700 )
105
147
if err != nil {
106
- return nil , errors .WithMessagef (err , "could not clean dir '%s' to persist build ouput" , durablePath )
148
+ return nil , errors .WithMessagef (err , "could not create dir '%s' to persist build ouput" , durablePath )
107
149
}
108
150
109
- err = os .Mkdir (durablePath , 0700 )
151
+ buildInfo , err := json .Marshal (& BuildInfo {
152
+ BuilderName : builder .Name ,
153
+ })
110
154
if err != nil {
111
- return nil , errors .WithMessagef (err , "could not create dir '%s' to persist build ouput" , durablePath )
155
+ os .RemoveAll (durablePath )
156
+ return nil , errors .WithMessage (err , "could not marshal for build-info.json" )
157
+ }
158
+
159
+ err = ioutil .WriteFile (filepath .Join (durablePath , "build-info.json" ), buildInfo , 0600 )
160
+ if err != nil {
161
+ os .RemoveAll (durablePath )
162
+ return nil , errors .WithMessage (err , "could not write build-info.json" )
112
163
}
113
164
114
- err = os .Rename (buildContext .OutputDir , filepath .Join (durablePath , "bld" ))
165
+ durableBldDir := filepath .Join (durablePath , "bld" )
166
+ err = os .Rename (buildContext .BldDir , durableBldDir )
115
167
if err != nil {
116
168
return nil , errors .WithMessagef (err , "could not move build context bld to persistent location '%s'" , durablePath )
117
169
}
118
170
119
171
return & Instance {
120
- PackageID : ccid ,
121
- Builder : builder ,
122
- DurablePath : durablePath ,
172
+ PackageID : ccid ,
173
+ Builder : builder ,
174
+ BldDir : durableBldDir ,
123
175
}, nil
124
176
}
125
177
@@ -129,7 +181,7 @@ type BuildContext struct {
129
181
ScratchDir string
130
182
SourceDir string
131
183
MetadataDir string
132
- OutputDir string
184
+ BldDir string
133
185
}
134
186
135
187
var pkgIDreg = regexp .MustCompile ("[^a-zA-Z0-9]+" )
@@ -177,7 +229,7 @@ func NewBuildContext(ccid string, md *persistence.ChaincodePackageMetadata, code
177
229
ScratchDir : scratchDir ,
178
230
SourceDir : sourceDir ,
179
231
MetadataDir : metadataDir ,
180
- OutputDir : outputDir ,
232
+ BldDir : outputDir ,
181
233
Metadata : md ,
182
234
CCID : ccid ,
183
235
}, nil
@@ -214,6 +266,19 @@ type Builder struct {
214
266
Name string
215
267
}
216
268
269
+ func CreateBuilders (builderConfs []peer.ExternalBuilder ) []* Builder {
270
+ builders := []* Builder {}
271
+ for _ , builderConf := range builderConfs {
272
+ builders = append (builders , & Builder {
273
+ Location : builderConf .Path ,
274
+ Name : builderConf .Name ,
275
+ EnvWhitelist : builderConf .EnvironmentWhitelist ,
276
+ Logger : logger .Named (builderConf .Name ),
277
+ })
278
+ }
279
+ return builders
280
+ }
281
+
217
282
func (b * Builder ) Detect (buildContext * BuildContext ) bool {
218
283
detect := filepath .Join (b .Location , "bin" , "detect" )
219
284
cmd := NewCommand (
@@ -225,7 +290,7 @@ func (b *Builder) Detect(buildContext *BuildContext) bool {
225
290
226
291
err := RunCommand (b .Logger , cmd )
227
292
if err != nil {
228
- logger .Debugf ("Detection for builder '%s' failed: %s" , b .Name , err )
293
+ logger .Debugf ("Detection for builder '%s' detect failed: %s" , b .Name , err )
229
294
// XXX, we probably also want to differentiate between a 'not detected'
230
295
// and a 'I failed nastily', but, again, good enough for now
231
296
return false
@@ -241,12 +306,12 @@ func (b *Builder) Build(buildContext *BuildContext) error {
241
306
b .EnvWhitelist ,
242
307
buildContext .SourceDir ,
243
308
buildContext .MetadataDir ,
244
- buildContext .OutputDir ,
309
+ buildContext .BldDir ,
245
310
)
246
311
247
312
err := RunCommand (b .Logger , cmd )
248
313
if err != nil {
249
- return errors .Wrapf (err , "builder '%s' failed" , b .Name )
314
+ return errors .Wrapf (err , "builder '%s' build failed" , b .Name )
250
315
}
251
316
252
317
return nil
@@ -261,7 +326,7 @@ type LaunchConfig struct {
261
326
RootCert []byte `json:"root_cert"`
262
327
}
263
328
264
- func (b * Builder ) Launch (ccid , durablePath string , peerConnection * ccintf.PeerConnection ) error {
329
+ func (b * Builder ) Launch (ccid , bldDir string , peerConnection * ccintf.PeerConnection ) error {
265
330
lc := & LaunchConfig {
266
331
PeerAddress : peerConnection .Address ,
267
332
CCID : ccid ,
@@ -291,13 +356,13 @@ func (b *Builder) Launch(ccid, durablePath string, peerConnection *ccintf.PeerCo
291
356
cmd := NewCommand (
292
357
launch ,
293
358
b .EnvWhitelist ,
294
- durablePath ,
359
+ bldDir ,
295
360
launchDir ,
296
361
)
297
362
298
363
err = RunCommand (b .Logger , cmd )
299
364
if err != nil {
300
- return errors .Wrapf (err , "builder '%s' failed" , b .Name )
365
+ return errors .Wrapf (err , "builder '%s' launch failed" , b .Name )
301
366
}
302
367
303
368
return nil
0 commit comments