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 ctypes
|
||||
import re
|
||||
import os
|
||||
|
||||
|
||||
lib = ctypes.CDLL('../c-bindings/libgojsonnet.so')
|
||||
@ -80,6 +81,23 @@ lib.jsonnet_native_callback.argtypes = [
|
||||
]
|
||||
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
|
||||
|
||||
lib.jsonnet_json_make_string.argtypes = [
|
||||
@ -206,6 +224,38 @@ def build_native(ctx, argv, success):
|
||||
success[0] = ctypes.c_int(1)
|
||||
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):
|
||||
def setUp(self):
|
||||
self.err = ctypes.c_int()
|
||||
@ -291,6 +341,13 @@ class TestJsonnetEvaluateBindings(unittest.TestCase):
|
||||
|
||||
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):
|
||||
lib.jsonnet_destroy(self.vm)
|
||||
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"unsafe"
|
||||
|
||||
"github.com/google/go-jsonnet"
|
||||
@ -25,6 +26,33 @@ type jsonValue struct {
|
||||
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 versionString *C.char
|
||||
|
||||
@ -219,6 +247,16 @@ func jsonnet_native_callback(vmRef *C.struct_JsonnetVm, name *C.char, cb *C.Json
|
||||
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
|
||||
func jsonnet_json_extract_string(vmRef *C.struct_JsonnetVm, json *C.struct_JsonnetJsonValue) *C.char {
|
||||
v := getJSONValue(json)
|
||||
|
@ -24,3 +24,18 @@ struct JsonnetJsonValue* jsonnet_internal_execute_native(JsonnetNativeCallback *
|
||||
void *ctx,
|
||||
const struct JsonnetJsonValue *const *argv,
|
||||
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);
|
||||
}
|
||||
|
||||
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() {
|
||||
fputs("TODO, NOT IMPLEMENTED YET\n", stderr);
|
||||
abort();
|
||||
|
Loading…
Reference in New Issue
Block a user