aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/cli/internal/ffi/ffi.go
diff options
context:
space:
mode:
author简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:55 +0800
committer简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:55 +0800
commitfc8c5fdce62fb229202659408798a7b6c98f6e8b (patch)
tree7554f80e50de4af6fd255afa7c21bcdd58a7af34 /cli/internal/ffi/ffi.go
parentdd84b9d64fb98746a230cd24233ff50a562c39c9 (diff)
downloadHydroRoll-fc8c5fdce62fb229202659408798a7b6c98f6e8b.tar.gz
HydroRoll-fc8c5fdce62fb229202659408798a7b6c98f6e8b.zip
Diffstat (limited to 'cli/internal/ffi/ffi.go')
-rw-r--r--cli/internal/ffi/ffi.go224
1 files changed, 0 insertions, 224 deletions
diff --git a/cli/internal/ffi/ffi.go b/cli/internal/ffi/ffi.go
deleted file mode 100644
index 7ac15e4..0000000
--- a/cli/internal/ffi/ffi.go
+++ /dev/null
@@ -1,224 +0,0 @@
-package ffi
-
-// ffi
-//
-// Please read the notes about safety (marked with `SAFETY`) in both this file,
-// and in turborepo-ffi/lib.rs before modifying this file.
-
-// #include "bindings.h"
-//
-// #cgo darwin,arm64 LDFLAGS: -L${SRCDIR} -lturborepo_ffi_darwin_arm64 -lz -liconv
-// #cgo darwin,amd64 LDFLAGS: -L${SRCDIR} -lturborepo_ffi_darwin_amd64 -lz -liconv
-// #cgo linux,arm64,staticbinary LDFLAGS: -L${SRCDIR} -lturborepo_ffi_linux_arm64 -lunwind
-// #cgo linux,amd64,staticbinary LDFLAGS: -L${SRCDIR} -lturborepo_ffi_linux_amd64 -lunwind
-// #cgo linux,arm64,!staticbinary LDFLAGS: -L${SRCDIR} -lturborepo_ffi_linux_arm64 -lz
-// #cgo linux,amd64,!staticbinary LDFLAGS: -L${SRCDIR} -lturborepo_ffi_linux_amd64 -lz
-// #cgo windows,amd64 LDFLAGS: -L${SRCDIR} -lturborepo_ffi_windows_amd64 -lole32 -lbcrypt -lws2_32 -luserenv
-import "C"
-
-import (
- "errors"
- "reflect"
- "unsafe"
-
- ffi_proto "github.com/vercel/turbo/cli/internal/ffi/proto"
- "google.golang.org/protobuf/proto"
-)
-
-// Unmarshal consumes a buffer and parses it into a proto.Message
-func Unmarshal[M proto.Message](b C.Buffer, c M) error {
- bytes := toBytes(b)
- if err := proto.Unmarshal(bytes, c); err != nil {
- return err
- }
-
- // free the buffer on the rust side
- //
- // SAFETY: do not use `C.free_buffer` to free a buffer that has been allocated
- // on the go side. If you happen to accidentally use the wrong one, you can
- // expect a segfault on some platforms. This is the only valid callsite.
- C.free_buffer(b)
-
- return nil
-}
-
-// Marshal consumes a proto.Message and returns a bufferfire
-//
-// NOTE: the buffer must be freed by calling `Free` on it
-func Marshal[M proto.Message](c M) C.Buffer {
- bytes, err := proto.Marshal(c)
- if err != nil {
- panic(err)
- }
-
- return toBuffer(bytes)
-}
-
-// Free frees a buffer that has been allocated *on the go side*.
-//
-// SAFETY: this is not the same as `C.free_buffer`, which frees a buffer that
-// has been allocated *on the rust side*. If you happen to accidentally use
-// the wrong one, you can expect a segfault on some platforms.
-//
-// EXAMPLE: it is recommended use this function via a `defer` statement, like so:
-//
-// reqBuf := Marshal(&req)
-// defer reqBuf.Free()
-func (c C.Buffer) Free() {
- C.free(unsafe.Pointer(c.data))
-}
-
-// rather than use C.GoBytes, we use this function to avoid copying the bytes,
-// since it is going to be immediately Unmarshalled into a proto.Message
-//
-// SAFETY: go slices contain a pointer to an underlying buffer with a length.
-// if the buffer is known to the garbage collector, dropping the last slice will
-// cause the memory to be freed. this memory is owned by the rust side (and is
-// not known the garbage collector), so dropping the slice will do nothing
-func toBytes(b C.Buffer) []byte {
- var out []byte
-
- len := (uint32)(b.len)
-
- sh := (*reflect.SliceHeader)(unsafe.Pointer(&out))
- sh.Data = uintptr(unsafe.Pointer(b.data))
- sh.Len = int(len)
- sh.Cap = int(len)
-
- return out
-}
-
-func toBuffer(bytes []byte) C.Buffer {
- b := C.Buffer{}
- b.len = C.uint(len(bytes))
- b.data = (*C.uchar)(C.CBytes(bytes))
- return b
-}
-
-// GetTurboDataDir returns the path to the Turbo data directory
-func GetTurboDataDir() string {
- buffer := C.get_turbo_data_dir()
- resp := ffi_proto.TurboDataDirResp{}
- if err := Unmarshal(buffer, resp.ProtoReflect().Interface()); err != nil {
- panic(err)
- }
- return resp.Dir
-}
-
-// Go convention is to use an empty string for an uninitialized or null-valued
-// string. Rust convention is to use an Option<String> for the same purpose, which
-// is encoded on the Go side as *string. This converts between the two.
-func stringToRef(s string) *string {
- if s == "" {
- return nil
- }
- return &s
-}
-
-// ChangedFiles returns the files changed in between two commits, the workdir and the index, and optionally untracked files
-func ChangedFiles(gitRoot string, turboRoot string, fromCommit string, toCommit string) ([]string, error) {
- fromCommitRef := stringToRef(fromCommit)
- toCommitRef := stringToRef(toCommit)
-
- req := ffi_proto.ChangedFilesReq{
- GitRoot: gitRoot,
- FromCommit: fromCommitRef,
- ToCommit: toCommitRef,
- TurboRoot: turboRoot,
- }
-
- reqBuf := Marshal(&req)
- defer reqBuf.Free()
-
- respBuf := C.changed_files(reqBuf)
-
- resp := ffi_proto.ChangedFilesResp{}
- if err := Unmarshal(respBuf, resp.ProtoReflect().Interface()); err != nil {
- panic(err)
- }
- if err := resp.GetError(); err != "" {
- return nil, errors.New(err)
- }
-
- return resp.GetFiles().GetFiles(), nil
-}
-
-// PreviousContent returns the content of a file at a previous commit
-func PreviousContent(gitRoot, fromCommit, filePath string) ([]byte, error) {
- req := ffi_proto.PreviousContentReq{
- GitRoot: gitRoot,
- FromCommit: fromCommit,
- FilePath: filePath,
- }
-
- reqBuf := Marshal(&req)
- defer reqBuf.Free()
-
- respBuf := C.previous_content(reqBuf)
-
- resp := ffi_proto.PreviousContentResp{}
- if err := Unmarshal(respBuf, resp.ProtoReflect().Interface()); err != nil {
- panic(err)
- }
- content := resp.GetContent()
- if err := resp.GetError(); err != "" {
- return nil, errors.New(err)
- }
-
- return []byte(content), nil
-}
-
-// NpmTransitiveDeps returns the transitive external deps of a given package based on the deps and specifiers given
-func NpmTransitiveDeps(content []byte, pkgDir string, unresolvedDeps map[string]string) ([]*ffi_proto.LockfilePackage, error) {
- return transitiveDeps(npmTransitiveDeps, content, pkgDir, unresolvedDeps)
-}
-
-func npmTransitiveDeps(buf C.Buffer) C.Buffer {
- return C.npm_transitive_closure(buf)
-}
-
-func transitiveDeps(cFunc func(C.Buffer) C.Buffer, content []byte, pkgDir string, unresolvedDeps map[string]string) ([]*ffi_proto.LockfilePackage, error) {
- req := ffi_proto.TransitiveDepsRequest{
- Contents: content,
- WorkspaceDir: pkgDir,
- UnresolvedDeps: unresolvedDeps,
- }
- reqBuf := Marshal(&req)
- resBuf := cFunc(reqBuf)
- reqBuf.Free()
-
- resp := ffi_proto.TransitiveDepsResponse{}
- if err := Unmarshal(resBuf, resp.ProtoReflect().Interface()); err != nil {
- panic(err)
- }
-
- if err := resp.GetError(); err != "" {
- return nil, errors.New(err)
- }
-
- list := resp.GetPackages()
- return list.GetList(), nil
-}
-
-// NpmSubgraph returns the contents of a npm lockfile subgraph
-func NpmSubgraph(content []byte, workspaces []string, packages []string) ([]byte, error) {
- req := ffi_proto.SubgraphRequest{
- Contents: content,
- Workspaces: workspaces,
- Packages: packages,
- }
- reqBuf := Marshal(&req)
- resBuf := C.npm_subgraph(reqBuf)
- reqBuf.Free()
-
- resp := ffi_proto.SubgraphResponse{}
- if err := Unmarshal(resBuf, resp.ProtoReflect().Interface()); err != nil {
- panic(err)
- }
-
- if err := resp.GetError(); err != "" {
- return nil, errors.New(err)
- }
-
- return resp.GetContents(), nil
-}