/
external_lock_file.go
121 lines (113 loc) · 3.55 KB
/
external_lock_file.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
// Copyright 2020 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bufmodule
import (
"bytes"
"context"
"io/ioutil"
"github.com/bufbuild/buf/internal/pkg/encoding"
"github.com/bufbuild/buf/internal/pkg/storage"
"go.opencensus.io/trace"
"go.uber.org/multierr"
)
// externalLockFile represents the buf.lock configuration file.
type externalLockFile struct {
Deps []string `json:"deps" yaml:"deps"`
}
// putDependencies puts the lock file representation of the given dependencies into the given write bucket.
// It validates that all module names are resolved (have a digest) and that there are no duplicates.
func putDependencies(ctx context.Context, writeBucket storage.WriteBucket, dependencies []ModuleName) (retErr error) {
lockContent, err := putDependenciesToData(dependencies)
if err != nil {
return err
}
writeObjectCloser, err := writeBucket.Put(ctx, LockFilePath, uint32(len(lockContent)))
if err != nil {
return err
}
defer func() {
retErr = multierr.Append(retErr, writeObjectCloser.Close())
}()
if _, err := writeObjectCloser.Write(lockContent); err != nil {
return err
}
return nil
}
func putDependenciesToData(dependencies []ModuleName) ([]byte, error) {
sortModuleNames(dependencies)
if err := ValidateModuleNamesUnique(dependencies); err != nil {
return nil, err
}
var dependencyStrings []string
for _, dependency := range dependencies {
if dependency.Digest() == "" {
return nil, NewNoDigestError(dependency)
}
dependencyStrings = append(dependencyStrings, dependency.String())
}
externalLock := &externalLockFile{
Deps: dependencyStrings,
}
yamlBytes, err := encoding.MarshalYAML(externalLock)
if err != nil {
return nil, err
}
buffer := bytes.NewBuffer(nil)
if _, err := buffer.WriteString("# Generated by buf. DO NOT EDIT.\n"); err != nil {
return nil, err
}
if _, err := buffer.Write(yamlBytes); err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
func dependenciesForBucket(ctx context.Context, readBucket storage.ReadBucket) (_ []ModuleName, retErr error) {
ctx, span := trace.StartSpan(ctx, "get_lock_file")
defer span.End()
readObject, err := readBucket.Get(ctx, LockFilePath)
if err != nil {
if storage.IsNotExist(err) {
// If the lock file doesn't exist, just return no dependencies.
return nil, nil
}
return nil, err
}
defer func() {
retErr = multierr.Append(retErr, readObject.Close())
}()
data, err := ioutil.ReadAll(readObject)
if err != nil {
return nil, err
}
externalLockFile := &externalLockFile{}
if err := encoding.UnmarshalYAMLStrict(data, externalLockFile); err != nil {
return nil, err
}
dependencies := make([]ModuleName, len(externalLockFile.Deps))
for i, dep := range externalLockFile.Deps {
dependency, err := ModuleNameForString(dep)
if err != nil {
return nil, err
}
if dependency.Digest() == "" {
return nil, NewNoDigestError(dependency)
}
dependencies[i] = dependency
}
sortModuleNames(dependencies)
if err := ValidateModuleNamesUnique(dependencies); err != nil {
return nil, err
}
return dependencies, nil
}