-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #26 from kcl-lang/feat-pure-rust-sdk
feat: add KCL pure rust sdk
- Loading branch information
Showing
33 changed files
with
1,641 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
name: CI | ||
on: | ||
pull_request: | ||
push: | ||
branches: | ||
- main | ||
- "releases/*" | ||
jobs: | ||
build-and-test: | ||
# Ref: https://github.com/actions/runner-images/tree/main/images/macos | ||
strategy: | ||
matrix: | ||
os: [macos-11, macos-12, ubuntu-latest, windows-latest] | ||
runs-on: ${{ matrix.os }} | ||
steps: | ||
- name: Git checkout | ||
uses: actions/checkout@v2 | ||
with: | ||
submodules: "true" | ||
|
||
- name: Install rust nightly toolchain | ||
uses: actions-rs/toolchain@v1 | ||
with: | ||
toolchain: 1.73 | ||
override: true | ||
components: clippy, rustfmt | ||
- name: Set up Go | ||
uses: actions/setup-go@v2 | ||
with: | ||
go-version: 1.19 | ||
|
||
- name: Rust code test | ||
run: cargo test | ||
- name: Go code test | ||
run: go test ./... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
name: "CLA Assistant" | ||
on: | ||
issue_comment: | ||
types: [created] | ||
pull_request_target: | ||
types: [opened,closed,synchronize] | ||
jobs: | ||
CLAssistant: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: "CLA Assistant" | ||
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target' | ||
uses: contributor-assistant/[email protected] | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
# the below token should have repo scope and must be manually added by you in the repository's secret | ||
PERSONAL_ACCESS_TOKEN : ${{ secrets.DEPLOY_ACCESS_TOKEN }} | ||
with: | ||
path-to-document: 'https://github.com/kcl-lang/.github/blob/main/CLA.md' # e.g. a CLA or a DCO document | ||
|
||
# branch should not be protected | ||
lock-pullrequest-aftermerge: True | ||
path-to-signatures: 'signatures/version1/cla.json' | ||
remote-organization-name: kcl-lang | ||
remote-repository-name: cla.db | ||
branch: 'main' | ||
allowlist: bot* | ||
|
||
#below are the optional inputs - If the optional inputs are not given, then default values will be taken | ||
#remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository) | ||
#remote-repository-name: enter the remote repository name where the signatures should be stored (Default is storing the signatures in the same repository) | ||
#create-file-commit-message: 'For example: Creating file for storing CLA Signatures' | ||
#signed-commit-message: 'For example: $contributorName has signed the CLA in #$pullRequestNo' | ||
#custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign' | ||
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA' | ||
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.' | ||
#lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true) | ||
#use-dco-flag: true - If you are using DCO instead of CLA |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[package] | ||
name = "kcl-lang" | ||
version = "0.7.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
prost = "0.11.8" | ||
prost-types = "0.11.8" | ||
serde_json = "1" | ||
anyhow = "1" | ||
serde = { version = "1", features = ["derive"] } | ||
libloading = "0.7.3" | ||
tempfile = "3.5.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,52 @@ | ||
# kcl-artifact-go | ||
# KCL Artifact for SDKs | ||
|
||
Embed kcl artifact for go | ||
## Rust | ||
|
||
### How to Use | ||
|
||
```shell | ||
cargo add kcl | ||
``` | ||
|
||
Write the Code | ||
|
||
```rust | ||
use kcl_lang::*; | ||
use std::path::Path; | ||
use anyhow::Result; | ||
|
||
fn main() -> Result<()> { | ||
let api = API::new()?; | ||
let args = &ExecProgramArgs { | ||
work_dir: Path::new(".").join("src").join("testdata").canonicalize().unwrap().display().to_string(), | ||
k_filename_list: vec!["test.k".to_string()], | ||
..Default::default() | ||
}; | ||
let exec_result = api.exec_program(args)?; | ||
assert_eq!(exec_result.yaml_result, "alice:\n age: 18"); | ||
Ok(()) | ||
} | ||
``` | ||
|
||
## Go | ||
|
||
### How to Use | ||
|
||
```shell | ||
go get kcl-lang.io/kcl-artifact-go | ||
``` | ||
|
||
Write the Code | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
artifact "kcl-lang.io/kcl-artifact-go" | ||
) | ||
|
||
func main() { | ||
path = "path/to/install" | ||
_ := artifact.InstallKclvm(path) | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# KCL Rust SDK | ||
|
||
KCL Rust SDK | ||
|
||
### How to Use | ||
|
||
```shell | ||
cargo add kcl | ||
``` | ||
|
||
Write the Code | ||
|
||
```rust | ||
use kcl_lang::*; | ||
use std::path::Path; | ||
use anyhow::Result; | ||
|
||
fn main() -> Result<()> { | ||
// File case | ||
let api = API::new()?; | ||
let args = &ExecProgramArgs { | ||
work_dir: Path::new(".").join("src").join("testdata").canonicalize().unwrap().display().to_string(), | ||
k_filename_list: vec!["test.k".to_string()], | ||
..Default::default() | ||
}; | ||
let exec_result = api.exec_program(args)?; | ||
assert_eq!(exec_result.yaml_result, "alice:\n age: 18"); | ||
Ok(()) | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
mod service; | ||
mod spec; | ||
use crate::bootstrap::{install_kclvm, lib_full_name}; | ||
use anyhow::Result; | ||
use prost::Message; | ||
use serde::de::DeserializeOwned; | ||
pub use service::Service; | ||
use service::ServiceHandler; | ||
pub use spec::*; | ||
use std::{ | ||
ffi::{c_char, CStr, CString}, | ||
sync::Mutex, | ||
}; | ||
use tempfile::TempDir; | ||
|
||
#[derive(Debug)] | ||
pub struct API { | ||
caller: Caller, | ||
} | ||
|
||
#[derive(Debug)] | ||
struct Caller { | ||
_dir: TempDir, | ||
lib: libloading::Library, | ||
mutex: Mutex<i32>, | ||
handler: *mut ServiceHandler, | ||
} | ||
|
||
impl Caller { | ||
fn new() -> Result<Self> { | ||
unsafe { | ||
let root = tempfile::tempdir()?; | ||
install_kclvm(&root)?; | ||
let lib = libloading::Library::new(&root.path().join("bin").join(lib_full_name()))?; | ||
let service_new: libloading::Symbol< | ||
unsafe extern "C" fn(plugin_agent: u64) -> *mut ServiceHandler, | ||
> = lib.get(b"kclvm_service_new")?; | ||
let handler = service_new(0); | ||
Ok(Self { | ||
_dir: root, | ||
mutex: Mutex::new(0i32), | ||
lib, | ||
handler, | ||
}) | ||
} | ||
} | ||
|
||
fn call<A, R>(&self, name: &str, args: &A) -> Result<R> | ||
where | ||
A: Message + DeserializeOwned, | ||
R: Message + Default + PartialEq + DeserializeOwned + serde::Serialize, | ||
{ | ||
let _lock = self.mutex.lock().unwrap(); | ||
let result_ptr = unsafe { | ||
let args = CString::from_vec_unchecked(args.encode_to_vec()); | ||
let call = CString::new(name)?; | ||
let service_call: libloading::Symbol< | ||
unsafe extern "C" fn( | ||
serv: *mut ServiceHandler, | ||
call: *const c_char, | ||
args: *const c_char, | ||
) -> *const c_char, | ||
> = self.lib.get(b"kclvm_service_call")?; | ||
|
||
service_call(self.handler, call.as_ptr(), args.as_ptr()) as *mut i8 | ||
}; | ||
let result = unsafe { CStr::from_ptr(result_ptr) }; | ||
match R::decode(result.to_bytes()) { | ||
Ok(result) => Ok(result), | ||
Err(_) => Err(anyhow::anyhow!(result.to_str()?.to_owned())), | ||
} | ||
} | ||
} | ||
|
||
impl Drop for Caller { | ||
fn drop(&mut self) { | ||
unsafe { | ||
let delete: libloading::Symbol<unsafe extern "C" fn(*mut ServiceHandler)> = | ||
self.lib.get(b"kclvm_service_delete").unwrap(); | ||
delete(self.handler); | ||
} | ||
} | ||
} | ||
|
||
impl API { | ||
pub fn new() -> Result<Self> { | ||
let caller = Caller::new()?; | ||
Ok(Self { caller }) | ||
} | ||
} | ||
|
||
impl Service for API { | ||
fn exec_program(&self, args: &ExecProgramArgs) -> anyhow::Result<ExecProgramResult> { | ||
self.caller.call("KclvmService.ExecProgram", args) | ||
} | ||
|
||
fn override_file(&self, args: &OverrideFileArgs) -> anyhow::Result<OverrideFileResult> { | ||
self.caller.call("KclvmService.OverrideFile", args) | ||
} | ||
|
||
fn get_full_schema_type( | ||
&self, | ||
args: &GetFullSchemaTypeArgs, | ||
) -> anyhow::Result<GetSchemaTypeResult> { | ||
self.caller.call("KclvmService.GetFullSchemaType", args) | ||
} | ||
|
||
fn format_code(&self, args: &FormatCodeArgs) -> anyhow::Result<FormatCodeResult> { | ||
self.caller.call("KclvmService.FormatCode", args) | ||
} | ||
|
||
fn format_path(&self, args: &FormatPathArgs) -> anyhow::Result<FormatPathResult> { | ||
self.caller.call("KclvmService.FormatPath", args) | ||
} | ||
|
||
fn lint_path(&self, args: &LintPathArgs) -> anyhow::Result<LintPathResult> { | ||
self.caller.call("KclvmService.LintPath", args) | ||
} | ||
|
||
fn validate_code(&self, args: &ValidateCodeArgs) -> anyhow::Result<ValidateCodeResult> { | ||
self.caller.call("KclvmService.ValidateCode", args) | ||
} | ||
|
||
fn load_settings_files( | ||
&self, | ||
args: &LoadSettingsFilesArgs, | ||
) -> anyhow::Result<LoadSettingsFilesResult> { | ||
self.caller.call("KclvmService.LoadSettingsFiles", args) | ||
} | ||
|
||
fn rename(&self, args: &RenameArgs) -> anyhow::Result<RenameResult> { | ||
self.caller.call("KclvmService.Rename", args) | ||
} | ||
|
||
fn rename_code(&self, args: &RenameCodeArgs) -> anyhow::Result<RenameCodeResult> { | ||
self.caller.call("KclvmService.RenameCode", args) | ||
} | ||
|
||
fn test(&self, args: &TestArgs) -> anyhow::Result<TestResult> { | ||
self.caller.call("KclvmService.Test", args) | ||
} | ||
} |
Oops, something went wrong.