Skip to content

Commit

Permalink
Feat: Use python-build-standalone over apt packages (#699)
Browse files Browse the repository at this point in the history
- Use python-build-standalone as a drop-in replacement for custom images
without python
- Template the install script, python versions, and a few other runtime
variables

Resolve BE-1974
  • Loading branch information
nickpetrovic authored Nov 12, 2024
1 parent 989db62 commit dacb52d
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 5 deletions.
58 changes: 57 additions & 1 deletion pkg/abstractions/image/build.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package image

import (
"bytes"
"context"
"crypto/sha1"
_ "embed"
"encoding/hex"
"fmt"
"log"
"regexp"
"runtime"
"strings"
"text/template"
"time"

"github.com/google/uuid"
Expand Down Expand Up @@ -290,7 +293,11 @@ func (b *Builder) Build(ctx context.Context, opts *BuildOpts, outputChan chan co
checkPythonVersionCmd := fmt.Sprintf("%s --version", opts.PythonVersion)
if resp, err := client.Exec(containerId, checkPythonVersionCmd); (err != nil || !resp.Ok) && !micromambaEnv {
outputChan <- common.OutputMsg{Done: false, Success: false, Msg: fmt.Sprintf("%s not detected, installing it for you...\n", opts.PythonVersion)}
installCmd := getPythonInstallCommand(opts.PythonVersion)
installCmd, err := getPythonStandaloneInstallCommand(b.config.ImageService.Runner.PythonStandalone, opts.PythonVersion)
if err != nil {
outputChan <- common.OutputMsg{Done: true, Success: false, Msg: err.Error() + "\n"}
return err
}
opts.Commands = append([]string{installCmd}, opts.Commands...)
}

Expand Down Expand Up @@ -493,6 +500,55 @@ func getPythonInstallCommand(pythonVersion string) string {
return fmt.Sprintf("%s && add-apt-repository ppa:deadsnakes/ppa && apt-get update && apt-get install -q -y %s && %s", baseCmd, installCmd, postInstallCmd)
}

// PythonStandaloneTemplate is used to render the standalone python install script
type PythonStandaloneTemplate struct {
PythonVersion string

// Architecture, OS, and Vendor are determined at runtime
Architecture string
OS string
Vendor string
}

func getPythonStandaloneInstallCommand(config types.PythonStandaloneConfig, pythonVersion string) (string, error) {
var arch string
switch runtime.GOARCH {
case "amd64":
arch = "x86_64"
case "arm64":
arch = "aarch64"
default:
return "", errors.New("unsupported architecture for python standalone install")
}

var vendor, os string
switch runtime.GOOS {
case "linux":
vendor, os = "unknown", "linux"
case "darwin":
vendor, os = "apple", "darwin"
default:
return "", errors.New("unsupported OS for python standalone install")
}

tmpl, err := template.New("standalonePython").Parse(config.InstallScriptTemplate)
if err != nil {
return "", err
}

var output bytes.Buffer
if err := tmpl.Execute(&output, PythonStandaloneTemplate{
PythonVersion: config.Versions[pythonVersion],
Architecture: arch,
OS: os,
Vendor: vendor,
}); err != nil {
return "", err
}

return output.String(), nil
}

func generatePipInstallCommand(pythonPackages []string, pythonVersion string) string {
flagLines, packages := parseFlagLinesAndPackages(pythonPackages)

Expand Down
21 changes: 20 additions & 1 deletion pkg/common/config.default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,25 @@ imageService:
micromamba3.10: micromamba3.10-latest
micromamba3.11: micromamba3.11-latest
micromamba3.12: micromamba3.12-latest
pythonStandalone:
versions:
python3.8: 3.8.20
python3.9: 3.9.20
python3.10: 3.10.5
python3.11: 3.11.10
python3.12: 3.12.7
installScriptTemplate: |
apt-get update -q && \
apt-get install -q -y build-essential curl git && \
curl -fsSL -o python.tgz 'https://github.com/indygreg/python-build-standalone/releases/download/20241016/cpython-{{.PythonVersion}}+20241016-{{.Architecture}}-{{.Vendor}}-{{.OS}}-gnu-install_only.tar.gz' && \
tar -xzf python.tgz -C /usr/local --strip-components 1 && \
rm -f python.tgz && \
rm -f /usr/bin/python && \
rm -f /usr/bin/python3 && \
ln -s /usr/local/bin/python3 /usr/bin/python && \
ln -s /usr/local/bin/python3 /usr/bin/python3 && \
ln -s /usr/local/bin/pip3 /usr/bin/pip && \
ln -s /usr/local/bin/pip3 /usr/bin/pip3
worker:
pools:
default:
Expand Down Expand Up @@ -204,4 +223,4 @@ abstractions:
Do not return the same marker data back to the user in consecutive responses.
stepIntervalS: 1
sessionInactivityTimeoutS: 10
sessionInactivityTimeoutS: 10
12 changes: 9 additions & 3 deletions pkg/types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,15 @@ type S3ImageRegistryConfig struct {
}

type RunnerConfig struct {
BaseImageName string `key:"baseImageName" json:"base_image_name"`
BaseImageRegistry string `key:"baseImageRegistry" json:"base_image_registry"`
Tags map[string]string `key:"tags" json:"tags"`
BaseImageName string `key:"baseImageName" json:"base_image_name"`
BaseImageRegistry string `key:"baseImageRegistry" json:"base_image_registry"`
Tags map[string]string `key:"tags" json:"tags"`
PythonStandalone PythonStandaloneConfig `key:"pythonStandalone" json:"python_standalone"`
}

type PythonStandaloneConfig struct {
Versions map[string]string `key:"versions" json:"versions"`
InstallScriptTemplate string `key:"installScriptTemplate" json:"install_script_template"`
}

type StorageConfig struct {
Expand Down

0 comments on commit dacb52d

Please sign in to comment.