-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Client] Add support for zig
client library
#160
base: main
Are you sure you want to change the base?
Changes from 8 commits
2f7a514
036f2be
7914620
8a9e609
c4f9f63
09f46ee
8633683
3f28831
0da9798
9f9d84c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.zig-cache/* | ||
zig-out/* |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
|
||
|
||
.PHONY: test coverage run run-ex build-ex | ||
|
||
|
||
test: test-cac test-expt | ||
|
||
test-cac: | ||
zig test -I../../headers -lc src/cac.zig ../../target/debug/libcac_client.so | ||
|
||
test-expt: | ||
zig test -I../../headers -lc src/expt.zig ../../target/debug/libexperimentation_client.so | ||
|
||
|
||
run-ex: build-ex | ||
./zig-out/bin/cli | ||
|
||
build-ex: | ||
zig build | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
### Pauli | ||
|
||
A zig based client SDK for [`superposition`](https://github.com/juspay/superposition) service. | ||
|
||
### Pre-requisites | ||
|
||
- As this client leverages `build.zig.zon` file for managing dependencies. Your zig version should atleast satisfy the minimum version mentioned in the `build.zig.zon` file. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @NishantJoshi00 can we include some usage examples too? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is part of the |
||
- You should have `superposition` service running on your local machine or on a remote server. (This is optional in the initial development phase, but might be required for testing) | ||
- The build steps consist of the following steps: | ||
- Pulling the superposition repository, this implies that you have `git` installed on your machine and you have access to the repository. | ||
- This is followed by the build stage of `superposition`. (required to get the shared library) `rust` and `cargo` should be installed on your machine for this stage to complete. | ||
|
||
### Get Started | ||
|
||
- To get started with the client, create your own zig project: | ||
```bash | ||
mkdir my_project | ||
cd my_project | ||
zig init-exe | ||
``` | ||
- To install the client as a dependency run the following command: | ||
```bash | ||
zig fetch --save <url/path> | ||
``` | ||
Here, the URL can be the place where the zig client is hosted or the path to the client on your local machine. | ||
The url/path should allow the zig build system to discover the `build.zig.zon` file and the paths included within it. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
const std = @import("std"); | ||
|
||
// Although this function looks imperative, note that its job is to | ||
// declaratively construct a build graph that will be executed by an external | ||
// runner. | ||
pub fn build(b: *std.Build) void { | ||
const target = b.standardTargetOptions(.{}); | ||
|
||
const optimize = b.standardOptimizeOption(.{}); | ||
|
||
const superposition = buildSuperpositionClient(b); | ||
|
||
const lib = b.addStaticLibrary(.{ | ||
.name = "pauli", | ||
.root_source_file = b.path("src/root.zig"), | ||
.target = target, | ||
.optimize = optimize, | ||
}); | ||
|
||
lib.step.dependOn(&superposition.step); | ||
|
||
linkBindingsDebug(b, lib); | ||
|
||
b.installArtifact(lib); | ||
|
||
// Tests section | ||
|
||
const test_step = b.step("test", "Run unit tests"); | ||
|
||
// Root Tests | ||
|
||
const lib_unit_tests = b.addTest(.{ | ||
.root_source_file = b.path("src/root.zig"), | ||
.target = target, | ||
.optimize = optimize, | ||
}); | ||
|
||
lib_unit_tests.step.dependOn(&superposition.step); | ||
|
||
linkBindingsDebug(b, lib_unit_tests); | ||
|
||
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); | ||
test_step.dependOn(&run_lib_unit_tests.step); | ||
|
||
const module = b.addModule("pauli", .{ | ||
.root_source_file = b.path("src/root.zig"), | ||
.target = target, | ||
.optimize = optimize, | ||
}); | ||
|
||
module.linkLibrary(lib); | ||
|
||
module.addIncludePath(b.path("superposition/headers")); | ||
module.addLibraryPath(b.path("superposition/target/release")); | ||
|
||
module.linkSystemLibrary("c", .{}); | ||
|
||
module.linkSystemLibrary("cac_client", .{}); | ||
module.linkSystemLibrary("experimentation_client", .{}); | ||
} | ||
|
||
fn linkBindingsDebug(b: *std.Build, c: *std.Build.Step.Compile) void { | ||
c.addIncludePath(b.path("superposition/headers")); | ||
c.addLibraryPath(b.path("superposition/target/release")); | ||
|
||
c.linkLibC(); | ||
c.linkSystemLibrary("cac_client"); | ||
c.linkSystemLibrary("experimentation_client"); | ||
} | ||
|
||
fn buildSuperpositionClient(b: *std.Build) *std.Build.Step.Run { | ||
const repository = b.addSystemCommand(&.{ | ||
"sh", "-c", std.fmt.comptimePrint( | ||
\\if [ ! -d superposition ]; then | ||
\\ git clone https://github.com/juspay/superposition.git | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How do we avoid this clone? Can you link to the libraries in target directory in the parent folder? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think when using this client as a dependency, we need some mechanism to be able to link the library, header files. By, doing this I don't need to worry about if you have the I think one possible fix might be to only build the client crates, while not touching the others. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah you can only build the clients rather than the whole project |
||
\\fi | ||
, .{}), | ||
}); | ||
|
||
const rust_build = b.addSystemCommand(&.{ "cargo", "build", "--release" }); | ||
|
||
rust_build.setCwd(b.path("superposition")); | ||
|
||
rust_build.step.dependOn(&repository.step); | ||
|
||
return rust_build; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
.{ | ||
// This is the default name used by packages depending on this one. For | ||
// example, when a user runs `zig fetch --save <url>`, this field is used | ||
// as the key in the `dependencies` table. Although the user can choose a | ||
// different name, most users will stick with this provided value. | ||
// | ||
// It is redundant to include "zig" in this name because it is already | ||
// within the Zig package namespace. | ||
.name = "pauli", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @NishantJoshi00 , what is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we have a generic name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sure, I started of with this, will change that |
||
|
||
// This is a [Semantic Version](https://semver.org/). | ||
// In a future version of Zig it will be used for package deduplication. | ||
.version = "0.0.0", | ||
|
||
// This field is optional. | ||
// This is currently advisory only; Zig does not yet do anything | ||
// with this value. | ||
//.minimum_zig_version = "0.11.0", | ||
NishantJoshi00 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// This field is optional. | ||
// Each dependency must either provide a `url` and `hash`, or a `path`. | ||
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively. | ||
// Once all dependencies are fetched, `zig build` no longer requires | ||
// internet connectivity. | ||
.dependencies = .{ | ||
// See `zig fetch --save <url>` for a command-line interface for adding dependencies. | ||
//.example = .{ | ||
// // When updating this field to a new URL, be sure to delete the corresponding | ||
// // `hash`, otherwise you are communicating that you expect to find the old hash at | ||
// // the new URL. | ||
// .url = "https://example.com/foo.tar.gz", | ||
// | ||
// // This is computed from the file contents of the directory of files that is | ||
// // obtained after fetching `url` and applying the inclusion rules given by | ||
// // `paths`. | ||
// // | ||
// // This field is the source of truth; packages do not come from a `url`; they | ||
// // come from a `hash`. `url` is just one of many possible mirrors for how to | ||
// // obtain a package matching this `hash`. | ||
// // | ||
// // Uses the [multihash](https://multiformats.io/multihash/) format. | ||
// .hash = "...", | ||
// | ||
// // When this is provided, the package is found in a directory relative to the | ||
// // build root. In this case the package's hash is irrelevant and therefore not | ||
// // computed. This field and `url` are mutually exclusive. | ||
// .path = "foo", | ||
|
||
// // When this is set to `true`, a package is declared to be lazily | ||
// // fetched. This makes the dependency only get fetched if it is | ||
// // actually used. | ||
// .lazy = false, | ||
//}, | ||
}, | ||
|
||
// Specifies the set of files and directories that are included in this package. | ||
// Only files and directories listed here are included in the `hash` that | ||
// is computed for this package. Only files listed here will remain on disk | ||
// when using the zig package manager. As a rule of thumb, one should list | ||
// files required for compilation plus any license(s). | ||
// Paths are relative to the build root. Use the empty string (`""`) to refer to | ||
// the build root itself. | ||
// A directory listed here means that all files within, recursively, are included. | ||
.paths = .{ | ||
"build.zig", | ||
"build.zig.zon", | ||
"src", | ||
// For example... | ||
//"LICENSE", | ||
"README.md", | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.zig-cache/* | ||
zig-out/* |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
const std = @import("std"); | ||
|
||
// Although this function looks imperative, note that its job is to | ||
// declaratively construct a build graph that will be executed by an external | ||
// runner. | ||
pub fn build(b: *std.Build) void { | ||
// Standard target options allows the person running `zig build` to choose | ||
// what target to build for. Here we do not override the defaults, which | ||
// means any target is allowed, and the default is native. Other options | ||
// for restricting supported target set are available. | ||
const target = b.standardTargetOptions(.{}); | ||
|
||
// Standard optimization options allow the person running `zig build` to select | ||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not | ||
// set a preferred release mode, allowing the user to decide how to optimize. | ||
const optimize = b.standardOptimizeOption(.{}); | ||
|
||
const package = b.dependency("pauli", .{ | ||
.target = target, | ||
.optimize = optimize, | ||
}); | ||
|
||
const module = package.module("pauli"); | ||
|
||
const exe = b.addExecutable(.{ | ||
.name = "example", | ||
.root_source_file = b.path("src/main.zig"), | ||
.target = target, | ||
.optimize = optimize, | ||
}); | ||
|
||
exe.root_module.addImport("pauli", module); | ||
|
||
// This declares intent for the executable to be installed into the | ||
// standard location when the user invokes the "install" step (the default | ||
// step when running `zig build`). | ||
b.installArtifact(exe); | ||
|
||
// This *creates* a Run step in the build graph, to be executed when another | ||
// step is evaluated that depends on it. The next line below will establish | ||
// such a dependency. | ||
const run_cmd = b.addRunArtifact(exe); | ||
|
||
// By making the run step depend on the install step, it will be run from the | ||
// installation directory rather than directly from within the cache directory. | ||
// This is not necessary, however, if the application depends on other installed | ||
// files, this ensures they will be present and in the expected location. | ||
run_cmd.step.dependOn(b.getInstallStep()); | ||
|
||
// This allows the user to pass arguments to the application in the build | ||
// command itself, like this: `zig build run -- arg1 arg2 etc` | ||
if (b.args) |args| { | ||
run_cmd.addArgs(args); | ||
} | ||
|
||
// This creates a build step. It will be visible in the `zig build --help` menu, | ||
// and can be selected like this: `zig build run` | ||
// This will evaluate the `run` step rather than the default, which is "install". | ||
const run_step = b.step("run", "Run the app"); | ||
run_step.dependOn(&run_cmd.step); | ||
|
||
const exe_unit_tests = b.addTest(.{ | ||
.root_source_file = b.path("src/main.zig"), | ||
.target = target, | ||
.optimize = optimize, | ||
}); | ||
|
||
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests); | ||
|
||
// Similar to creating the run step earlier, this exposes a `test` step to | ||
// the `zig build --help` menu, providing a way for the user to request | ||
// running the unit tests. | ||
const test_step = b.step("test", "Run unit tests"); | ||
test_step.dependOn(&run_exe_unit_tests.step); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
.{ | ||
// This is the default name used by packages depending on this one. For | ||
// example, when a user runs `zig fetch --save <url>`, this field is used | ||
// as the key in the `dependencies` table. Although the user can choose a | ||
// different name, most users will stick with this provided value. | ||
// | ||
// It is redundant to include "zig" in this name because it is already | ||
// within the Zig package namespace. | ||
.name = "example", | ||
|
||
// This is a [Semantic Version](https://semver.org/). | ||
// In a future version of Zig it will be used for package deduplication. | ||
.version = "0.0.0", | ||
|
||
// This field is optional. | ||
// This is currently advisory only; Zig does not yet do anything | ||
// with this value. | ||
//.minimum_zig_version = "0.11.0", | ||
|
||
// This field is optional. | ||
// Each dependency must either provide a `url` and `hash`, or a `path`. | ||
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively. | ||
// Once all dependencies are fetched, `zig build` no longer requires | ||
// internet connectivity. | ||
.dependencies = .{ | ||
.pauli = .{ | ||
.url = "../", | ||
.hash = "12206eb33ebbd1b0936dcb84d44460da9a863150e60e2432cef3ddf3fb6fd75a2f09", | ||
}, | ||
}, | ||
.paths = .{ | ||
"build.zig", | ||
"build.zig.zon", | ||
"src", | ||
// For example... | ||
//"LICENSE", | ||
//"README.md", | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
const cac_client = @import("pauli").cac; | ||
const std = @import("std"); | ||
|
||
pub fn main() !void { | ||
var logging_alloc = std.heap.loggingAllocator(std.heap.page_allocator); | ||
const alloc = logging_alloc.allocator(); | ||
|
||
const setup_config = cac_client.SetupConfig{ .tenant = "public", .update_frequency = 10, .hostname = "http://localhost:8080" }; | ||
NishantJoshi00 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
const client = try cac_client.Client.init(setup_config); | ||
|
||
std.log.info("Client Initialized", .{}); | ||
|
||
const input = [_][]const u8{"test"}; | ||
|
||
const config = struct { test_2: u8 }; | ||
|
||
const output_1 = try client.getDefaultConfig(config, alloc, &input); | ||
std.log.info("Output: {}", .{output_1}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NishantJoshi00 few things here:
If any support is needed from Superposition, we can add this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is no longer required, I was using this initially to test it. Will remove this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the libs and headers are figured out in build by build.zig