Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions lua/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,29 +43,40 @@ Use `luarocks` to build the library and install it for your current Lua version:
luarocks --local make
```

If you need to re-generate the protobuf spec files, run:

```bash
luajit hack/generate_pb.lua
```

## Usage

### Basic Usage

The KCL Lua library provides two main functions for working with KCL configurations:

```lua
local kcl = require("kcl_lib")
local api = require("kcl_lib.api")

-- Execute a single KCL file
local result = assert(kcl.run("./config/schema.k"))
print("Configuration result:", result.yaml_result)
local result = api:run("./config/schema.k")
print("Configuration result:", result:yaml())

-- Execute multiple KCL files
local result = assert(kcl.run({
local result = api:run({
"./config/schema.k",
"./config/data.k"
}))
print("Combined configuration:", result.yaml_result)
})
print("Combined configuration:", result:json())

-- Using the raw API to the native service
local raw_api = require("kcl_lib.raw_api")

-- Format a KCL file
local formatted_files = assert(kcl.format("./config/unordered.k"))
print("Formatted files:", table.concat(formatted_files, ", "))
-- Perform a call to a native service function
local result = raw_api:exec_program({
k_filename_list = { "./config/schema.k" },
})
print("Configuration result", result.yaml_result)
```

## Development
Expand Down
18 changes: 18 additions & 0 deletions lua/hack/generate_pb.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
local io = require("io")

local protoc = require("protoc")

local function main()
local p = protoc.new()
p.proto3_optional = true
local fh = assert(io.open("../spec/spec.proto", "r"))
local content = fh:read("*a")
fh:close()
local dump = p:compile(content, "spec.proto")
fh = assert(io.open("./kcl_lib/schema.lua", "w"))
assert(fh:write("return "))
assert(fh:write(string.format("%q", dump)))
fh:close()
end

main()
8 changes: 8 additions & 0 deletions lua/kcl_lib-0.12.3-1.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ description = {
dependencies = {
"lua >= 5.1",
"luarocks-build-rust-mlua = 0.2.0",
"lua-protobuf >= 0.5",
"dkjson >= 2.9",
}
test_dependencies = {
"busted >= 2.2",
Expand All @@ -32,4 +34,10 @@ build = {
["kcl_lib"] = "kcl_lib_lua",
},
target_path = "target",
include = {
"api.lua",
"raw_api.lua",
"types.lua",
"schema.lua",
},
}
34 changes: 34 additions & 0 deletions lua/kcl_lib/api.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
local api = require("kcl_lib.raw_api")
local types = require("kcl_lib.types")

---@class kcl_lib.API
---@field private raw kcl_lib.RawAPI The object to access the raw API.
local API = {}

---Create a new API object.
---@return kcl_lib.RawAPI
function API:new()
local o = {
raw = api,
}
setmetatable(o, self)
self.__index = self
o.overrides = {}
return o
end

---Run a KCL program or set of programs and its output.
---@param file string|string[] The file or list of files to run.
---@return kcl_lib.types.RunResponse
function API:run(file)
if type(file) == "string" then
file = { file }
end
local args = {
k_filename_list = file,
}
local res = self.raw:exec_program(args)
return types.RunResponse:from_exec_program_result(res)
end

return API:new()
53 changes: 53 additions & 0 deletions lua/kcl_lib/raw_api.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
local kcl_lib = require("kcl_lib")
local schema = require("kcl_lib.schema")

---@class kcl_lib.RawAPI
local RawAPI = {}

---Create a new API object.
---@return kcl_lib.RawAPI
function RawAPI:new()
local pb = require("pb")
pb.clear()
assert(pb.load(schema))
local o = {
pb = pb,
client = assert(kcl_lib.new_client(), "failed to create native KCL client"),
}
setmetatable(o, self)
self.__index = self
o.overrides = {}
return o
end

---Add a method to the raw API.
---@param name string The KCL service function name to call.
---@param arg_name string The name of the argument type that the method accepts.
---@param return_name string The name of the return type that the method returns.
---@return function
local function add_method(name, arg_name, return_name)
return function(self, args)
local arg_type = ".com.kcl.api." .. arg_name
args = assert(
self.pb.encode(arg_type, args),
"failed to encode argument into " .. arg_type
)
local res = assert(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that I use very defensive programming here. This might not be desired if you want to propagate errors to the users. I currently implemented this so that the errors are easier to pin-point.

self.client:call(name, args),
"failed to perform native call for method " .. name
)
local return_type = ".com.kcl.api." .. return_name
return assert(
self.pb.decode(return_type, res),
"failed to decode buffer into " .. return_type
)
end
end

RawAPI.exec_program =
add_method("KclService.ExecProgram", "ExecProgramArgs", "ExecProgramResult")

RawAPI.format_path =
add_method("KclService.FormatPath", "FormatPathArgs", "FormatPathResult")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional functions can be added by a single line like this in the future. I will do this in a second PR if this is accepted to support all the functions in the SDK.


return RawAPI:new()
Loading
Loading