feat: cli enclave build (#137)
This commit is contained in:
parent
eb90043172
commit
3f1cd0b463
11 changed files with 130 additions and 15 deletions
|
@ -10,7 +10,7 @@ keywords = ["blockchain", "cosmos", "tendermint", "cycles", "quartz"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap.workspace = true
|
clap = { workspace = true, features=["env"] }
|
||||||
color-eyre.workspace = true
|
color-eyre.workspace = true
|
||||||
displaydoc.workspace = true
|
displaydoc.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
|
|
|
@ -27,6 +27,11 @@ pub struct Cli {
|
||||||
#[clap(flatten)]
|
#[clap(flatten)]
|
||||||
pub verbose: Verbosity,
|
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
|
/// Main command
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
pub command: Command,
|
pub command: Command,
|
||||||
|
@ -36,8 +41,28 @@ pub struct Cli {
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
/// Create an empty Quartz app from a template
|
/// Create an empty Quartz app from a template
|
||||||
Init {
|
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)]
|
#[clap(long)]
|
||||||
path: Option<PathBuf>,
|
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>,
|
||||||
|
},
|
||||||
|
}
|
|
@ -5,4 +5,6 @@ use thiserror::Error;
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// specified path `{0}` is not a directory
|
/// specified path `{0}` is not a directory
|
||||||
PathNotDir(String),
|
PathNotDir(String),
|
||||||
|
/// {0}
|
||||||
|
GenericErr(String),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 mod init;
|
||||||
|
|
||||||
pub trait Handler {
|
pub trait Handler {
|
||||||
type Error;
|
type Error;
|
||||||
type Response;
|
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 {
|
impl Handler for Request {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type Response = Response;
|
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 {
|
match self {
|
||||||
Request::Init(request) => request.handle(verbosity),
|
Request::Init(request) => request.handle(config),
|
||||||
|
Request::EnclaveBuild(request) => request.handle(config),
|
||||||
}
|
}
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
42
cli/src/handler/enclave_build.rs
Normal file
42
cli/src/handler/enclave_build.rs
Normal 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())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,14 @@
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::Verbosity, error::Error, handler::Handler, request::init::InitRequest,
|
error::Error, handler::Handler, request::init::InitRequest, response::Response, Config,
|
||||||
response::init::InitResponse,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Handler for InitRequest {
|
impl Handler for InitRequest {
|
||||||
type Error = Error;
|
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...");
|
trace!("initializing directory structure...");
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,10 @@ use tracing_subscriber::{util::SubscriberInitExt, EnvFilter};
|
||||||
|
|
||||||
use crate::{cli::Cli, handler::Handler, request::Request};
|
use crate::{cli::Cli, handler::Handler, request::Request};
|
||||||
|
|
||||||
|
pub struct Config {
|
||||||
|
pub mock_sgx: bool,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
color_eyre::install()?;
|
color_eyre::install()?;
|
||||||
|
|
||||||
|
@ -48,7 +52,9 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
// Each `Request` defines an associated `Handler` (i.e. logic) and `Response`. All handlers are
|
// 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`.
|
// 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`.
|
// `Handlers` must use `Responses` to output to `stdout`.
|
||||||
println!(
|
println!(
|
||||||
|
|
|
@ -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;
|
pub mod init;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Request {
|
pub enum Request {
|
||||||
Init(InitRequest),
|
Init(InitRequest),
|
||||||
|
EnclaveBuild(EnclaveBuildRequest),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Command> for Request {
|
impl TryFrom<Command> for Request {
|
||||||
|
@ -12,8 +18,13 @@ impl TryFrom<Command> for Request {
|
||||||
|
|
||||||
fn try_from(cmd: Command) -> Result<Self, Self::Error> {
|
fn try_from(cmd: Command) -> Result<Self, Self::Error> {
|
||||||
match cmd {
|
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
cli/src/request/enclave_build.rs
Normal file
14
cli/src/request/enclave_build.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,12 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::response::init::InitResponse;
|
use crate::response::{enclave_build::EnclaveBuildResponse, init::InitResponse};
|
||||||
|
|
||||||
|
pub mod enclave_build;
|
||||||
pub mod init;
|
pub mod init;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
pub enum Response {
|
pub enum Response {
|
||||||
Init(InitResponse),
|
Init(InitResponse),
|
||||||
|
EnclaveBuild(EnclaveBuildResponse),
|
||||||
}
|
}
|
||||||
|
|
12
cli/src/response/enclave_build.rs
Normal file
12
cli/src/response/enclave_build.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue