Skip to content

Commit

Permalink
Merge pull request #141 from Web3-Builders-Alliance/main
Browse files Browse the repository at this point in the history
  • Loading branch information
JuanMarchetto authored Jul 25, 2023
2 parents f944667 + b6c8c5d commit 807aa41
Show file tree
Hide file tree
Showing 241 changed files with 8,866 additions and 2,280 deletions.
63 changes: 33 additions & 30 deletions README.MD
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
<p align="center">
<img src="https://github.com/Web3-Builders-Alliance/soda/blob/main/ui/src-tauri/icons/icon.png?raw=true" width="100">
</p>
<p align="center">
<img src="https://github.com/Web3-Builders-Alliance/soda/blob/main/assets/soda.png?raw=true" width="200">
</p>

# SODA: Ship a Solana program inferred from Solana data.
# Ship a Solana program inferred from Solana data

A tool for Solana development and audit that allows you to automate tasks and build Solana programs and clients from: IDLs, on-chain data, existing repos, input and output examples of each instruction, and naming conventions, among other possible resources.
From an IDL to whatever you want.

**Note: Soda is in active development, so all is subject to change. This code is unaudited. Use at your own risk.**

---
### Current Features

- **Generate Solana Program and client from IDL.**
- **Write, read and edit IDL in a desktop UI.**
- **Template based: create your custom building blocks.**
- **Lang and chain agnostic.**
- Generate Solana Programs and clients' source code from an IDL
- Write, read and edit IDL in a desktop UI
- Template based:
- Create your custom building blocks
- Handlebars with Rhai scripting available
- Common helpers added by default
- Custom helpers support
- Binary Files support
- Filesystem based and dynamic paths
- Lang agnostic
- Interconvertible portable template file format and template folder, both supported by CLI and Desktop App
- Available Templates:
- Anchor Program With a NextJs-Tailwind Client (Used as default in Desktop App)
- Seahorse Program (experimental)
- React Native Client (experimental)

## Install Soda Desktop


To install the Desktop App you need to [download the lastest release](https://github.com/Web3-Builders-Alliance/soda/releases)

(Optionally you can download templates.zip file if you want to use other templates than the default one, or just clone this repo an use it from the templates folder)

**Provisional Steps:** We are still working in add code signing in our app so at this point a security warning probably will show up. Until we finish the code signing process you will need to check how to open the app in your OS.

## Install Soda CLI

You can install the CLI using cargo or npm.

- Using cargo:
- Using cargo (recommended):
```cargo install soda-cli```

- Using npm:
Expand All @@ -31,28 +46,16 @@ You can install the CLI using cargo or npm.
#### CLI Usage

```soda-cli create-project <idl_path> <template_path>```

creates a new project from an IDL file.
If no template path is provided, the project will be try to use a template.soda file in the current directory.
Creates a new project from an IDL file.
If no template path is provided, the project will try to use a template.soda file in the current directory.
If no IDL path is provided, the CLI will try to open an idl.json file in the current directory.

```soda-cli pack-template <template_path> <output_path>```

creates a template file from a template folder.
Creates a template file from a template folder.
If no output path is provided, the template will be created in the current directory with the name template.soda
if no template path is provided, the CLI will try to read from a template folder in the current directory.

```soda-cli unpack-template <template_path> <output_path>```

creates a template folder from a template file.
Creates a template folder from a template file.
If no output path is provided, the template folder will be created in the current directory with the name template.
if no template path is provided, the CLI will try to read from a template.soda file in the current directory.

## Note

Soda is in active development, so all is subject to change.
This code is unaudited.
Use at your own risk.

## Powered by
![The Solana Foundation](https://github.com/Web3-Builders-Alliance/soda/blob/main/ui/public/solana.svg?raw=true)
If no template path is provided, the CLI will try to read from a template.soda file in the current directory.
Binary file added assets/soda.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions cli/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
[package]
name = "soda-cli"
version = "0.0.5"
version = "0.1.1"
edition = "2021"
license = "Apache-2.0"
description = "Generates Solana Projects from an IDL"
repository = "https://github.com/Web3-Builders-Alliance/soda"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde_json = "1.0.93"
clap = { version = "4.1.8", features = ["derive"] }
soda_sol = "0.0.5"
soda_sol = "0.0.6"
2 changes: 1 addition & 1 deletion cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@use_soda/soda-cli",
"version": "0.0.5",
"version": "0.1.1",
"description": "Generates Solana Projects from an IDL",
"main": "start.js",
"directories": {
Expand Down
4 changes: 2 additions & 2 deletions cli/pre-install.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ if (fs.existsSync(cargoDir)) {

const features = process.env.npm_config_features ? `--features ${process.env.npm_config_features.replace(",", " ")}` : "";

console.log(`Installing and compiling soda-cli 0.0.5 ${features} ...`);
exec(`cargo install soda-cli --vers 0.0.5 ${features}`, (error, stdout, stderr) => {
console.log(`Installing and compiling soda-cli 0.1.1 ${features} ...`);
exec(`cargo install soda-cli --vers 0.1.1 ${features}`, (error, stdout, stderr) => {
console.log(stdout);
if (error || stderr) {
console.log(error || stderr);
Expand Down
23 changes: 11 additions & 12 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ fn main() -> Result<(), Box<dyn Error>> {
} else {
TEMPLATE_FILE_NAME
};
let template = get_template_from_fs(template_path).unwrap();
save_template(template, file_path).unwrap();
let template = get_template_from_fs(template_path)?;
save_template(template, file_path)?;
println!("Template File Generated!");
}
command if command == "unpack-template" => {
Expand All @@ -45,20 +45,19 @@ fn main() -> Result<(), Box<dyn Error>> {
} else {
TEMPLATE_DEFAULT_PATH
};
let template = load_template(template_path).unwrap();
write_project_to_fs(template.files, &format!("{}/files", base_path)).unwrap();
let template = load_template(template_path)?;
write_project_to_fs(template.files, &format!("{}/files", base_path))?;
let mut helpers = vec![];
for helper in template.helpers {
helpers.push(TemplateFile {
path: format!("helpers/{}.rhai", helper.helper_name),
content: Content::String(helper.script),
});
}
write_project_to_fs(helpers, base_path).unwrap();
let metadata = serde_json::to_string(&template.metadata).unwrap();
let mut metadata_file =
File::create(format!("{}/metadata.json", base_path)).unwrap();
metadata_file.write_all(metadata.as_bytes()).unwrap();
write_project_to_fs(helpers, base_path)?;
let metadata = serde_json::to_string(&template.metadata)?;
let mut metadata_file = File::create(format!("{}/metadata.json", base_path))?;
metadata_file.write_all(metadata.as_bytes())?;
println!("Template Unpacked!");
}
command if command == "create-project" => {
Expand All @@ -72,10 +71,10 @@ fn main() -> Result<(), Box<dyn Error>> {
} else {
TEMPLATE_FILE_NAME
};
let json_file_path = canonicalize(idl_path).unwrap();
let file = File::open(json_file_path).unwrap();
let json_file_path = canonicalize(idl_path)?;
let file = File::open(json_file_path)?;
let idl: IDL = serde_json::from_reader(file).expect("error while reading json");
generate_from_idl(".", idl, template_path).unwrap();
generate_from_idl(".", idl, template_path)?;
println!("Project Generated!");
}
_ => {
Expand Down
2 changes: 1 addition & 1 deletion crate/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crate/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
[package]
name = "soda_sol"
version = "0.0.5"
version = "0.0.6"
edition = "2021"
license = "Apache-2.0"
description = "Generates Solana Projects from an IDL"
repository = "https://github.com/Web3-Builders-Alliance/soda"
documentation = "https://docs.rs/soda_sol/latest/soda_sol/"
authors = ["Juan Patricio Marchetto"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
90 changes: 90 additions & 0 deletions crate/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use std::sync::{MutexGuard, PoisonError};

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("soda_sol crate error: {message}")]
CustomError { message: String },
}
#[derive(serde::Serialize, serde::Deserialize)]
struct ErrorWrapper {
error: String,
}
impl serde::Serialize for Error {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
let error_message = match self {
Error::CustomError { message } => message,
};
let wrapper = ErrorWrapper {
error: error_message.to_string(),
};
wrapper.serialize(serializer)
}
}

impl<'de> serde::Deserialize<'de> for Error {
fn deserialize<D>(deserializer: D) -> Result<Error, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let wrapper = ErrorWrapper::deserialize(deserializer)?;
Ok(Error::CustomError {
message: wrapper.error,
})
}
}

impl From<bincode::Error> for Error {
fn from(err: bincode::Error) -> Error {
Error::CustomError {
message: err.to_string(),
}
}
}

impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Error {
Error::CustomError {
message: err.to_string(),
}
}
}

impl From<Result<(), std::io::Error>> for Error {
fn from(err: Result<(), std::io::Error>) -> Error {
match err {
Ok(_) => Error::CustomError {
message: "no error".to_string(),
},
Err(err) => Error::CustomError {
message: err.to_string(),
},
}
}
}

impl From<serde_json::Error> for Error {
fn from(err: serde_json::Error) -> Error {
Error::CustomError {
message: err.to_string(),
}
}
}

impl From<handlebars::RenderError> for Error {
fn from(err: handlebars::RenderError) -> Error {
Error::CustomError {
message: err.to_string(),
}
}
}

impl<T> From<PoisonError<MutexGuard<'_, T>>> for Error {
fn from(err: PoisonError<MutexGuard<'_, T>>) -> Error {
Error::CustomError {
message: err.to_string(),
}
}
}
12 changes: 12 additions & 0 deletions crate/src/generate_from_idl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use crate::*;
use std::path::PathBuf;

pub fn generate_from_idl(base_path: &str, idl: IDL, template_path: &str) -> Result<(), Error> {
let template = if PathBuf::from(template_path).is_file() {
load_template(template_path)?
} else {
get_template_from_fs(template_path)?
};
let dinamyc_files = generate_project(template, &idl)?;
write_project_to_fs(dinamyc_files, base_path)
}
Loading

0 comments on commit 807aa41

Please sign in to comment.