feat: with compose
This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -938,9 +938,9 @@ checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.9"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
|
checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1349,9 +1349,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_users"
|
name = "redox_users"
|
||||||
version = "0.5.2"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.16",
|
"getrandom 0.2.16",
|
||||||
"libredox",
|
"libredox",
|
||||||
|
@@ -35,9 +35,37 @@ pub struct Project {
|
|||||||
#[prost(string, tag = "2")]
|
#[prost(string, tag = "2")]
|
||||||
pub image: ::prost::alloc::string::String,
|
pub image: ::prost::alloc::string::String,
|
||||||
#[prost(string, tag = "3")]
|
#[prost(string, tag = "3")]
|
||||||
|
#[prost(uint32, optional, tag="2")]
|
||||||
|
pub port: ::core::option::Option<u32>,
|
||||||
|
#[prost(oneof="project::ProjectType", tags="3, 4")]
|
||||||
|
pub project_type: ::core::option::Option<project::ProjectType>,
|
||||||
|
}
|
||||||
|
/// Nested message and enum types in `Project`.
|
||||||
|
pub mod project {
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||||
|
pub enum ProjectType {
|
||||||
|
#[prost(message, tag="3")]
|
||||||
|
Container(super::Container),
|
||||||
|
#[prost(message, tag="4")]
|
||||||
|
Compose(super::Compose),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Container {
|
||||||
|
#[prost(string, tag="1")]
|
||||||
|
pub image: ::prost::alloc::string::String,
|
||||||
|
#[prost(string, tag="2")]
|
||||||
pub version: ::prost::alloc::string::String,
|
pub version: ::prost::alloc::string::String,
|
||||||
#[prost(uint32, optional, tag = "4")]
|
#[prost(uint32, optional, tag = "4")]
|
||||||
pub port: ::core::option::Option<u32>,
|
pub port: ::core::option::Option<u32>,
|
||||||
}
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct Compose {
|
||||||
|
#[prost(map="string, bytes", tag="1")]
|
||||||
|
pub files: ::std::collections::HashMap<::prost::alloc::string::String, ::prost::alloc::vec::Vec<u8>>,
|
||||||
|
}
|
||||||
include!("norun.v1.tonic.rs");
|
include!("norun.v1.tonic.rs");
|
||||||
// @@protoc_insertion_point(module)
|
// @@protoc_insertion_point(module)
|
||||||
|
@@ -4,7 +4,6 @@ pub mod registry_service_client {
|
|||||||
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
|
#![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)]
|
||||||
use tonic::codegen::*;
|
use tonic::codegen::*;
|
||||||
use tonic::codegen::http::Uri;
|
use tonic::codegen::http::Uri;
|
||||||
///
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RegistryServiceClient<T> {
|
pub struct RegistryServiceClient<T> {
|
||||||
inner: tonic::client::Grpc<T>,
|
inner: tonic::client::Grpc<T>,
|
||||||
@@ -85,7 +84,6 @@ pub mod registry_service_client {
|
|||||||
self.inner = self.inner.max_encoding_message_size(limit);
|
self.inner = self.inner.max_encoding_message_size(limit);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
///
|
|
||||||
pub async fn publish(
|
pub async fn publish(
|
||||||
&mut self,
|
&mut self,
|
||||||
request: impl tonic::IntoRequest<super::PublishRequest>,
|
request: impl tonic::IntoRequest<super::PublishRequest>,
|
||||||
@@ -111,7 +109,6 @@ pub mod registry_service_client {
|
|||||||
.insert(GrpcMethod::new("norun.v1.RegistryService", "Publish"));
|
.insert(GrpcMethod::new("norun.v1.RegistryService", "Publish"));
|
||||||
self.inner.unary(req, path, codec).await
|
self.inner.unary(req, path, codec).await
|
||||||
}
|
}
|
||||||
///
|
|
||||||
pub async fn get_topic(
|
pub async fn get_topic(
|
||||||
&mut self,
|
&mut self,
|
||||||
request: impl tonic::IntoRequest<super::GetTopicRequest>,
|
request: impl tonic::IntoRequest<super::GetTopicRequest>,
|
||||||
@@ -146,12 +143,10 @@ pub mod registry_service_server {
|
|||||||
/// Generated trait containing gRPC methods that should be implemented for use with RegistryServiceServer.
|
/// Generated trait containing gRPC methods that should be implemented for use with RegistryServiceServer.
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait RegistryService: Send + Sync + 'static {
|
pub trait RegistryService: Send + Sync + 'static {
|
||||||
///
|
|
||||||
async fn publish(
|
async fn publish(
|
||||||
&self,
|
&self,
|
||||||
request: tonic::Request<super::PublishRequest>,
|
request: tonic::Request<super::PublishRequest>,
|
||||||
) -> std::result::Result<tonic::Response<super::PublishResponse>, tonic::Status>;
|
) -> std::result::Result<tonic::Response<super::PublishResponse>, tonic::Status>;
|
||||||
///
|
|
||||||
async fn get_topic(
|
async fn get_topic(
|
||||||
&self,
|
&self,
|
||||||
request: tonic::Request<super::GetTopicRequest>,
|
request: tonic::Request<super::GetTopicRequest>,
|
||||||
@@ -160,7 +155,6 @@ pub mod registry_service_server {
|
|||||||
tonic::Status,
|
tonic::Status,
|
||||||
>;
|
>;
|
||||||
}
|
}
|
||||||
///
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RegistryServiceServer<T: RegistryService> {
|
pub struct RegistryServiceServer<T: RegistryService> {
|
||||||
inner: _Inner<T>,
|
inner: _Inner<T>,
|
||||||
|
@@ -1,10 +1,14 @@
|
|||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::{publish::PublishCommand, serve::ServeCommand, subscribe::SubscribeCommand},
|
cli::{
|
||||||
|
node::NodeCommand, publish::PublishCommand, serve::ServeCommand,
|
||||||
|
subscribe::SubscribeCommand,
|
||||||
|
},
|
||||||
state::ClientState,
|
state::ClientState,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod node;
|
||||||
mod publish;
|
mod publish;
|
||||||
mod serve;
|
mod serve;
|
||||||
mod subscribe;
|
mod subscribe;
|
||||||
@@ -25,6 +29,7 @@ struct Cli {
|
|||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
enum CliSubcommands {
|
enum CliSubcommands {
|
||||||
|
Node(NodeCommand),
|
||||||
Subscribe(SubscribeCommand),
|
Subscribe(SubscribeCommand),
|
||||||
Publish(PublishCommand),
|
Publish(PublishCommand),
|
||||||
Serve(ServeCommand),
|
Serve(ServeCommand),
|
||||||
@@ -36,6 +41,7 @@ pub async fn execute() -> anyhow::Result<()> {
|
|||||||
let state = ClientState::new(&cmd.server_url);
|
let state = ClientState::new(&cmd.server_url);
|
||||||
|
|
||||||
match cmd.subcommands {
|
match cmd.subcommands {
|
||||||
|
CliSubcommands::Node(cmd) => cmd.execute(&state).await,
|
||||||
CliSubcommands::Publish(cmd) => cmd.execute(&state).await,
|
CliSubcommands::Publish(cmd) => cmd.execute(&state).await,
|
||||||
CliSubcommands::Serve(cmd) => cmd.execute().await,
|
CliSubcommands::Serve(cmd) => cmd.execute().await,
|
||||||
CliSubcommands::Subscribe(cmd) => cmd.execute(&state).await,
|
CliSubcommands::Subscribe(cmd) => cmd.execute(&state).await,
|
||||||
|
22
crates/norun/src/cli/node.rs
Normal file
22
crates/norun/src/cli/node.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
use crate::{cli::node::start::StartCommand, state::ClientState};
|
||||||
|
|
||||||
|
mod start;
|
||||||
|
|
||||||
|
#[derive(clap::Parser)]
|
||||||
|
pub struct NodeCommand {
|
||||||
|
#[clap(subcommand)]
|
||||||
|
commands: NodeCommands,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(clap::Subcommand)]
|
||||||
|
pub enum NodeCommands {
|
||||||
|
Start(StartCommand),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeCommand {
|
||||||
|
pub async fn execute(&self, state: &ClientState) -> anyhow::Result<()> {
|
||||||
|
match &self.commands {
|
||||||
|
NodeCommands::Start(start_command) => start_command.execute(state).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
crates/norun/src/cli/node/start.rs
Normal file
15
crates/norun/src/cli/node/start.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
use crate::{node::services::node_service::NodeServiceState, state::ClientState};
|
||||||
|
|
||||||
|
#[derive(clap::Parser)]
|
||||||
|
pub struct StartCommand {}
|
||||||
|
|
||||||
|
impl StartCommand {
|
||||||
|
pub async fn execute(&self, state: &ClientState) -> anyhow::Result<()> {
|
||||||
|
notmad::Mad::builder()
|
||||||
|
.add(state.node_service())
|
||||||
|
.run()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@@ -1,3 +1,5 @@
|
|||||||
|
use norun_grpc_interface::project::ProjectType;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
container_runtime::ContainerRuntimeState, grpc_client::GrpcClientState, models::port::Port,
|
container_runtime::ContainerRuntimeState, grpc_client::GrpcClientState, models::port::Port,
|
||||||
state::ClientState,
|
state::ClientState,
|
||||||
@@ -19,16 +21,26 @@ impl SubscribeCommand {
|
|||||||
for project in projects.projects {
|
for project in projects.projects {
|
||||||
println!("project: {project:?}");
|
println!("project: {project:?}");
|
||||||
|
|
||||||
runtime
|
match project.project_type {
|
||||||
.ensure_running(
|
Some(project_type) => match project_type {
|
||||||
&project.name,
|
ProjectType::Container(container) => {
|
||||||
&format!("{}:{}", project.image, project.version),
|
runtime
|
||||||
vec![Port {
|
.ensure_running(
|
||||||
host_port: 38080,
|
&project.name,
|
||||||
container_port: 80,
|
&format!("{}:{}", container.image, container.version),
|
||||||
}],
|
vec![Port {
|
||||||
)
|
host_port: 38080,
|
||||||
.await?;
|
container_port: 80,
|
||||||
|
}],
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
ProjectType::Compose(compose) => {
|
||||||
|
// Allocate a local project
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => todo!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use norun_grpc_interface::{
|
use norun_grpc_interface::{
|
||||||
GetTopicRequest, Projects, PublishRequest, registry_service_client::RegistryServiceClient,
|
GetTopicRequest, Projects, PublishRequest, registry_service_client::RegistryServiceClient,
|
||||||
};
|
};
|
||||||
@@ -70,9 +72,39 @@ impl From<ProjectFile> for norun_grpc_interface::Project {
|
|||||||
fn from(value: ProjectFile) -> Self {
|
fn from(value: ProjectFile) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: value.project.name,
|
name: value.project.name,
|
||||||
image: value.container.image,
|
|
||||||
version: value.container.version,
|
|
||||||
port: value.expose.and_then(|e| e.port),
|
port: value.expose.and_then(|e| e.port),
|
||||||
|
project_type: Some({
|
||||||
|
match (value.container, value.compose) {
|
||||||
|
(None, None) => panic!("either a container or compose is required"),
|
||||||
|
(Some(_), Some(_)) => {
|
||||||
|
panic!("either a container or compose is required, but not both")
|
||||||
|
}
|
||||||
|
(Some(container), None) => {
|
||||||
|
norun_grpc_interface::project::ProjectType::Container(
|
||||||
|
norun_grpc_interface::Container {
|
||||||
|
image: container.image,
|
||||||
|
version: container.version,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
(None, Some(compose)) => norun_grpc_interface::project::ProjectType::Compose(
|
||||||
|
norun_grpc_interface::Compose {
|
||||||
|
// TODO: dirty hack to get files out for compose, it should instead
|
||||||
|
// be transformed into an intermediary format, or simply extraced from the <From>
|
||||||
|
files: compose
|
||||||
|
.include
|
||||||
|
.into_iter()
|
||||||
|
.map(|i| {
|
||||||
|
(
|
||||||
|
i.to_string_lossy().to_string(),
|
||||||
|
std::fs::read(&i).expect("to be able to read include file"),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<HashMap<_, _>>(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,8 @@ mod grpc_server;
|
|||||||
|
|
||||||
mod container_runtime;
|
mod container_runtime;
|
||||||
|
|
||||||
|
mod node;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
|
3
crates/norun/src/node.rs
Normal file
3
crates/norun/src/node.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod config;
|
||||||
|
|
||||||
|
pub mod services;
|
15
crates/norun/src/node/config.rs
Normal file
15
crates/norun/src/node/config.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct Config {
|
||||||
|
node_name: Option<String>,
|
||||||
|
|
||||||
|
subscriptions: BTreeMap<String, Subscription>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct Subscription {
|
||||||
|
enabled: Option<bool>,
|
||||||
|
}
|
3
crates/norun/src/node/services.rs
Normal file
3
crates/norun/src/node/services.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod config_service;
|
||||||
|
pub mod data_store;
|
||||||
|
pub mod node_service;
|
31
crates/norun/src/node/services/config_service.rs
Normal file
31
crates/norun/src/node/services/config_service.rs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
use anyhow::Context;
|
||||||
|
|
||||||
|
use crate::{node::config::Config, state::ClientState};
|
||||||
|
|
||||||
|
pub struct ConfigService {}
|
||||||
|
|
||||||
|
impl ConfigService {
|
||||||
|
pub async fn get_config(&self) -> anyhow::Result<Config> {
|
||||||
|
let config_file_path = dirs::config_dir()
|
||||||
|
.context("failed to get config dir")?
|
||||||
|
.join("norun")
|
||||||
|
.join("node")
|
||||||
|
.join("config.toml");
|
||||||
|
|
||||||
|
let config_file_content = tokio::fs::read_to_string(&config_file_path).await?;
|
||||||
|
|
||||||
|
let config: Config = toml::from_str(&config_file_content)?;
|
||||||
|
|
||||||
|
Ok(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ConfigServiceState {
|
||||||
|
fn config_service(&self) -> ConfigService;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConfigServiceState for ClientState {
|
||||||
|
fn config_service(&self) -> ConfigService {
|
||||||
|
ConfigService {}
|
||||||
|
}
|
||||||
|
}
|
69
crates/norun/src/node/services/data_store.rs
Normal file
69
crates/norun/src/node/services/data_store.rs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use notmad::{Component, MadError};
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
|
use crate::state::ClientState;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct DataStore {
|
||||||
|
sender: tokio::sync::mpsc::Sender<()>,
|
||||||
|
receiver: Arc<Mutex<tokio::sync::mpsc::Receiver<()>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataStore {
|
||||||
|
pub async fn execute(&self, cancellation_token: CancellationToken) -> anyhow::Result<()> {
|
||||||
|
let mut rec = self.receiver.lock().await;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let msg = tokio::select! {
|
||||||
|
_ = cancellation_token.cancelled() => {
|
||||||
|
return Ok(())
|
||||||
|
},
|
||||||
|
item = rec.recv() => {
|
||||||
|
match item {
|
||||||
|
Some(item) => item,
|
||||||
|
None => return Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tracing::debug!("handling item");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn publish(&self) -> anyhow::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl Component for DataStore {
|
||||||
|
fn name(&self) -> Option<String> {
|
||||||
|
Some("norun/node/data-store".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run(&self, cancellation_token: CancellationToken) -> Result<(), MadError> {
|
||||||
|
self.execute(cancellation_token)
|
||||||
|
.await
|
||||||
|
.map_err(notmad::MadError::Inner)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DataStoreState {
|
||||||
|
fn data_store(&self) -> DataStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataStoreState for ClientState {
|
||||||
|
fn data_store(&self) -> DataStore {
|
||||||
|
let (sender, receiver) = tokio::sync::mpsc::channel(100);
|
||||||
|
|
||||||
|
DataStore {
|
||||||
|
sender,
|
||||||
|
receiver: Arc::new(Mutex::new(receiver)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
crates/norun/src/node/services/node_service.rs
Normal file
35
crates/norun/src/node/services/node_service.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use notmad::{Component, MadError};
|
||||||
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
|
use crate::state::ClientState;
|
||||||
|
|
||||||
|
pub struct NodeService {}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl Component for NodeService {
|
||||||
|
fn name(&self) -> Option<String> {
|
||||||
|
Some("norun/node".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn setup(&self) -> Result<(), MadError> {
|
||||||
|
tracing::info!("starting norun/node!");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn run(&self, cancellation_token: CancellationToken) -> Result<(), MadError> {
|
||||||
|
cancellation_token.cancelled().await;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NodeServiceState {
|
||||||
|
fn node_service(&self) -> NodeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeServiceState for ClientState {
|
||||||
|
fn node_service(&self) -> NodeService {
|
||||||
|
NodeService {}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@@ -8,8 +8,9 @@ const NORUN_PROJECT_FILE_NAME: &str = "norun.toml";
|
|||||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||||
pub struct ProjectFile {
|
pub struct ProjectFile {
|
||||||
pub project: ProjectDecl,
|
pub project: ProjectDecl,
|
||||||
pub container: ContainerDecl,
|
pub container: Option<ContainerDecl>,
|
||||||
pub expose: Option<ExposeDecl>,
|
pub expose: Option<ExposeDecl>,
|
||||||
|
pub compose: Option<ComposeDecl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||||
@@ -23,6 +24,11 @@ pub struct ContainerDecl {
|
|||||||
pub version: String,
|
pub version: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||||
|
pub struct ComposeDecl {
|
||||||
|
pub include: Vec<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, PartialEq)]
|
||||||
pub struct ExposeDecl {
|
pub struct ExposeDecl {
|
||||||
pub port: Option<u32>,
|
pub port: Option<u32>,
|
||||||
@@ -72,10 +78,11 @@ port = 8080
|
|||||||
project: ProjectDecl {
|
project: ProjectDecl {
|
||||||
name: "hello-world".into(),
|
name: "hello-world".into(),
|
||||||
},
|
},
|
||||||
container: ContainerDecl {
|
container: Some(ContainerDecl {
|
||||||
image: "kasperhermansen/hello-world".into(),
|
image: "kasperhermansen/hello-world".into(),
|
||||||
version: "latest".into(),
|
version: "latest".into(),
|
||||||
},
|
}),
|
||||||
|
compose: None,
|
||||||
expose: Some(ExposeDecl { port: Some(8080) }),
|
expose: Some(ExposeDecl { port: Some(8080) }),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -27,9 +27,19 @@ message Projects {
|
|||||||
|
|
||||||
message Project {
|
message Project {
|
||||||
string name = 1;
|
string name = 1;
|
||||||
|
optional uint32 port = 2;
|
||||||
|
|
||||||
string image = 2;
|
oneof project_type {
|
||||||
string version = 3;
|
Container container = 3;
|
||||||
|
Compose compose = 4;
|
||||||
optional uint32 port = 4;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Container {
|
||||||
|
string image = 1;
|
||||||
|
string version = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Compose {
|
||||||
|
map<string, bytes> files = 1;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user