-
Notifications
You must be signed in to change notification settings - Fork 52
Expand file tree
/
Copy pathgenerator_pip.go
More file actions
151 lines (127 loc) · 3.86 KB
/
generator_pip.go
File metadata and controls
151 lines (127 loc) · 3.86 KB
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
package dalec
import (
"context"
"path/filepath"
"github.com/goccy/go-yaml/ast"
"github.com/moby/buildkit/client/llb"
"github.com/pkg/errors"
)
func (s *Source) isPip() bool {
for _, gen := range s.Generate {
if gen.Pip != nil {
return true
}
}
return false
}
func (s *Spec) HasPips() bool {
for _, src := range s.Sources {
if src.isPip() {
return true
}
}
return false
}
func withPip(g *SourceGenerator, srcSt, worker llb.State, path string, opts ...llb.ConstraintsOpt) llb.State {
workDir := "/work/src"
joinedWorkDir := filepath.Join(workDir, path, g.Subpath)
srcMount := llb.AddMount(workDir, srcSt)
paths := g.Pip.Paths
if g.Pip.Paths == nil {
paths = []string{"."}
}
// Create a cache directory for pip packages
result := llb.Scratch()
cacheDir := "/pip-cache"
for _, path := range paths {
requirementsFile := g.Pip.RequirementsFile
if requirementsFile == "" {
requirementsFile = "requirements.txt"
}
pipCmd := "set -e; "
// Create the cache directory
pipCmd += "mkdir -p " + cacheDir + "; "
// First, download essential build dependencies that are needed for source builds
pipCmd += "python3 -m pip download --dest=" + cacheDir + " setuptools wheel"
if g.Pip.IndexUrl != "" {
pipCmd += " --index-url=" + g.Pip.IndexUrl
}
for _, extraUrl := range g.Pip.ExtraIndexUrls {
pipCmd += " --extra-index-url=" + extraUrl
}
pipCmd += "; python3 -m pip download --no-binary=:all: --dest=" + cacheDir + " --requirement=" + requirementsFile
// Add custom index URLs for main dependencies if specified
if g.Pip.IndexUrl != "" {
pipCmd += " --index-url=" + g.Pip.IndexUrl
}
for _, extraUrl := range g.Pip.ExtraIndexUrls {
pipCmd += " --extra-index-url=" + extraUrl
}
// Just download the packages, don't install them
result = worker.Run(
llb.Args([]string{"bash", "-c", pipCmd}),
llb.Dir(filepath.Join(joinedWorkDir, path)),
srcMount,
WithConstraints(opts...),
g.Pip._sourceMap.GetLocation(result),
).AddMount(cacheDir, result)
}
return result
}
func (s *Spec) pipSources() map[string]Source {
sources := map[string]Source{}
for name, src := range s.Sources {
if src.isPip() {
sources[name] = src
}
}
return sources
}
// PipDeps returns an llb.State containing all the pip dependencies for the spec
// for any sources that have a pip generator specified.
// If there are no sources with a pip generator, this will return nil.
// The returned state contains a merged cache of all downloaded pip packages.
func (s *Spec) PipDeps(sOpt SourceOpts, worker llb.State, opts ...llb.ConstraintsOpt) *llb.State {
sources := s.pipSources()
if len(sources) == 0 {
return nil
}
// Get the patched sources for the Python projects
// This is needed in case a patch includes changes to requirements.txt
patched := s.getPatchedSources(sOpt, worker, func(name string) bool {
_, ok := sources[name]
return ok
}, opts...)
// Create a unified cache containing all pip packages
var cacheStates []llb.State
sorted := SortMapKeys(patched)
opts = append(opts, ProgressGroup("Fetch pip dependencies for sources"))
for _, key := range sorted {
src := s.Sources[key]
merged := patched[key]
for _, gen := range src.Generate {
if gen.Pip == nil {
continue
}
cacheState := withPip(gen, merged, worker, key, opts...)
cacheStates = append(cacheStates, cacheState)
}
}
if len(cacheStates) == 0 {
return nil
}
// Merge all cache states into a single state
merged := MergeAtPath(llb.Scratch(), cacheStates, "/", opts...)
return &merged
}
func (gen *GeneratorPip) UnmarshalYAML(ctx context.Context, node ast.Node) error {
type internal GeneratorPip
var i internal
dec := getDecoder(ctx)
if err := dec.DecodeFromNodeContext(ctx, node, &i); err != nil {
return errors.Wrap(err, "failed to decode pip generator")
}
*gen = GeneratorPip(i)
gen._sourceMap = newSourceMap(ctx, node)
return nil
}