Skip to content

Commit d08d6aa

Browse files
authored
add first version of rgr sandwich (vercel#3306)
1 parent 54df174 commit d08d6aa

17 files changed

+731
-11
lines changed

.github/workflows/test.yml

+8
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ jobs:
193193
- name: Setup Protos
194194
run: cd cli && make compile-protos
195195

196+
- name: Build turborepo-ffi
197+
run: cd cli && make turborepo-ffi-install
198+
196199
- name: golangci Linting
197200
uses: golangci/golangci-lint-action@v3
198201
with:
@@ -599,6 +602,11 @@ jobs:
599602
- name: Setup Node.js
600603
uses: ./.github/actions/setup-node
601604

605+
- name: Setup Protoc
606+
uses: arduino/setup-protoc@v1
607+
with:
608+
repo-token: ${{ secrets.GITHUB_TOKEN }}
609+
602610
- name: Prepare toolchain on Windows
603611
run: |
604612
pnpx node-gyp install

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,7 @@ rust-artifacts
4343

4444
# CI
4545
sweep.timestamp
46+
47+
crates/turborepo-ffi/bindings.h
48+
crates/turborepo-ffi/ffi/proto/*
49+
cli/internal/ffi/libturborepo_ffi.a

Cargo.lock

+71
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ members = [
3737
"crates/turbopack",
3838
"crates/turbopack-tests",
3939
"crates/turborepo",
40+
"crates/turborepo-ffi",
4041
"crates/turborepo-lib",
4142
"crates/turbo-updater",
4243
"xtask",

cli/Makefile

+21-3
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,33 @@ GO_FLAGS += -trimpath
1717

1818
CLI_DIR = $(shell pwd)
1919

20+
# allow opting in to the rust codepaths
21+
GO_TAG ?= go
22+
2023
GO_FILES = $(shell find . -name "*.go")
2124
SRC_FILES = $(shell find . -name "*.go" | grep -v "_test.go")
2225
GENERATED_FILES = internal/turbodprotocol/turbod.pb.go internal/turbodprotocol/turbod_grpc.pb.go
2326

2427
turbo: go-turbo$(EXT)
2528
cargo build --manifest-path ../crates/turborepo/Cargo.toml
2629

27-
go-turbo$(EXT): $(GENERATED_FILES) $(SRC_FILES) go.mod
28-
CGO_ENABLED=1 go build $(GO_FLAGS) -o go-turbo$(EXT) ./cmd/turbo
30+
go-turbo$(EXT): $(GENERATED_FILES) $(SRC_FILES) go.mod turborepo-ffi-install
31+
CGO_ENABLED=1 go build $(GO_FLAGS) -tags $(GO_TAG) -o go-turbo$(EXT) ./cmd/turbo
32+
33+
.PHONY: turborepo-ffi-install
34+
turborepo-ffi-install: turborepo-ffi turborepo-ffi-proto
35+
cp -r ../crates/turborepo-ffi/bindings.h \
36+
../crates/turborepo-ffi/ffi/proto \
37+
../crates/turborepo-ffi/target/release/libturborepo_ffi.a \
38+
./internal/ffi
39+
40+
.PHONY: turborepo-ffi
41+
turborepo-ffi:
42+
cd ../crates/turborepo-ffi && CARGO_TARGET_DIR=./target cargo build --release
43+
44+
.PHONY: turborepo-ffi-proto
45+
turborepo-ffi-proto:
46+
cd ../crates/turborepo-ffi && protoc --go_out=. messages.proto
2947

3048
protoc: internal/turbodprotocol/turbod.proto
3149
protoc --go_out=. --go_opt=paths=source_relative \
@@ -57,7 +75,7 @@ clean-go:
5775
go clean -testcache ./...
5876

5977
test-go: $(GENERATED_FILES) $(GO_FILES) go.mod go.sum
60-
go test $(TURBO_RACE) ./...
78+
go test $(TURBO_RACE) -tags $(GO_TAG) ./...
6179

6280
# protos need to be compiled before linting, since linting needs to pick up
6381
# some types from the generated code

cli/internal/ffi/bindings.h

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <stdarg.h>
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
6+
typedef struct Buffer {
7+
uint32_t len;
8+
uint8_t *data;
9+
} Buffer;
10+
11+
struct Buffer get_turbo_data_dir(void);

cli/internal/ffi/ffi.go

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package ffi
2+
3+
// #include "bindings.h"
4+
//
5+
// #cgo LDFLAGS: -L${SRCDIR} -lturborepo_ffi
6+
// #cgo windows LDFLAGS: -lole32 -lbcrypt -lws2_32 -luserenv
7+
import "C"
8+
9+
import (
10+
"reflect"
11+
"unsafe"
12+
13+
ffi_proto "github.com/vercel/turbo/cli/internal/ffi/proto"
14+
"google.golang.org/protobuf/proto"
15+
)
16+
17+
// Unmarshal consumes a buffer and parses it into a proto.Message
18+
func Unmarshal[M proto.Message](b C.Buffer, c M) error {
19+
bytes := toBytes(b)
20+
if err := proto.Unmarshal(bytes, c); err != nil {
21+
return err
22+
}
23+
24+
b.Free()
25+
26+
return nil
27+
}
28+
29+
// Marshal consumes a proto.Message and returns a bufferfire
30+
//
31+
// NOTE: the buffer must be freed by calling `Free` on it
32+
func Marshal[M proto.Message](c M) C.Buffer {
33+
bytes, err := proto.Marshal(c)
34+
if err != nil {
35+
panic(err)
36+
}
37+
38+
return toBuffer(bytes)
39+
}
40+
41+
func (c C.Buffer) Free() {
42+
C.free(unsafe.Pointer(c.data))
43+
}
44+
45+
// rather than use C.GoBytes, we use this function to avoid copying the bytes,
46+
// since it is going to be immediately Unmarshalled into a proto.Message
47+
func toBytes(b C.Buffer) []byte {
48+
var out []byte
49+
50+
len := (uint32)(b.len)
51+
52+
sh := (*reflect.SliceHeader)(unsafe.Pointer(&out))
53+
sh.Data = uintptr(unsafe.Pointer(b.data))
54+
sh.Len = int(len)
55+
sh.Cap = int(len)
56+
57+
return out
58+
}
59+
60+
func toBuffer(bytes []byte) C.Buffer {
61+
b := C.Buffer{}
62+
b.len = C.uint(len(bytes))
63+
b.data = (*C.uchar)(C.CBytes(bytes))
64+
return b
65+
}
66+
67+
// GetTurboDataDir returns the path to the Turbo data directory
68+
func GetTurboDataDir() string {
69+
buffer := C.get_turbo_data_dir()
70+
resp := ffi_proto.TurboDataDirResp{}
71+
if err := Unmarshal(buffer, resp.ProtoReflect().Interface()); err != nil {
72+
panic(err)
73+
}
74+
return resp.Dir
75+
}

0 commit comments

Comments
 (0)