Skip to content

Commit 58f7be1

Browse files
The127claude
andcommitted
perf: keep the emulator out of the qemu-user package for later builds
Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: karo <karolin.kostial@gmail.com>
1 parent 778cf73 commit 58f7be1

3 files changed

Lines changed: 144 additions & 6 deletions

File tree

‎internal/emulator/pin.go‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,18 @@ var pins = map[string]download.Pin{
1515
Digest: "sha256:c73711af02b97cd5e2667e735d9c06890c57165517110ca4e646c95a7083158d",
1616
},
1717
}
18+
19+
// emulators are the digests of the programs in each package, by the
20+
// builder's architecture and then the architecture a program runs the
21+
// programs of. A build keeps the one it takes out under its digest, and
22+
// later builds read it without opening the package again.
23+
var emulators = map[string]map[string]string{
24+
"amd64": {
25+
"amd64": "sha256:36d35ffe5363bd49bfa9c2b6a048e9fb2e798fea38285a5a45f52d34f9869089",
26+
"arm64": "sha256:73cc2584f119f9e74c85c0a8549dbb6fd104ae3897a06a7500797f9e5b4d0943",
27+
},
28+
"arm64": {
29+
"amd64": "sha256:9af86352fd463ad9ec25bdd6a4b891ac6b6a7f3d46a7db3da6f23e2c09094a59",
30+
"arm64": "sha256:088500814a5a8e0e0ee3cad0f6c600b5dfa261f77cc0e6460f81b0b616e09509",
31+
},
32+
}

‎internal/emulator/ready.go‎

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package emulator
22

33
import (
4+
"bytes"
45
"context"
56
"fmt"
67
"io"
8+
"os"
9+
"time"
710

811
"github.com/The127/miso/internal/deb"
912
"github.com/The127/miso/internal/download"
@@ -30,12 +33,16 @@ func Ready(ctx context.Context, store *download.Store, builder, target string) (
3033
return nil, fmt.Errorf("miso has no QEMU that runs programs of %s", target)
3134
}
3235

33-
return ready(ctx, store, pin, target)
36+
return ready(ctx, store, pin, target, emulators[builder][target])
3437
}
3538

36-
// ready takes the program that runs the programs of target out of the
37-
// package a pin names.
38-
func ready(ctx context.Context, store *download.Store, pin download.Pin, target string) ([]byte, error) {
39+
// ready is the program that runs the programs of target, the one the store
40+
// keeps under digest, or else taken out of the package a pin names.
41+
func ready(ctx context.Context, store *download.Store, pin download.Pin, target, digest string) ([]byte, error) {
42+
if kept, err := os.ReadFile(store.Path(digest)); err == nil {
43+
return kept, store.Use(time.Now(), digest)
44+
}
45+
3946
pkg, err := store.OpenPinned(ctx, pin)
4047
if err != nil {
4148
return nil, err
@@ -47,7 +54,24 @@ func ready(ctx context.Context, store *download.Store, pin download.Pin, target
4754
files, failed := deb.Files(pkg)
4855
for name, file := range files {
4956
if name == wanted {
50-
return io.ReadAll(file)
57+
program, err := io.ReadAll(file)
58+
if err != nil {
59+
return nil, err
60+
}
61+
62+
got, err := store.Keep(bytes.NewReader(program))
63+
if err != nil {
64+
return nil, err
65+
}
66+
67+
if got != digest {
68+
// a pin on the digest it sits under would later find it
69+
_ = store.Remove(got)
70+
71+
return nil, fmt.Errorf("the package holds %s as %s, pinned to %s", wanted, got, digest)
72+
}
73+
74+
return program, nil
5175
}
5276
}
5377

‎internal/emulator/ready_test.go‎

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ package emulator_test
22

33
import (
44
"context"
5+
"crypto/sha256"
6+
"encoding/hex"
57
"errors"
68
"net/http"
9+
"os"
10+
"path/filepath"
711
"testing"
812

913
"github.com/stretchr/testify/assert"
@@ -26,13 +30,64 @@ func TestTheEmulatorOfAnArm64ImageIsTakenFromThePinnedPackage(t *testing.T) {
2630
store := download.Open(dir, http.DefaultClient)
2731

2832
// act
29-
found, err := emulator.ReadyFrom(context.Background(), store, download.Pin{URL: "https://snapshot.invalid/qemu-user.deb", Digest: digest}, "arm64")
33+
found, err := emulator.ReadyFrom(context.Background(), store, download.Pin{URL: "https://snapshot.invalid/qemu-user.deb", Digest: digest}, "arm64", digestOf("the emulator"))
3034

3135
// assert
3236
require.NoError(t, err)
3337
assert.Equal(t, []byte("the emulator"), found)
3438
}
3539

40+
func TestAnEmulatorTheStoreKeepsIsReadWithoutThePackage(t *testing.T) {
41+
// arrange
42+
dir := t.TempDir()
43+
digest := downloadtest.Kept(t, dir, []byte("the emulator"))
44+
refuse := roundTrip(func(*http.Request) (*http.Response, error) {
45+
return nil, errors.New("offline")
46+
})
47+
store := download.Open(dir, &http.Client{Transport: refuse})
48+
49+
// act
50+
found, err := emulator.ReadyFrom(context.Background(), store, download.Pin{URL: "https://snapshot.invalid/qemu-user.deb", Digest: "sha256:notkept"}, "arm64", digest)
51+
52+
// assert
53+
require.NoError(t, err)
54+
assert.Equal(t, []byte("the emulator"), found)
55+
}
56+
57+
func TestAnEmulatorTakenFromThePackageIsKeptUnderItsDigest(t *testing.T) {
58+
// arrange
59+
pkg := debtest.Package(t, map[string]string{"./usr/bin/qemu-aarch64": "the emulator"})
60+
dir := t.TempDir()
61+
digest := downloadtest.Kept(t, dir, pkg)
62+
store := download.Open(dir, http.DefaultClient)
63+
program := digestOf("the emulator")
64+
65+
// act
66+
_, err := emulator.ReadyFrom(context.Background(), store, download.Pin{URL: "https://snapshot.invalid/qemu-user.deb", Digest: digest}, "arm64", program)
67+
68+
// assert
69+
require.NoError(t, err)
70+
kept, err := os.ReadFile(store.Path(program))
71+
require.NoError(t, err)
72+
assert.Equal(t, []byte("the emulator"), kept)
73+
}
74+
75+
func TestAnEmulatorOtherThanItsPinIsRefusedAndNotKept(t *testing.T) {
76+
// arrange
77+
pkg := debtest.Package(t, map[string]string{"./usr/bin/qemu-aarch64": "another emulator"})
78+
dir := t.TempDir()
79+
digest := downloadtest.Kept(t, dir, pkg)
80+
store := download.Open(dir, http.DefaultClient)
81+
pinned := digestOf("the emulator")
82+
83+
// act
84+
_, err := emulator.ReadyFrom(context.Background(), store, download.Pin{URL: "https://snapshot.invalid/qemu-user.deb", Digest: digest}, "arm64", pinned)
85+
86+
// assert
87+
require.ErrorContains(t, err, pinned)
88+
assert.NoFileExists(t, store.Path(digestOf("another emulator")))
89+
}
90+
3691
func TestAnArm64BuilderRunsAnAmd64ImageWithQEMUOfItsOwnArchitecture(t *testing.T) {
3792
// arrange
3893
var asked string
@@ -51,6 +106,44 @@ func TestAnArm64BuilderRunsAnAmd64ImageWithQEMUOfItsOwnArchitecture(t *testing.T
51106
assert.Contains(t, asked, "/qemu-user_10.0.13%2Bds-0%2Bdeb13u1_arm64.deb")
52107
}
53108

109+
func TestAnArm64BuilderReadsTheAmd64EmulatorItKeptWithoutThePackage(t *testing.T) {
110+
// arrange
111+
dir := t.TempDir()
112+
refuse := roundTrip(func(*http.Request) (*http.Response, error) {
113+
return nil, errors.New("offline")
114+
})
115+
store := download.Open(dir, &http.Client{Transport: refuse})
116+
kept := store.Path("sha256:9af86352fd463ad9ec25bdd6a4b891ac6b6a7f3d46a7db3da6f23e2c09094a59")
117+
require.NoError(t, os.MkdirAll(filepath.Dir(kept), 0o750))
118+
require.NoError(t, os.WriteFile(kept, []byte("the emulator"), 0o600))
119+
120+
// act
121+
found, err := emulator.Ready(context.Background(), store, "arm64", "amd64")
122+
123+
// assert
124+
require.NoError(t, err)
125+
assert.Equal(t, []byte("the emulator"), found)
126+
}
127+
128+
func TestAnAmd64BuilderReadsTheArm64EmulatorItKeptWithoutThePackage(t *testing.T) {
129+
// arrange
130+
dir := t.TempDir()
131+
refuse := roundTrip(func(*http.Request) (*http.Response, error) {
132+
return nil, errors.New("offline")
133+
})
134+
store := download.Open(dir, &http.Client{Transport: refuse})
135+
kept := store.Path("sha256:73cc2584f119f9e74c85c0a8549dbb6fd104ae3897a06a7500797f9e5b4d0943")
136+
require.NoError(t, os.MkdirAll(filepath.Dir(kept), 0o750))
137+
require.NoError(t, os.WriteFile(kept, []byte("the emulator"), 0o600))
138+
139+
// act
140+
found, err := emulator.Ready(context.Background(), store, "amd64", "arm64")
141+
142+
// assert
143+
require.NoError(t, err)
144+
assert.Equal(t, []byte("the emulator"), found)
145+
}
146+
54147
func TestAnEmulatorForABuilderMisoHasNoQEMUForIsRefusedNamingIt(t *testing.T) {
55148
// arrange
56149
store := download.Open(t.TempDir(), http.DefaultClient)
@@ -86,3 +179,9 @@ type roundTrip func(*http.Request) (*http.Response, error)
86179
func (f roundTrip) RoundTrip(request *http.Request) (*http.Response, error) {
87180
return f(request)
88181
}
182+
183+
func digestOf(content string) string {
184+
sum := sha256.Sum256([]byte(content))
185+
186+
return "sha256:" + hex.EncodeToString(sum[:])
187+
}

0 commit comments

Comments
 (0)