Skip to content

Commit

Permalink
Merge pull request #553 from XxChang/update_dora_new
Browse files Browse the repository at this point in the history
Update dora new
  • Loading branch information
haixuanTao authored Jun 14, 2024
2 parents f34cbe2 + 7cca18f commit a346f35
Show file tree
Hide file tree
Showing 25 changed files with 701 additions and 256 deletions.
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,44 @@ jobs:
dora stop --name ci-python-test --grace-duration 5s
dora destroy
- name: "Test CLI (C)"
timeout-minutes: 30
# fail-fast by using bash shell explictly
shell: bash
if: runner.os == 'Linux'
run: |
# Test C template Project
dora new test_c_project --lang c --internal-create-with-path-dependencies
cd test_c_project
dora up
dora list
cmake -B build
cmake --build build
cmake --install build
dora start dataflow.yml --name ci-c-test
sleep 10
dora stop --name ci-c-test --grace-duration 5s
dora destroy
- name: "Test CLI (C++)"
timeout-minutes: 30
# fail-fast by using bash shell explictly
shell: bash
if: runner.os == 'Linux'
run: |
# Test C++ template Project
dora new test_cxx_project --lang cxx --internal-create-with-path-dependencies
cd test_cxx_project
dora up
dora list
cmake -B build
cmake --build build
cmake --install build
dora start dataflow.yml --name ci-cxx-test
sleep 10
dora stop --name ci-cxx-test --grace-duration 5s
dora destroy
clippy:
name: "Clippy"
runs-on: ubuntu-latest
Expand Down
3 changes: 1 addition & 2 deletions binaries/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ enum Command {
#[clap(value_name = "PATH", value_hint = clap::ValueHint::FilePath)]
dataflow: PathBuf,
},
/// Generate a new project, node or operator. Choose the language between Rust, Python, C or C++.
/// Generate a new project or node. Choose the language between Rust, Python, C or C++.
New {
#[clap(flatten)]
args: CommandNew,
Expand Down Expand Up @@ -230,7 +230,6 @@ pub struct CommandNew {
#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
enum Kind {
Dataflow,
Operator,
CustomNode,
}

Expand Down
79 changes: 79 additions & 0 deletions binaries/cli/src/template/c/cmake-template.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
cmake_minimum_required(VERSION 3.21)
project(cxx-dataflow LANGUAGES C)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "-fPIC")

set(DORA_ROOT_DIR "__DORA_PATH__" CACHE FILEPATH "Path to the root of dora")

set(dora_c_include_dir "${CMAKE_CURRENT_BINARY_DIR}/include/c")
if(DORA_ROOT_DIR)
include(ExternalProject)
ExternalProject_Add(Dora
SOURCE_DIR ${DORA_ROOT_DIR}
BUILD_IN_SOURCE True
CONFIGURE_COMMAND ""
BUILD_COMMAND
cargo build
--package dora-node-api-c
INSTALL_COMMAND ""
)

add_custom_command(OUTPUT ${dora_c_include_dir}
WORKING_DIRECTORY ${DORA_ROOT_DIR}
DEPENDS Dora
COMMAND
mkdir ${CMAKE_CURRENT_BINARY_DIR}/include/c -p
&&
cp apis/c/node ${CMAKE_CURRENT_BINARY_DIR}/include/c -r
)

add_custom_target(Dora_c DEPENDS ${dora_c_include_dir})
set(dora_link_dirs ${DORA_ROOT_DIR}/target/debug)
else()
include(ExternalProject)
ExternalProject_Add(Dora
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dora
GIT_REPOSITORY https://github.com/dora-rs/dora.git
GIT_TAG main
BUILD_IN_SOURCE True
CONFIGURE_COMMAND ""
BUILD_COMMAND
cargo build
--package dora-node-api-c
--target-dir ${CMAKE_CURRENT_BINARY_DIR}/dora/src/Dora/target
INSTALL_COMMAND ""
)

add_custom_command(OUTPUT ${dora_c_include_dir}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dora/src/Dora/target
DEPENDS Dora
COMMAND
mkdir ${CMAKE_CURRENT_BINARY_DIR}/include/c -p
&&
cp ../apis/c/node ${CMAKE_CURRENT_BINARY_DIR}/include/c -r
)

set(dora_link_dirs ${CMAKE_CURRENT_BINARY_DIR}/dora/src/Dora/target/debug)

add_custom_target(Dora_c DEPENDS ${dora_c_include_dir})
endif()

link_directories(${dora_link_dirs})

add_executable(talker_1 talker_1/node.c)
add_dependencies(talker_1 Dora_c)
target_include_directories(talker_1 PRIVATE ${dora_c_include_dir})
target_link_libraries(talker_1 dora_node_api_c m)

add_executable(talker_2 talker_2/node.c)
add_dependencies(talker_2 Dora_c)
target_include_directories(talker_2 PRIVATE ${dora_c_include_dir})
target_link_libraries(talker_2 dora_node_api_c m)

add_executable(listener_1 listener_1/node.c)
add_dependencies(listener_1 Dora_c)
target_include_directories(listener_1 PRIVATE ${dora_c_include_dir})
target_link_libraries(listener_1 dora_node_api_c m)

install(TARGETS listener_1 talker_1 talker_2 DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
30 changes: 14 additions & 16 deletions binaries/cli/src/template/c/dataflow-template.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
nodes:
- id: op_1
operator:
shared-library: build/op_1
- id: talker_1
custom:
source: bin/talker_1
inputs:
foo: dora/timer/millis/100
tick: dora/timer/millis/100
outputs:
- bar
- id: op_2
operator:
shared-library: build/op_2
- speech
- id: talker_2
custom:
source: bin/talker_2
inputs:
foo: dora/timer/secs/2
tick: dora/timer/secs/2
outputs:
- bar
- speech

- id: custom-node_1
- id: listener_1
custom:
source: build/node_1
source: bin/listener_1
inputs:
input-1: op_1/bar
input-2: op_2/bar
outputs:
- foo
speech-1: talker_1/speech
speech-2: talker_2/speech
69 changes: 69 additions & 0 deletions binaries/cli/src/template/c/listener/listener-template.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "node_api.h"

// sleep
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#endif

int main()
{
void *dora_context = init_dora_context_from_env();
if (dora_context == NULL)
{
fprintf(stderr, "[c node] init dora context failed\n");
return -1;
}

printf("[c node] dora context initialized\n");

for (char i = 0; i < 20; i++)
{
void *event = dora_next_event(dora_context);
if (event == NULL)
{
printf("[c node] ERROR: unexpected end of event\n");
return -1;
}

enum DoraEventType ty = read_dora_event_type(event);

if (ty == DoraEventType_Input)
{
char *id_ptr;
size_t id_len;
read_dora_input_id(event, &id_ptr, &id_len);

char *data_ptr;
size_t data_len;
read_dora_input_data(event, &data_ptr, &data_len);

printf("I heard %s from %s\n", data_ptr, id_ptr);
}
else if (ty == DoraEventType_Stop)
{
printf("[c node] received stop event\n");
free_dora_event(event);
break;
}
else if (ty == DoraEventType_InputClosed) {
printf("[c node] received input closed event\n");
}
else
{
printf("[c node] received unexpected event: %d\n", ty);
free_dora_event(event);
break;
}

free_dora_event(event);
}

free_dora_context(dora_context);

return 0;
}
92 changes: 43 additions & 49 deletions binaries/cli/src/template/c/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
use dora_node_api_c::HEADER_NODE_API;
use dora_operator_api_c::{HEADER_OPERATOR_API, HEADER_OPERATOR_TYPES};
use eyre::{bail, Context};
use eyre::{bail, Context, ContextCompat};
use std::{
fs,
path::{Path, PathBuf},
};

pub fn create(args: crate::CommandNew) -> eyre::Result<()> {
const NODE: &str = include_str!("node/node-template.c");
const TALKER: &str = include_str!("talker/talker-template.c");
const LISTENER: &str = include_str!("listener/listener-template.c");

pub fn create(args: crate::CommandNew, use_path_deps: bool) -> eyre::Result<()> {
let crate::CommandNew {
kind,
lang: _,
Expand All @@ -15,13 +18,16 @@ pub fn create(args: crate::CommandNew) -> eyre::Result<()> {
} = args;

match kind {
crate::Kind::Operator => create_operator(name, path),
crate::Kind::CustomNode => create_custom_node(name, path),
crate::Kind::Dataflow => create_dataflow(name, path),
crate::Kind::CustomNode => create_custom_node(name, path, NODE),
crate::Kind::Dataflow => create_dataflow(name, path, use_path_deps),
}
}

fn create_dataflow(name: String, path: Option<PathBuf>) -> Result<(), eyre::ErrReport> {
fn create_dataflow(
name: String,
path: Option<PathBuf>,
use_path_deps: bool,
) -> Result<(), eyre::ErrReport> {
const DATAFLOW_YML: &str = include_str!("dataflow-template.yml");

if name.contains('/') {
Expand All @@ -41,9 +47,10 @@ fn create_dataflow(name: String, path: Option<PathBuf>) -> Result<(), eyre::ErrR
fs::write(&dataflow_yml_path, dataflow_yml)
.with_context(|| format!("failed to write `{}`", dataflow_yml_path.display()))?;

create_operator("op_1".into(), Some(root.join("op_1")))?;
create_operator("op_2".into(), Some(root.join("op_2")))?;
create_custom_node("node_1".into(), Some(root.join("node_1")))?;
create_custom_node("talker_1".into(), Some(root.join("talker_1")), TALKER)?;
create_custom_node("talker_2".into(), Some(root.join("talker_2")), TALKER)?;
create_custom_node("listener_1".into(), Some(root.join("listener_1")), LISTENER)?;
create_cmakefile(root.to_path_buf(), use_path_deps)?;

println!(
"Created new C dataflow at `{name}` at {}",
Expand All @@ -53,47 +60,34 @@ fn create_dataflow(name: String, path: Option<PathBuf>) -> Result<(), eyre::ErrR
Ok(())
}

fn create_operator(name: String, path: Option<PathBuf>) -> Result<(), eyre::ErrReport> {
const OPERATOR: &str = include_str!("operator/operator-template.c");

if name.contains('/') {
bail!("operator name must not contain `/` separators");
}
if name.contains('-') {
bail!("operator name must not contain `-` separators");
}
if !name.is_ascii() {
bail!("operator name must be ASCII");
}

// create directories
let root = path.as_deref().unwrap_or_else(|| Path::new(&name));
fs::create_dir(root)
.with_context(|| format!("failed to create directory `{}`", root.display()))?;

let operator_path = root.join("operator.c");
fs::write(&operator_path, OPERATOR)
.with_context(|| format!("failed to write `{}`", operator_path.display()))?;
let header_api_path = root.join("operator_api.h");
let header_type_path = root.join("operator_types.h");
fs::write(&header_api_path, HEADER_OPERATOR_API)
.with_context(|| format!("failed to write `{}`", header_api_path.display()))?;
fs::write(&header_type_path, HEADER_OPERATOR_TYPES)
.with_context(|| format!("failed to write `{}`", header_type_path.display()))?;

// TODO: Makefile?

println!(
"Created new C operator `{name}` at {}",
Path::new(".").join(root).display()
);

fn create_cmakefile(root: PathBuf, use_path_deps: bool) -> Result<(), eyre::ErrReport> {
const CMAKEFILE: &str = include_str!("cmake-template.txt");

let cmake_file = if use_path_deps {
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let workspace_dir = manifest_dir
.parent()
.context("Could not get manifest parent folder")?
.parent()
.context("Could not get manifest grandparent folder")?;
CMAKEFILE.replace("__DORA_PATH__", workspace_dir.to_str().unwrap())
} else {
CMAKEFILE.replace("__DORA_PATH__", "")
};

let cmake_path = root.join("CMakeLists.txt");
fs::write(&cmake_path, cmake_file)
.with_context(|| format!("failed to write `{}`", cmake_path.display()))?;

println!("Created new CMakeLists.txt at {}", cmake_path.display());
Ok(())
}

fn create_custom_node(name: String, path: Option<PathBuf>) -> Result<(), eyre::ErrReport> {
const NODE: &str = include_str!("node/node-template.c");

fn create_custom_node(
name: String,
path: Option<PathBuf>,
template_scripts: &str,
) -> Result<(), eyre::ErrReport> {
if name.contains('/') {
bail!("node name must not contain `/` separators");
}
Expand All @@ -107,7 +101,7 @@ fn create_custom_node(name: String, path: Option<PathBuf>) -> Result<(), eyre::E
.with_context(|| format!("failed to create directory `{}`", root.display()))?;

let node_path = root.join("node.c");
fs::write(&node_path, NODE)
fs::write(&node_path, template_scripts)
.with_context(|| format!("failed to write `{}`", node_path.display()))?;
let header_path = root.join("node_api.h");
fs::write(&header_path, HEADER_NODE_API)
Expand Down
Loading

0 comments on commit a346f35

Please sign in to comment.