feat: cli enclave build (#137)

This commit is contained in:
Daniel Gushchyan 2024-08-02 12:19:07 -07:00 committed by GitHub
parent eb90043172
commit 3f1cd0b463
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 130 additions and 15 deletions

View file

@ -10,7 +10,7 @@ keywords = ["blockchain", "cosmos", "tendermint", "cycles", "quartz"]
readme = "README.md"
[dependencies]
clap.workspace = true
clap = { workspace = true, features=["env"] }
color-eyre.workspace = true
displaydoc.workspace = true
serde.workspace = true

View file

@ -27,6 +27,11 @@ pub struct Cli {
#[clap(flatten)]
pub verbose: Verbosity,
/// Enable mock SGX mode for testing purposes.
/// This flag disables the use of an Intel SGX processor and allows the system to run without remote attestations.
#[clap(long, env)]
pub mock_sgx: bool,
/// Main command
#[command(subcommand)]
pub command: Command,
@ -36,7 +41,27 @@ pub struct Cli {
pub enum Command {
/// Create an empty Quartz app from a template
Init {
/// path to create & init a quartz app, defaults to current path if unspecified
/// path to create & init a Quartz app, defaults to current path if unspecified
#[clap(long)]
path: Option<PathBuf>,
},
/// Subcommands for handling the Quartz app enclave
Enclave {
#[command(subcommand)]
enclave_command: EnclaveCommand,
},
}
#[derive(Debug, Clone, Subcommand)]
pub enum EnclaveCommand {
/// Build the Quartz app's enclave
Build {
/// path to Cargo.toml file of the Quartz app's enclave package, defaults to './enclave/Cargo.toml' if unspecified
#[arg(long, default_value = "./enclave/Cargo.toml")]
manifest_path: PathBuf,
},
// Run the Quartz app's enclave
Start {
#[clap(long)]
path: Option<PathBuf>,
},

View file

@ -5,4 +5,6 @@ use thiserror::Error;
pub enum Error {
/// specified path `{0}` is not a directory
PathNotDir(String),
/// {0}
GenericErr(String),
}

View file

@ -1,21 +1,23 @@
use crate::{cli::Verbosity, error::Error, request::Request, response::Response};
use crate::{error::Error, request::Request, response::Response, Config};
pub mod enclave_build;
pub mod init;
pub trait Handler {
type Error;
type Response;
fn handle(self, verbosity: Verbosity) -> Result<Self::Response, Self::Error>;
fn handle(self, config: Config) -> Result<Self::Response, Self::Error>;
}
impl Handler for Request {
type Error = Error;
type Response = Response;
fn handle(self, verbosity: Verbosity) -> Result<Self::Response, Self::Error> {
fn handle(self, config: Config) -> Result<Self::Response, Self::Error> {
match self {
Request::Init(request) => request.handle(verbosity),
Request::Init(request) => request.handle(config),
Request::EnclaveBuild(request) => request.handle(config),
}
.map(Into::into)
}

View file

@ -0,0 +1,42 @@
use std::process::Command;
use tracing::{debug, trace};
use crate::{
error::Error,
handler::Handler,
request::enclave_build::EnclaveBuildRequest,
response::{enclave_build::EnclaveBuildResponse, Response},
Config,
};
impl Handler for EnclaveBuildRequest {
type Error = Error;
type Response = Response;
fn handle(self, config: Config) -> Result<Self::Response, Self::Error> {
let mut cargo = Command::new("cargo");
let command = cargo
.args(["build", "--release"])
.args(["--manifest-path", &self.manifest_path.display().to_string()]);
if config.mock_sgx {
debug!("Building with mock-sgx enabled");
command.arg("--features=mock-sgx");
}
trace!("🚧 Building enclave ...");
let status = command
.status()
.map_err(|e| Error::GenericErr(e.to_string()))?;
if !status.success() {
return Err(Error::GenericErr(format!(
"Couldn't build enclave. {:?}",
status
)));
}
Ok(EnclaveBuildResponse.into())
}
}

View file

@ -1,15 +1,14 @@
use tracing::trace;
use crate::{
cli::Verbosity, error::Error, handler::Handler, request::init::InitRequest,
response::init::InitResponse,
error::Error, handler::Handler, request::init::InitRequest, response::Response, Config,
};
impl Handler for InitRequest {
type Error = Error;
type Response = InitResponse;
type Response = Response;
fn handle(self, _verbosity: Verbosity) -> Result<Self::Response, Self::Error> {
fn handle(self, _config: Config) -> Result<Self::Response, Self::Error> {
trace!("initializing directory structure...");
todo!()
}

View file

@ -25,6 +25,10 @@ use tracing_subscriber::{util::SubscriberInitExt, EnvFilter};
use crate::{cli::Cli, handler::Handler, request::Request};
pub struct Config {
pub mock_sgx: bool,
}
fn main() -> Result<()> {
color_eyre::install()?;
@ -48,7 +52,9 @@ fn main() -> Result<()> {
// Each `Request` defines an associated `Handler` (i.e. logic) and `Response`. All handlers are
// free to log to the terminal and these logs are sent to `stderr`.
let response = request.handle(args.verbose)?;
let response = request.handle(Config {
mock_sgx: args.mock_sgx,
})?;
// `Handlers` must use `Responses` to output to `stdout`.
println!(

View file

@ -1,10 +1,16 @@
use crate::{cli::Command, error::Error, request::init::InitRequest};
use crate::{
cli::{Command, EnclaveCommand},
error::Error,
request::{enclave_build::EnclaveBuildRequest, init::InitRequest},
};
pub mod enclave_build;
pub mod init;
#[derive(Clone, Debug)]
pub enum Request {
Init(InitRequest),
EnclaveBuild(EnclaveBuildRequest),
}
impl TryFrom<Command> for Request {
@ -12,8 +18,13 @@ impl TryFrom<Command> for Request {
fn try_from(cmd: Command) -> Result<Self, Self::Error> {
match cmd {
Command::Init { path } => InitRequest::try_from(path),
Command::Init { path } => InitRequest::try_from(path).map(Into::into),
Command::Enclave { enclave_command } => match enclave_command {
EnclaveCommand::Build { manifest_path } => {
Ok(EnclaveBuildRequest { manifest_path }.into())
}
_ => todo!(),
},
}
.map(Into::into)
}
}

View file

@ -0,0 +1,14 @@
use std::path::PathBuf;
use crate::request::Request;
#[derive(Clone, Debug)]
pub struct EnclaveBuildRequest {
pub manifest_path: PathBuf,
}
impl From<EnclaveBuildRequest> for Request {
fn from(request: EnclaveBuildRequest) -> Self {
Self::EnclaveBuild(request)
}
}

View file

@ -1,10 +1,12 @@
use serde::Serialize;
use crate::response::init::InitResponse;
use crate::response::{enclave_build::EnclaveBuildResponse, init::InitResponse};
pub mod enclave_build;
pub mod init;
#[derive(Clone, Debug, Serialize)]
pub enum Response {
Init(InitResponse),
EnclaveBuild(EnclaveBuildResponse),
}

View file

@ -0,0 +1,12 @@
use serde::Serialize;
use crate::response::Response;
#[derive(Clone, Debug, Serialize)]
pub struct EnclaveBuildResponse;
impl From<EnclaveBuildResponse> for Response {
fn from(response: EnclaveBuildResponse) -> Self {
Self::EnclaveBuild(response)
}
}