mirror of
https://github.com/google/go-jsonnet.git
synced 2025-08-07 23:07:14 +02:00
Implemented jsonnet_import_callback c-binding (#330)
Implemented jsonnet_import_callback c-binding
This commit is contained in:
parent
42cb19ef24
commit
acf0e5cfbf
@ -2,6 +2,7 @@
|
|||||||
import unittest
|
import unittest
|
||||||
import ctypes
|
import ctypes
|
||||||
import re
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
lib = ctypes.CDLL('../c-bindings/libgojsonnet.so')
|
lib = ctypes.CDLL('../c-bindings/libgojsonnet.so')
|
||||||
@ -80,6 +81,23 @@ lib.jsonnet_native_callback.argtypes = [
|
|||||||
]
|
]
|
||||||
lib.jsonnet_native_callback.restype = None
|
lib.jsonnet_native_callback.restype = None
|
||||||
|
|
||||||
|
IMPORT_CALLBACK = ctypes.CFUNCTYPE(
|
||||||
|
ctypes.c_char_p,
|
||||||
|
ctypes.c_void_p,
|
||||||
|
ctypes.POINTER(ctypes.c_char),
|
||||||
|
ctypes.POINTER(ctypes.c_char),
|
||||||
|
# we use *int instead of **char to pass the real C allocated pointer, that we have to free
|
||||||
|
ctypes.POINTER(ctypes.c_uint64),
|
||||||
|
ctypes.POINTER(ctypes.c_int)
|
||||||
|
)
|
||||||
|
|
||||||
|
lib.jsonnet_import_callback.argtypes = [
|
||||||
|
ctypes.c_void_p,
|
||||||
|
IMPORT_CALLBACK,
|
||||||
|
ctypes.c_void_p,
|
||||||
|
]
|
||||||
|
lib.jsonnet_import_callback.restype = None
|
||||||
|
|
||||||
# json declaration
|
# json declaration
|
||||||
|
|
||||||
lib.jsonnet_json_make_string.argtypes = [
|
lib.jsonnet_json_make_string.argtypes = [
|
||||||
@ -206,6 +224,38 @@ def build_native(ctx, argv, success):
|
|||||||
success[0] = ctypes.c_int(1)
|
success[0] = ctypes.c_int(1)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
@IMPORT_CALLBACK
|
||||||
|
def import_callback(ctx, dir, rel, found_here, success):
|
||||||
|
full_path, content = jsonnet_try_path(b"jsonnet_import_test/", to_bytes(rel))
|
||||||
|
|
||||||
|
bcontent = content.encode()
|
||||||
|
dst = lib.jsonnet_realloc(ctx, None, len(bcontent) + 1)
|
||||||
|
ctypes.memmove(ctypes.addressof(dst.contents), bcontent, len(bcontent) + 1)
|
||||||
|
|
||||||
|
fdst = lib.jsonnet_realloc(ctx, None, len(full_path) + 1)
|
||||||
|
ctypes.memmove(ctypes.addressof(fdst.contents), full_path, len(full_path) + 1)
|
||||||
|
found_here[0] = ctypes.addressof(fdst.contents)
|
||||||
|
|
||||||
|
success[0] = ctypes.c_int(1)
|
||||||
|
|
||||||
|
return ctypes.addressof(dst.contents)
|
||||||
|
|
||||||
|
# Returns content if worked, None if file not found, or throws an exception
|
||||||
|
def jsonnet_try_path(dir, rel):
|
||||||
|
if not rel:
|
||||||
|
raise RuntimeError('Got invalid filename (empty string).')
|
||||||
|
if rel[0] == '/':
|
||||||
|
full_path = rel
|
||||||
|
else:
|
||||||
|
full_path = dir + rel
|
||||||
|
if full_path[-1] == '/':
|
||||||
|
raise RuntimeError('Attempted to import a directory')
|
||||||
|
|
||||||
|
if not os.path.isfile(full_path):
|
||||||
|
return full_path, None
|
||||||
|
with open(full_path) as f:
|
||||||
|
return full_path, f.read()
|
||||||
|
|
||||||
class TestJsonnetEvaluateBindings(unittest.TestCase):
|
class TestJsonnetEvaluateBindings(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.err = ctypes.c_int()
|
self.err = ctypes.c_int()
|
||||||
@ -291,6 +341,13 @@ class TestJsonnetEvaluateBindings(unittest.TestCase):
|
|||||||
|
|
||||||
free_buffer(self.vm, res)
|
free_buffer(self.vm, res)
|
||||||
|
|
||||||
|
def test_jsonnet_import_callback(self):
|
||||||
|
lib.jsonnet_import_callback(self.vm, import_callback, self.vm)
|
||||||
|
|
||||||
|
res = lib.jsonnet_evaluate_snippet(self.vm, b"jsonnet_import_callback", b"""import 'foo.jsonnet'""", self.err_ref)
|
||||||
|
self.assertEqual(b'42\n', to_bytes(res))
|
||||||
|
free_buffer(self.vm, res)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
lib.jsonnet_destroy(self.vm)
|
lib.jsonnet_destroy(self.vm)
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/google/go-jsonnet"
|
"github.com/google/go-jsonnet"
|
||||||
@ -25,6 +26,33 @@ type jsonValue struct {
|
|||||||
owned []*C.struct_JsonnetJsonValue
|
owned []*C.struct_JsonnetJsonValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type importer struct {
|
||||||
|
cb *C.JsonnetImportCallback
|
||||||
|
ctx unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import fetches data from a given path by using c.JsonnetImportCallback
|
||||||
|
func (i *importer) Import(importedFrom, importedPath string) (contents jsonnet.Contents, foundAt string, err error) {
|
||||||
|
var (
|
||||||
|
success = C.int(0)
|
||||||
|
dir, _ = path.Split(importedFrom)
|
||||||
|
foundHereC *C.char
|
||||||
|
)
|
||||||
|
|
||||||
|
resultC := C.jsonnet_internal_execute_import(i.cb, i.ctx, C.CString(dir), C.CString(importedPath), &foundHereC, &success)
|
||||||
|
result := C.GoString(resultC)
|
||||||
|
C.jsonnet_internal_free_string(resultC)
|
||||||
|
|
||||||
|
foundHere := C.GoString(foundHereC)
|
||||||
|
C.jsonnet_internal_free_string(foundHereC)
|
||||||
|
|
||||||
|
if success != 1 {
|
||||||
|
return jsonnet.Contents{}, "", fmt.Errorf("failed to execute import callback, code: %d", success)
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonnet.MakeContents(result), foundHere, nil
|
||||||
|
}
|
||||||
|
|
||||||
var handles = handlesTable{}
|
var handles = handlesTable{}
|
||||||
var versionString *C.char
|
var versionString *C.char
|
||||||
|
|
||||||
@ -219,6 +247,16 @@ func jsonnet_native_callback(vmRef *C.struct_JsonnetVm, name *C.char, cb *C.Json
|
|||||||
vm.NativeFunction(f)
|
vm.NativeFunction(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//export jsonnet_import_callback
|
||||||
|
func jsonnet_import_callback(vmRef *C.struct_JsonnetVm, cb *C.JsonnetImportCallback, ctx unsafe.Pointer) {
|
||||||
|
vm := getVM(vmRef)
|
||||||
|
|
||||||
|
vm.Importer(&importer{
|
||||||
|
ctx: ctx,
|
||||||
|
cb: cb,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
//export jsonnet_json_extract_string
|
//export jsonnet_json_extract_string
|
||||||
func jsonnet_json_extract_string(vmRef *C.struct_JsonnetVm, json *C.struct_JsonnetJsonValue) *C.char {
|
func jsonnet_json_extract_string(vmRef *C.struct_JsonnetVm, json *C.struct_JsonnetJsonValue) *C.char {
|
||||||
v := getJSONValue(json)
|
v := getJSONValue(json)
|
||||||
|
@ -24,3 +24,18 @@ struct JsonnetJsonValue* jsonnet_internal_execute_native(JsonnetNativeCallback *
|
|||||||
void *ctx,
|
void *ctx,
|
||||||
const struct JsonnetJsonValue *const *argv,
|
const struct JsonnetJsonValue *const *argv,
|
||||||
int *success);
|
int *success);
|
||||||
|
|
||||||
|
typedef char *JsonnetImportCallback(void *ctx,
|
||||||
|
const char *base,
|
||||||
|
const char *rel,
|
||||||
|
char **found_here,
|
||||||
|
int *success);
|
||||||
|
|
||||||
|
char* jsonnet_internal_execute_import(JsonnetImportCallback *cb,
|
||||||
|
void *ctx,
|
||||||
|
const char *base,
|
||||||
|
const char *rel,
|
||||||
|
char **found_here,
|
||||||
|
int *success);
|
||||||
|
|
||||||
|
void jsonnet_internal_free_string(char *str);
|
||||||
|
@ -34,6 +34,22 @@ struct JsonnetJsonValue* jsonnet_internal_execute_native(JsonnetNativeCallback *
|
|||||||
return (cb)(ctx, argv, success);
|
return (cb)(ctx, argv, success);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char* jsonnet_internal_execute_import(JsonnetImportCallback *cb,
|
||||||
|
void *ctx,
|
||||||
|
const char *base,
|
||||||
|
const char *rel,
|
||||||
|
char **found_here,
|
||||||
|
int *success)
|
||||||
|
{
|
||||||
|
return (cb)(ctx, base, rel, found_here, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jsonnet_internal_free_string(char *str) {
|
||||||
|
if (str != nullptr) {
|
||||||
|
::free(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline static void todo() {
|
inline static void todo() {
|
||||||
fputs("TODO, NOT IMPLEMENTED YET\n", stderr);
|
fputs("TODO, NOT IMPLEMENTED YET\n", stderr);
|
||||||
abort();
|
abort();
|
||||||
|
Loading…
Reference in New Issue
Block a user