aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/rosa/python.go
blob: d868efe3c8b1207db03ef9f50a6c018065c51e85 (plain)
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
package rosa

import (
	"slices"

	"hakurei.app/internal/pkg"
)

var (
	_python       = H("python")
	_pythonPyTest = H("python-pytest")
)

// PipHelper is the [Python] pip packaging helper.
type PipHelper struct {
	// Path elements joined with source.
	Append []string
	// Whether to omit --no-build-isolation.
	BuildIsolation bool
	// Whether to enter source after install.
	EnterSource bool
	// Whether to install to build environment after install.
	Install bool
	// Whether to skip running tests.
	SkipCheck bool
	// Replaces pytest if non-empty.
	Check string
	// Runs after install.
	Script string
}

var _ Helper = new(PipHelper)

// extra returns python, or pytest if defaults are assumed.
func (attr *PipHelper) extra(int) P {
	if attr == nil || (!attr.SkipCheck && attr.Check == "") {
		return P{_pythonPyTest}
	}
	return P{_python}
}

// wantsChmod returns true.
func (*PipHelper) wantsChmod() bool { return true }

// wantsWrite is equivalent to wantsChmod.
func (attr *PipHelper) wantsWrite() bool { return attr.wantsChmod() }

// scriptEarly is a noop.
func (*PipHelper) scriptEarly() string { return "" }

// wantsDir requests a new directory in TMPDIR.
func (*PipHelper) wantsDir() (string, bool) { return `"$(mktemp -d)"`, false }

// script generates the pip3 install command.
func (attr *PipHelper) script(_ Toolchain, name string) string {
	if attr == nil {
		attr = new(PipHelper)
	}
	sourcePath := AbsUsrSrc.Append(name).Append(attr.Append...)

	var extra string
	if !attr.BuildIsolation {
		extra += `
	--no-build-isolation \`
	}

	var script string
	if attr.Install {
		script += `pip3 install \
	--no-index \
	--prefix=/system \
	--no-build-isolation \
	'` + sourcePath.String() + `'
`
	}
	if attr.EnterSource {
		script += "cd '/usr/src/" + name + "'\n"
	}
	if !attr.SkipCheck {
		if attr.Check == "" {
			// some test suites fall apart when ran out-of-tree
			script += "(cd '" + sourcePath.String() + "' && pytest)\n"
		} else {
			script += attr.Check
		}
	}
	script += attr.Script

	return `
pip3 install \
	--no-index \
	--prefix=/system \
	--root=/work \` + extra + `
	'` + sourcePath.String() + `'
` + script
}

// newPythonPackage registers a new [Python] package.
func (s *S) newPythonPackage(
	name string, id int, description, website, version string,
	source pkg.Artifact, attrP *PackageAttr, attr *PipHelper,
	build P, extra ...ArtifactH,
) {
	name = "python-" + name
	s.MustRegister(name, func(t Toolchain) (*Metadata, pkg.Artifact) {
		return &Metadata{
				Name:        name,
				Description: description,
				Website:     website,
				Version:     version,

				Dependencies: slices.Concat(P{_python}, extra),

				ID: id,
			}, t.NewPackage(name, version, source, attrP, attr, slices.Concat(
				extra,
				build,
			)...)
	})
}