Simplified in-memory execution
All checks were successful
/ test (push) Successful in 22s

This commit is contained in:
Eduard Urbach 2025-07-07 15:13:13 +02:00
parent e01b0b3951
commit b55b582b69
Signed by: akyoto
GPG key ID: 49226B848C78F6C8
4 changed files with 39 additions and 39 deletions

View file

@ -16,6 +16,7 @@ func TestExec(t *testing.T) {
assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello", "--dry", "--os", "mac", "--arch", "x86"}), 0) assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello", "--dry", "--os", "mac", "--arch", "x86"}), 0)
assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello", "--dry", "--os", "windows", "--arch", "arm"}), 0) assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello", "--dry", "--os", "windows", "--arch", "arm"}), 0)
assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello", "--dry", "--os", "windows", "--arch", "x86"}), 0) assert.Equal(t, cli.Exec([]string{"build", "../../examples/hello", "--dry", "--os", "windows", "--arch", "x86"}), 0)
assert.Equal(t, cli.Exec([]string{"run", "../../examples/hello"}), 0)
assert.Equal(t, cli.Exec([]string{"help"}), 0) assert.Equal(t, cli.Exec([]string{"help"}), 0)
} }

View file

@ -3,45 +3,17 @@
package memfile package memfile
import ( import (
"fmt"
"os" "os"
"strconv" "os/exec"
"syscall"
"unsafe"
"golang.org/x/sys/unix"
) )
// Exec executes an in-memory file. // Exec executes an in-memory file.
func Exec(file *os.File) error { func Exec(file *os.File) error {
empty, err := syscall.BytePtrFromString("") defer file.Close()
cmd := exec.Command(fmt.Sprintf("/proc/self/fd/%d", file.Fd()))
if err != nil { cmd.Stdout = os.Stdout
return err cmd.Stdin = os.Stdin
} cmd.Stderr = os.Stderr
return cmd.Run()
argv := []string{"/proc/self/fd/" + strconv.Itoa(int(file.Fd()))}
argvp, err := syscall.SlicePtrFromStrings(argv)
if err != nil {
return err
}
envv := os.Environ()
envvp, err := syscall.SlicePtrFromStrings(envv)
if err != nil {
return err
}
_, _, errno := syscall.Syscall6(
unix.SYS_EXECVEAT,
file.Fd(),
uintptr(unsafe.Pointer(empty)),
uintptr(unsafe.Pointer(&argvp[0])),
uintptr(unsafe.Pointer(&envvp[0])),
uintptr(unix.AT_EMPTY_PATH),
0,
)
return errno
} }

View file

@ -10,7 +10,7 @@ import (
// New creates a new anonymous in-memory file. // New creates a new anonymous in-memory file.
func New(name string) (*os.File, error) { func New(name string) (*os.File, error) {
pattern := "" pattern := "*"
if global.OS == "windows" { if global.OS == "windows" {
pattern = "*.exe" pattern = "*.exe"

View file

@ -1,15 +1,42 @@
package memfile_test package memfile_test
import ( import (
"errors"
"io/fs"
"testing" "testing"
"git.urbach.dev/cli/q/src/build"
"git.urbach.dev/cli/q/src/compiler"
"git.urbach.dev/cli/q/src/linker"
"git.urbach.dev/cli/q/src/memfile" "git.urbach.dev/cli/q/src/memfile"
"git.urbach.dev/go/assert" "git.urbach.dev/go/assert"
) )
func TestNew(t *testing.T) { func TestEmptyFile(t *testing.T) {
file, err := memfile.New("") file, err := memfile.New("")
assert.Nil(t, err) assert.Nil(t, err)
assert.NotNil(t, file) assert.NotNil(t, file)
// memfile.Exec can't be tested because it would replace the test executable
err = memfile.Exec(file)
assert.NotNil(t, err)
err = file.Close()
assert.True(t, errors.Is(err, fs.ErrClosed))
}
func TestHelloExample(t *testing.T) {
file, err := memfile.New("")
assert.Nil(t, err)
assert.NotNil(t, file)
b := build.New("../../examples/hello")
env, err := compiler.Compile(b)
assert.Nil(t, err)
linker.Write(file, b, env)
err = memfile.Exec(file)
assert.Nil(t, err)
err = file.Close()
assert.True(t, errors.Is(err, fs.ErrClosed))
} }