mirror of
https://gitea.com/gitea/runner.git
synced 2026-11-14 20:03:42 +00:00
refactor(container): stream copies into the job and archives out of the host (#1340)
Adds `CopyTarStream` to the job environments. It extracts directories and files into the job as they are written, kept below the destination and owned by the job user along with any directories it creates, so built-in actions can put large content in place without buffering it. The host's `GetContainerArchive` now streams instead of building the archive in memory. --------- Co-authored-by: silverwind <[email protected]> Co-authored-by: silverwind <[email protected]> Co-authored-by: Lunny Xiao <[email protected]> Reviewed-on: https://gitea.com/gitea/runner/pulls/1340 Reviewed-by: Lunny Xiao <[email protected]> Reviewed-by: silverwind <[email protected]> Co-authored-by: bircni <[email protected]>
This commit is contained in:
1 parent
b88d111cc5
commit
8c8950d9ef
9 files changed
+313
-40
No files matched your search
@@ -8,6 +8,7 @@ import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -76,7 +77,54 @@ func TestGetContainerArchive(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, expectedContent, content)
|
||||
_, err = reader.Next()
|
||||
assert.ErrorIs(t, err, io.EOF)
|
||||
require.ErrorIs(t, err, io.EOF)
|
||||
require.NoError(t, archive.Close())
|
||||
|
||||
_, err = e.GetContainerArchive(ctx, filepath.Join(e.Path, "missing"))
|
||||
assert.ErrorIs(t, err, os.ErrNotExist)
|
||||
}
|
||||
|
||||
func TestHostCopyTarStream(t *testing.T) {
|
||||
dest := filepath.Join(t.TempDir(), "out")
|
||||
write := func(name string, mode int64, body string) func(*TarWriter) error {
|
||||
return func(tw *TarWriter) error {
|
||||
if err := tw.WriteHeader(&tar.Header{Typeflag: tar.TypeReg, Name: name, Mode: mode, Size: int64(len(body))}); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := tw.Write([]byte(body))
|
||||
return err
|
||||
}
|
||||
}
|
||||
e := &HostEnvironment{}
|
||||
require.NoError(t, e.CopyTarStream(t.Context(), dest, write("dir/run.sh", 0o755, "#!/bin/sh\n")))
|
||||
content, err := os.ReadFile(filepath.Join(dest, "dir", "run.sh"))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "#!/bin/sh\n", string(content))
|
||||
if runtime.GOOS != "windows" {
|
||||
require.NoError(t, os.Chmod(filepath.Join(dest, "dir", "run.sh"), 0o444))
|
||||
require.NoError(t, e.CopyTarStream(t.Context(), dest, func(tw *TarWriter) error {
|
||||
if err := tw.WriteHeader(&tar.Header{Typeflag: tar.TypeDir, Name: "dir/", Mode: 0o555}); err != nil {
|
||||
return err
|
||||
}
|
||||
return write("dir/run.sh", 0o755, "")(tw)
|
||||
}))
|
||||
t.Cleanup(func() { require.NoError(t, os.Chmod(filepath.Join(dest, "dir"), 0o755)) })
|
||||
for name, mode := range map[string]os.FileMode{"dir": 0o555, filepath.Join("dir", "run.sh"): 0o755} {
|
||||
info, err := os.Stat(filepath.Join(dest, name))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, mode, info.Mode().Perm(), name)
|
||||
}
|
||||
require.NoError(t, os.Symlink(t.TempDir(), filepath.Join(dest, "link")))
|
||||
require.ErrorContains(t, e.CopyTarStream(t.Context(), dest, write("link/x", 0o644, "x")), "escapes")
|
||||
}
|
||||
|
||||
require.ErrorContains(t, e.CopyTarStream(t.Context(), dest, write("../escape", 0o644, "x")), "escapes")
|
||||
assert.NoFileExists(t, filepath.Join(filepath.Dir(dest), "escape"))
|
||||
require.Error(t, e.CopyTarStream(t.Context(), dest, func(_tw *TarWriter) error { return fmt.Errorf("read body: %w", io.EOF) }))
|
||||
canceled, cancel := context.WithCancel(t.Context())
|
||||
cancel()
|
||||
require.ErrorIs(t, e.CopyTarStream(canceled, dest, write("late", 0o644, "x")), context.Canceled)
|
||||
assert.NoFileExists(t, filepath.Join(dest, "late"))
|
||||
}
|
||||
|
||||
func TestHostEnvironmentExecExitCode(t *testing.T) {
|
||||
|
||||
Reference in new issue
Block a user