forked from cloudfoundry/python-buildpack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconda.go
More file actions
165 lines (137 loc) · 4.37 KB
/
Copy pathconda.go
File metadata and controls
165 lines (137 loc) · 4.37 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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package conda
import (
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/cloudfoundry/libbuildpack"
"github.com/kr/text"
)
type Stager interface {
BuildDir() string
CacheDir() string
DepDir() string
DepsIdx() string
LinkDirectoryInDepDir(string, string) error
WriteProfileD(string, string) error
}
type Installer interface {
InstallOnlyVersion(string, string) error
}
type Command interface {
Execute(string, io.Writer, io.Writer, string, ...string) error
Output(dir string, program string, args ...string) (string, error)
}
type Conda struct {
Installer Installer
Stager Stager
Command Command
Log *libbuildpack.Logger
}
func New(i Installer, s Stager, c Command, l *libbuildpack.Logger) *Conda {
return &Conda{
Installer: i,
Stager: s,
Command: c,
Log: l,
}
}
func Run(c *Conda) error {
c.Warning()
if err := c.Install(c.Version()); err != nil {
c.Log.Error("Could not install conda: %v", err)
return err
}
if err := c.UpdateAndClean(); err != nil {
c.Log.Error("Could not update conda env: %v", err)
return err
}
c.Stager.LinkDirectoryInDepDir(c.condaBin(), "bin")
if err := c.Stager.WriteProfileD("conda.sh", c.ProfileD()); err != nil {
c.Log.Error("Could not write profile.d script: %v", err)
return err
}
c.Log.BeginStep("Done")
return nil
}
func (c *Conda) Version() string {
return "miniforge"
}
func (c *Conda) Install(version string) error {
c.Log.BeginStep("Supplying conda")
var installer string
if installerDir, err := os.MkdirTemp("", "miniforge"); err != nil {
return err
} else {
installer = filepath.Join(installerDir, "miniforge.sh")
defer os.RemoveAll(installerDir)
}
if err := c.Installer.InstallOnlyVersion(version, installer); err != nil {
return fmt.Errorf("Error downloading miniforge: %v", err)
}
if err := os.Chmod(installer, 0755); err != nil {
return err
}
c.Log.BeginStep("Installing Miniforge")
if err := c.Command.Execute("/", indentWriter(os.Stdout), io.Discard, installer, "-b", "-p", c.condaHome()); err != nil {
return fmt.Errorf("Error installing miniforge: %v", err)
}
return nil
}
func (c *Conda) UpdateAndClean() error {
c.Log.BeginStep("Installing Dependencies")
c.Log.BeginStep("Installing conda environment from environment.yml")
verbosity := []string{"--quiet"}
if os.Getenv("BP_DEBUG") != "" {
verbosity = []string{"--debug", "--verbose"}
}
condaCache := filepath.Join(c.Stager.CacheDir(), "conda")
c.Log.Debug("Setting CONDA_PKGS_DIRS to %s", condaCache)
if err := os.Setenv("CONDA_PKGS_DIRS", condaCache); err != nil {
return fmt.Errorf("setting CONDA_PKGS_DIRS: %w", err)
}
args := append(append([]string{"env", "update"}, verbosity...), "-n", "dep_env", "-f", filepath.Join(c.Stager.BuildDir(), "environment.yml"))
c.Log.Debug("Run Conda: %s %s", c.condaExec(), strings.Join(args, " "))
if err := c.Command.Execute("/", indentWriter(os.Stdout), indentWriter(os.Stderr), c.condaExec(), args...); err != nil {
return fmt.Errorf("Could not run conda env update: %v", err)
}
if err := c.Command.Execute("/", indentWriter(os.Stdout), indentWriter(os.Stderr), c.condaExec(), "clean", "-pt"); err != nil {
c.Log.Error("Could not run conda clean: %v", err)
return fmt.Errorf("Could not run conda clean: %v", err)
}
return nil
}
func (c *Conda) condaHome() string {
return filepath.Join(c.Stager.DepDir(), "conda")
}
func (c *Conda) condaBin() string {
return filepath.Join(c.condaHome(), "bin")
}
func (c *Conda) condaExec() string {
return filepath.Join(c.condaBin(), "conda")
}
func (c *Conda) ProfileD() string {
return fmt.Sprintf(`grep -rlI %s $DEPS_DIR/%s/conda | xargs sed -i -e "s|%s|$DEPS_DIR/%s|g"
source activate dep_env
`, c.Stager.DepDir(), c.Stager.DepsIdx(), c.Stager.DepDir(), c.Stager.DepsIdx())
}
func (c *Conda) Warning() error {
if exists, err := libbuildpack.FileExists(filepath.Join(c.Stager.BuildDir(), "runtime.txt")); err != nil {
return err
} else if !exists {
return nil
}
if contents, err := os.ReadFile(filepath.Join(c.Stager.BuildDir(), "environment.yml")); err != nil {
return err
} else {
if bytes.Contains(contents, []byte("python=")) {
c.Log.Warning("you have specified the version of Python runtime both in 'runtime.txt' and 'environment.yml'. You should remove one of the two versions")
}
}
return nil
}
func indentWriter(writer io.Writer) io.Writer {
return text.NewIndentWriter(writer, []byte(" "))
}