mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
config event template
This commit is contained in:
parent
f1a229002f
commit
569da533a1
10
.idea/inspectionProfiles/Project_Default.xml
Normal file
10
.idea/inspectionProfiles/Project_Default.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
|
||||
<Languages>
|
||||
<language minSize="46" name="Rust" />
|
||||
</Languages>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
@ -1 +1,2 @@
|
||||
proto_crates = ["src/model"]
|
||||
proto_crates = ["src/model"]
|
||||
event_files = []
|
@ -255,14 +255,22 @@ pub enum Default {
|
||||
Path(syn::ExprPath),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EventAttrs {
|
||||
input: Option<syn::Path>,
|
||||
output: Option<syn::Path>,
|
||||
pub ignore: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ASTEnumAttrVariant {
|
||||
pub name: String,
|
||||
pub value: String,
|
||||
pub event_attrs: EventAttrs,
|
||||
}
|
||||
|
||||
impl ASTEnumAttrVariant {
|
||||
pub fn from_ast(_cx: &Ctxt, variant: &syn::Variant) -> Self {
|
||||
pub fn from_ast(ctxt: &Ctxt, variant: &syn::Variant) -> Self {
|
||||
let name = variant.ident.to_string();
|
||||
let mut value = String::new();
|
||||
if variant.discriminant.is_some() {
|
||||
@ -278,8 +286,70 @@ impl ASTEnumAttrVariant {
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
ASTEnumAttrVariant { name, value }
|
||||
let mut event_attrs = EventAttrs {
|
||||
input: None,
|
||||
output: None,
|
||||
ignore: false,
|
||||
};
|
||||
variant.attrs.iter().for_each(|attr| match get_meta_items(ctxt, attr) {
|
||||
Ok(meta_items) => {
|
||||
for meta_item in meta_items {
|
||||
match &meta_item {
|
||||
Meta(NameValue(name_value)) => {
|
||||
if name_value.path == EVENT_INPUT {
|
||||
if let syn::Lit::Str(s) = &name_value.lit {
|
||||
let input_type = parse_lit_str(s)
|
||||
.map_err(|_| {
|
||||
ctxt.error_spanned_by(
|
||||
s,
|
||||
format!("failed to parse request deserializer {:?}", s.value()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
event_attrs.input = Some(input_type);
|
||||
}
|
||||
}
|
||||
|
||||
if name_value.path == EVENT_OUTPUT {
|
||||
if let syn::Lit::Str(s) = &name_value.lit {
|
||||
let output_type = parse_lit_str(s)
|
||||
.map_err(|_| {
|
||||
ctxt.error_spanned_by(
|
||||
s,
|
||||
format!("failed to parse response deserializer {:?}", s.value()),
|
||||
)
|
||||
})
|
||||
.unwrap();
|
||||
event_attrs.output = Some(output_type);
|
||||
}
|
||||
}
|
||||
},
|
||||
Meta(Path(word)) => {
|
||||
if word == EVENT_IGNORE && attr.path == EVENT {
|
||||
event_attrs.ignore = true;
|
||||
}
|
||||
},
|
||||
Lit(s) => {
|
||||
ctxt.error_spanned_by(s, "unexpected type in cqrs container attribute");
|
||||
},
|
||||
_ => {
|
||||
ctxt.error_spanned_by(meta_item, "unexpected type in cqrs container attribute");
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(_) => {},
|
||||
});
|
||||
ASTEnumAttrVariant {
|
||||
name,
|
||||
value,
|
||||
event_attrs,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn event_input(&self) -> Option<syn::Path> { self.event_attrs.input.clone() }
|
||||
|
||||
pub fn event_output(&self) -> Option<syn::Path> { self.event_attrs.output.clone() }
|
||||
}
|
||||
|
||||
pub fn get_meta_items(cx: &Ctxt, attr: &syn::Attribute) -> Result<Vec<syn::NestedMeta>, ()> {
|
||||
|
35
rust-lib/flowy-ast/src/event_ast.rs
Normal file
35
rust-lib/flowy-ast/src/event_ast.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use crate::ASTEnumAttrVariant;
|
||||
|
||||
pub struct EventASTContext {
|
||||
pub event: syn::Ident,
|
||||
pub event_ty: syn::Ident,
|
||||
pub event_request_struct: syn::Ident,
|
||||
pub event_input: Option<syn::Path>,
|
||||
pub event_output: Option<syn::Path>,
|
||||
}
|
||||
|
||||
impl EventASTContext {
|
||||
pub fn from(variant: &ASTEnumAttrVariant) -> EventASTContext {
|
||||
let command_name = variant.name.clone();
|
||||
if command_name.is_empty() {
|
||||
panic!("Invalid command name: {}", variant.name);
|
||||
}
|
||||
|
||||
let event = format_ident!("{}", &command_name);
|
||||
let splits = command_name.split("_").collect::<Vec<&str>>();
|
||||
|
||||
let event_ty = format_ident!("UserEvent");
|
||||
let event_request_struct = format_ident!("{}Event", &splits.join(""));
|
||||
|
||||
let event_input = variant.event_input();
|
||||
let event_output = variant.event_output();
|
||||
|
||||
EventASTContext {
|
||||
event,
|
||||
event_ty,
|
||||
event_request_struct,
|
||||
event_input,
|
||||
event_output,
|
||||
}
|
||||
}
|
||||
}
|
@ -7,9 +7,10 @@ extern crate quote;
|
||||
mod ast;
|
||||
mod attr;
|
||||
mod ctxt;
|
||||
|
||||
pub mod event_ast;
|
||||
pub mod symbol;
|
||||
pub mod ty_ext;
|
||||
|
||||
pub use self::{symbol::*, ty_ext::*};
|
||||
pub use ast::*;
|
||||
pub use attr::*;
|
||||
|
@ -14,6 +14,11 @@ pub const SKIP_SERIALIZING: Symbol = Symbol("skip_serializing"); //#[pb(skip_ser
|
||||
pub const PB_STRUCT: Symbol = Symbol("struct"); //#[pb(struct="some struct")]
|
||||
pub const PB_ENUM: Symbol = Symbol("enum"); //#[pb(enum="some enum")]
|
||||
|
||||
pub const EVENT_INPUT: Symbol = Symbol("input");
|
||||
pub const EVENT_OUTPUT: Symbol = Symbol("output");
|
||||
pub const EVENT_IGNORE: Symbol = Symbol("ignore");
|
||||
pub const EVENT: Symbol = Symbol("event");
|
||||
|
||||
impl PartialEq<Symbol> for Ident {
|
||||
fn eq(&self, word: &Symbol) -> bool { self == word.0 }
|
||||
}
|
||||
|
@ -1,2 +1,3 @@
|
||||
|
||||
proto_crates = ["src/domain"]
|
||||
proto_crates = ["src/domain"]
|
||||
event_files = ["src/module.rs"]
|
@ -3,6 +3,7 @@ use std::fs;
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct FlowyConfig {
|
||||
pub proto_crates: Vec<String>,
|
||||
pub event_files: Vec<String>,
|
||||
}
|
||||
|
||||
impl FlowyConfig {
|
||||
|
122
scripts/flowy-tool/src/dart_event/dart_event.rs
Normal file
122
scripts/flowy-tool/src/dart_event/dart_event.rs
Normal file
@ -0,0 +1,122 @@
|
||||
use super::event_template::*;
|
||||
|
||||
use crate::util::*;
|
||||
use flowy_ast::{event_ast::*, *};
|
||||
use syn::Item;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
pub struct DartEventCodeGen {
|
||||
pub rust_source: String,
|
||||
pub output_dir: String,
|
||||
}
|
||||
|
||||
impl DartEventCodeGen {
|
||||
pub fn gen(&self) {
|
||||
let event_crates = parse_dart_event_files(self.rust_source.as_ref());
|
||||
let event_ast = event_crates
|
||||
.iter()
|
||||
.map(|event_crate| parse_event_crate(event_crate))
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let event_render_ctx = ast_to_event_render_ctx(event_ast.as_ref());
|
||||
|
||||
let mut render_result = String::new();
|
||||
for (index, render_ctx) in event_render_ctx.into_iter().enumerate() {
|
||||
let mut event_template = EventTemplate::new();
|
||||
|
||||
match event_template.render(render_ctx, index) {
|
||||
Some(content) => render_result.push_str(content.as_ref()),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
save_content_to_file_with_diff_prompt(
|
||||
render_result.as_ref(),
|
||||
self.output_dir.as_str(),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DartEventCrate {
|
||||
crate_path: String,
|
||||
crate_name: String,
|
||||
event_files: Vec<String>,
|
||||
}
|
||||
|
||||
impl DartEventCrate {
|
||||
pub fn from_config(config: &CrateConfig) -> Self {
|
||||
DartEventCrate {
|
||||
crate_path: config.crate_path.clone(),
|
||||
crate_name: config.folder_name.clone(),
|
||||
event_files: config.flowy_config.event_files.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_dart_event_files(root: &str) -> Vec<DartEventCrate> {
|
||||
WalkDir::new(root)
|
||||
.into_iter()
|
||||
.filter_entry(|e| !is_hidden(e))
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|e| is_crate_dir(e))
|
||||
.flat_map(|e| parse_crate_config_from(&e))
|
||||
.map(|crate_config| DartEventCrate::from_config(&crate_config))
|
||||
.collect::<Vec<DartEventCrate>>()
|
||||
}
|
||||
|
||||
pub fn parse_event_crate(event_crate: &DartEventCrate) -> Vec<EventASTContext> {
|
||||
event_crate
|
||||
.event_files
|
||||
.iter()
|
||||
.map(|event_file| {
|
||||
let file_path = format!("{}/{}", event_crate.crate_path, event_file);
|
||||
let file_content = read_file(file_path.as_ref()).unwrap();
|
||||
let ast = syn::parse_file(file_content.as_ref()).expect("Unable to parse file");
|
||||
|
||||
ast.items
|
||||
.iter()
|
||||
.map(|item| match item {
|
||||
Item::Enum(item_enum) => {
|
||||
let ctxt = Ctxt::new();
|
||||
let attrs = flowy_ast::enum_from_ast(&ctxt, &item_enum.variants);
|
||||
ctxt.check().unwrap();
|
||||
attrs
|
||||
.iter()
|
||||
.filter(|attr| attr.attrs.event_attrs.ignore == false)
|
||||
.enumerate()
|
||||
.map(|(_index, attr)| EventASTContext::from(&attr.attrs))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
_ => vec![],
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<EventASTContext>>()
|
||||
}
|
||||
|
||||
pub fn ast_to_event_render_ctx(ast: &Vec<EventASTContext>) -> Vec<EventRenderContext> {
|
||||
ast.iter()
|
||||
.map(|event_ast| EventRenderContext {
|
||||
input_deserializer: event_ast
|
||||
.event_input
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get_ident()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
output_deserializer: event_ast
|
||||
.event_output
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.get_ident()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
event: event_ast.event.to_string(),
|
||||
event_ty: event_ast.event_ty.to_string(),
|
||||
})
|
||||
.collect::<Vec<EventRenderContext>>()
|
||||
}
|
25
scripts/flowy-tool/src/dart_event/event_template.rs
Normal file
25
scripts/flowy-tool/src/dart_event/event_template.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use tera::Context;
|
||||
|
||||
pub struct EventTemplate {
|
||||
tera_context: Context,
|
||||
}
|
||||
|
||||
pub struct EventRenderContext {
|
||||
pub input_deserializer: String,
|
||||
pub output_deserializer: String,
|
||||
pub event: String,
|
||||
pub event_ty: String,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl EventTemplate {
|
||||
pub fn new() -> Self {
|
||||
return EventTemplate {
|
||||
tera_context: Context::new(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn render(&mut self, _render_context: EventRenderContext, _index: usize) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
4
scripts/flowy-tool/src/dart_event/mod.rs
Normal file
4
scripts/flowy-tool/src/dart_event/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod dart_event;
|
||||
mod event_template;
|
||||
|
||||
pub use dart_event::*;
|
@ -1,4 +1,5 @@
|
||||
mod config;
|
||||
mod dart_event;
|
||||
mod proto;
|
||||
mod util;
|
||||
|
||||
@ -22,6 +23,17 @@ fn main() {
|
||||
.build()
|
||||
.gen();
|
||||
}
|
||||
|
||||
if let Some(ref matches) = matches.subcommand_matches("dart-event") {
|
||||
let rust_source = matches.value_of("rust_source").unwrap().to_string();
|
||||
let output_dir = matches.value_of("output").unwrap().to_string();
|
||||
|
||||
let code_gen = dart_event::DartEventCodeGen {
|
||||
rust_source,
|
||||
output_dir,
|
||||
};
|
||||
code_gen.gen();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn app<'a, 'b>() -> App<'a, 'b> {
|
||||
@ -49,6 +61,21 @@ pub fn app<'a, 'b>() -> App<'a, 'b> {
|
||||
.long("flutter_package_lib")
|
||||
.value_name("DIRECTORY"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
App::new("dart-event")
|
||||
.about("Generate the codes that sending events from rust ast")
|
||||
.arg(
|
||||
Arg::with_name("rust_source")
|
||||
.long("rust_source")
|
||||
.value_name("DIRECTORY")
|
||||
.help("Directory of the cargo workspace"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("output")
|
||||
.long("output")
|
||||
.value_name("DIRECTORY"),
|
||||
),
|
||||
);
|
||||
|
||||
app
|
||||
|
@ -1,5 +1,4 @@
|
||||
use crate::proto::crate_info::*;
|
||||
use crate::proto::helper::*;
|
||||
use crate::proto::proto_info::*;
|
||||
use crate::proto::template::{EnumTemplate, StructTemplate};
|
||||
use crate::util::*;
|
||||
use fancy_regex::Regex;
|
||||
@ -16,19 +15,19 @@ pub fn parse_crate_protobuf(root: &str) -> Vec<CrateProtoInfo> {
|
||||
.map(|crate_info| {
|
||||
let proto_output_dir = crate_info.proto_file_output_dir();
|
||||
let files = crate_info
|
||||
.proto_crate_paths
|
||||
.proto_paths
|
||||
.iter()
|
||||
.map(|proto_crate_path| parse_files_protobuf(proto_crate_path, &proto_output_dir))
|
||||
.flatten()
|
||||
.collect::<Vec<FileProtoInfo>>();
|
||||
.collect::<Vec<ProtoFile>>();
|
||||
|
||||
CrateProtoInfo::from_crate_info(crate_info, files)
|
||||
})
|
||||
.collect::<Vec<CrateProtoInfo>>()
|
||||
}
|
||||
|
||||
fn parse_files_protobuf(proto_crate_path: &str, proto_output_dir: &str) -> Vec<FileProtoInfo> {
|
||||
let mut gen_proto_vec: Vec<FileProtoInfo> = vec![];
|
||||
fn parse_files_protobuf(proto_crate_path: &str, proto_output_dir: &str) -> Vec<ProtoFile> {
|
||||
let mut gen_proto_vec: Vec<ProtoFile> = vec![];
|
||||
// file_stem https://doc.rust-lang.org/std/path/struct.Path.html#method.file_stem
|
||||
for (path, file_name) in WalkDir::new(proto_crate_path)
|
||||
.into_iter()
|
||||
@ -78,7 +77,7 @@ fn parse_files_protobuf(proto_crate_path: &str, proto_output_dir: &str) -> Vec<F
|
||||
});
|
||||
|
||||
if !enums.is_empty() || !structs.is_empty() {
|
||||
let info = FileProtoInfo {
|
||||
let info = ProtoFile {
|
||||
file_name: file_name.clone(),
|
||||
structs: structs.iter().map(|s| s.name.clone()).collect(),
|
||||
enums: enums.iter().map(|e| e.name.clone()).collect(),
|
||||
|
@ -1,26 +0,0 @@
|
||||
pub fn is_crate_dir(e: &walkdir::DirEntry) -> bool {
|
||||
let cargo = e.path().file_stem().unwrap().to_str().unwrap().to_string();
|
||||
cargo == "Cargo".to_string()
|
||||
}
|
||||
|
||||
pub fn is_proto_file(e: &walkdir::DirEntry) -> bool {
|
||||
if e.path().extension().is_none() {
|
||||
return false;
|
||||
}
|
||||
let ext = e.path().extension().unwrap().to_str().unwrap().to_string();
|
||||
ext == "proto".to_string()
|
||||
}
|
||||
|
||||
pub fn is_hidden(entry: &walkdir::DirEntry) -> bool {
|
||||
entry
|
||||
.file_name()
|
||||
.to_str()
|
||||
.map(|s| s.starts_with("."))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn create_dir_if_not_exist(dir: &str) {
|
||||
if !std::path::Path::new(&dir).exists() {
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
}
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
mod ast;
|
||||
mod builder;
|
||||
mod crate_info;
|
||||
mod helper;
|
||||
mod proto_gen;
|
||||
mod proto_info;
|
||||
mod template;
|
||||
|
||||
pub use builder::*;
|
||||
|
@ -1,9 +1,7 @@
|
||||
use crate::proto::ast::*;
|
||||
use crate::proto::crate_info::*;
|
||||
use crate::proto::helper::*;
|
||||
use crate::proto::proto_info::*;
|
||||
use crate::{proto::template::*, util::*};
|
||||
use std::{fs::OpenOptions, io::Write};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
pub struct ProtoGen {
|
||||
pub(crate) rust_source_dir: String,
|
||||
@ -77,7 +75,7 @@ fn write_flutter_protobuf_package_mod_file(
|
||||
package_info: &FlutterProtobufInfo,
|
||||
) {
|
||||
let mod_path = package_info.mod_file_path();
|
||||
let model_dir = package_info.model_dir();
|
||||
let _model_dir = package_info.model_dir();
|
||||
match OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
@ -90,7 +88,7 @@ fn write_flutter_protobuf_package_mod_file(
|
||||
mod_file_content.push_str("// Auto-generated, do not edit \n");
|
||||
|
||||
for crate_info in crate_infos {
|
||||
let mod_path = crate_info.inner.proto_model_mod_file();
|
||||
let _mod_path = crate_info.inner.proto_model_mod_file();
|
||||
walk_dir(
|
||||
crate_info.inner.proto_file_output_dir().as_ref(),
|
||||
|e| e.file_type().is_dir() == false,
|
||||
@ -151,23 +149,3 @@ fn run_flutter_protoc(crate_infos: &Vec<CrateProtoInfo>, package_info: &FlutterP
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_dir<F1, F2>(dir: &str, filter: F2, mut path_and_name: F1)
|
||||
where
|
||||
F1: FnMut(String, String),
|
||||
F2: Fn(&walkdir::DirEntry) -> bool,
|
||||
{
|
||||
for (path, name) in WalkDir::new(dir)
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|e| filter(e))
|
||||
.map(|e| {
|
||||
(
|
||||
e.path().to_str().unwrap().to_string(),
|
||||
e.path().file_stem().unwrap().to_str().unwrap().to_string(),
|
||||
)
|
||||
})
|
||||
{
|
||||
path_and_name(path, name);
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +1,15 @@
|
||||
use crate::config::FlowyConfig;
|
||||
use crate::proto::helper::*;
|
||||
use crate::util::*;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CrateInfo {
|
||||
pub crate_folder_name: String,
|
||||
pub proto_crate_paths: Vec<String>,
|
||||
pub crate_path: String,
|
||||
}
|
||||
|
||||
pub struct CrateProtoInfo {
|
||||
pub files: Vec<FileProtoInfo>,
|
||||
pub inner: CrateInfo,
|
||||
}
|
||||
|
||||
impl CrateInfo {
|
||||
fn protobuf_crate_name(&self) -> String {
|
||||
format!("{}/src/protobuf", self.crate_path)
|
||||
}
|
||||
|
||||
pub fn proto_file_output_dir(&self) -> String {
|
||||
let dir = format!("{}/proto", self.protobuf_crate_name());
|
||||
create_dir_if_not_exist(dir.as_ref());
|
||||
dir
|
||||
}
|
||||
|
||||
pub fn proto_struct_output_dir(&self) -> String {
|
||||
let dir = format!("{}/model", self.protobuf_crate_name());
|
||||
create_dir_if_not_exist(dir.as_ref());
|
||||
dir
|
||||
}
|
||||
|
||||
pub fn proto_model_mod_file(&self) -> String {
|
||||
format!("{}/mod.rs", self.proto_struct_output_dir())
|
||||
}
|
||||
pub files: Vec<ProtoFile>,
|
||||
pub inner: ProtobufCrate,
|
||||
}
|
||||
|
||||
impl CrateProtoInfo {
|
||||
pub fn from_crate_info(inner: CrateInfo, files: Vec<FileProtoInfo>) -> Self {
|
||||
pub fn from_crate_info(inner: ProtobufCrate, files: Vec<ProtoFile>) -> Self {
|
||||
Self { files, inner }
|
||||
}
|
||||
|
||||
@ -68,45 +38,61 @@ pub use model::*;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ProtobufCrate {
|
||||
pub folder_name: String,
|
||||
pub proto_paths: Vec<String>,
|
||||
pub crate_path: String,
|
||||
}
|
||||
|
||||
impl ProtobufCrate {
|
||||
pub fn from_config(config: CrateConfig) -> Self {
|
||||
let proto_paths = config.proto_paths();
|
||||
ProtobufCrate {
|
||||
folder_name: config.folder_name,
|
||||
proto_paths,
|
||||
crate_path: config.crate_path,
|
||||
}
|
||||
}
|
||||
|
||||
fn protobuf_crate_name(&self) -> String {
|
||||
format!("{}/src/protobuf", self.crate_path)
|
||||
}
|
||||
|
||||
pub fn proto_file_output_dir(&self) -> String {
|
||||
let dir = format!("{}/proto", self.protobuf_crate_name());
|
||||
create_dir_if_not_exist(dir.as_ref());
|
||||
dir
|
||||
}
|
||||
|
||||
pub fn proto_struct_output_dir(&self) -> String {
|
||||
let dir = format!("{}/model", self.protobuf_crate_name());
|
||||
create_dir_if_not_exist(dir.as_ref());
|
||||
dir
|
||||
}
|
||||
|
||||
pub fn proto_model_mod_file(&self) -> String {
|
||||
format!("{}/mod.rs", self.proto_struct_output_dir())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FileProtoInfo {
|
||||
pub struct ProtoFile {
|
||||
pub file_name: String,
|
||||
pub structs: Vec<String>,
|
||||
pub enums: Vec<String>,
|
||||
pub generated_content: String,
|
||||
}
|
||||
|
||||
pub fn parse_crate_info_from_path(root: &str) -> Vec<CrateInfo> {
|
||||
pub fn parse_crate_info_from_path(root: &str) -> Vec<ProtobufCrate> {
|
||||
WalkDir::new(root)
|
||||
.into_iter()
|
||||
.filter_entry(|e| !is_hidden(e))
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|e| is_crate_dir(e))
|
||||
.flat_map(|e| {
|
||||
// Assert e.path().parent() will be the crate dir
|
||||
let path = e.path().parent().unwrap();
|
||||
let crate_path = path.to_str().unwrap().to_string();
|
||||
let crate_folder_name = path.file_stem().unwrap().to_str().unwrap().to_string();
|
||||
let flowy_config_file = format!("{}/Flowy.toml", crate_path);
|
||||
|
||||
if std::path::Path::new(&flowy_config_file).exists() {
|
||||
let config = FlowyConfig::from_toml_file(flowy_config_file.as_ref());
|
||||
let crate_path = path.to_str().unwrap().to_string();
|
||||
let proto_crate_paths = config
|
||||
.proto_crates
|
||||
.iter()
|
||||
.map(|name| format!("{}/{}", crate_path, name))
|
||||
.collect::<Vec<String>>();
|
||||
Some(CrateInfo {
|
||||
crate_folder_name,
|
||||
proto_crate_paths,
|
||||
crate_path,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<CrateInfo>>()
|
||||
.flat_map(|e| parse_crate_config_from(&e))
|
||||
.map(|crate_config| ProtobufCrate::from_config(crate_config))
|
||||
.collect::<Vec<ProtobufCrate>>()
|
||||
}
|
||||
|
||||
pub struct FlutterProtobufInfo {
|
@ -1,4 +1,4 @@
|
||||
use crate::proto::crate_info::{CrateProtoInfo, FileProtoInfo};
|
||||
use crate::proto::proto_info::{CrateProtoInfo, ProtoFile};
|
||||
use crate::util::{get_tera, read_file};
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::Write;
|
||||
@ -40,7 +40,7 @@ pub fn write_derive_meta(crate_infos: &Vec<CrateProtoInfo>, derive_meta_dir: &st
|
||||
.iter()
|
||||
.map(|ref crate_info| &crate_info.files)
|
||||
.flatten()
|
||||
.collect::<Vec<&FileProtoInfo>>();
|
||||
.collect::<Vec<&ProtoFile>>();
|
||||
|
||||
let structs: Vec<String> = file_proto_infos
|
||||
.iter()
|
||||
|
38
scripts/flowy-tool/src/util/crate_config.rs
Normal file
38
scripts/flowy-tool/src/util/crate_config.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use crate::config::FlowyConfig;
|
||||
|
||||
pub struct CrateConfig {
|
||||
pub(crate) crate_path: String,
|
||||
pub(crate) folder_name: String,
|
||||
pub(crate) flowy_config: FlowyConfig,
|
||||
}
|
||||
|
||||
impl CrateConfig {
|
||||
pub fn proto_paths(&self) -> Vec<String> {
|
||||
let proto_paths = self
|
||||
.flowy_config
|
||||
.proto_crates
|
||||
.iter()
|
||||
.map(|name| format!("{}/{}", self.crate_path, name))
|
||||
.collect::<Vec<String>>();
|
||||
proto_paths
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_crate_config_from(entry: &walkdir::DirEntry) -> Option<CrateConfig> {
|
||||
let path = entry.path().parent().unwrap();
|
||||
let crate_path = path.to_str().unwrap().to_string();
|
||||
let folder_name = path.file_stem().unwrap().to_str().unwrap().to_string();
|
||||
let config_path = format!("{}/Flowy.toml", crate_path);
|
||||
|
||||
if std::path::Path::new(&config_path).exists() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let flowy_config = FlowyConfig::from_toml_file(config_path.as_ref());
|
||||
|
||||
Some(CrateConfig {
|
||||
crate_path,
|
||||
folder_name,
|
||||
flowy_config,
|
||||
})
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use console::Style;
|
||||
use dialoguer::Confirm;
|
||||
|
||||
use similar::{ChangeTag, TextDiff};
|
||||
use std::{
|
||||
fs::{File, OpenOptions},
|
||||
@ -7,6 +7,7 @@ use std::{
|
||||
path::Path,
|
||||
};
|
||||
use tera::Tera;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
pub fn read_file(path: &str) -> Option<String> {
|
||||
let mut file = File::open(path).expect("Unable to open file");
|
||||
@ -20,7 +21,7 @@ pub fn read_file(path: &str) -> Option<String> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save_content_to_file_with_diff_prompt(content: &str, output_file: &str, force_write: bool) {
|
||||
pub fn save_content_to_file_with_diff_prompt(content: &str, output_file: &str, _force_write: bool) {
|
||||
if Path::new(output_file).exists() {
|
||||
let old_content = read_file(output_file).unwrap();
|
||||
let new_content = content.to_owned();
|
||||
@ -106,3 +107,50 @@ pub fn get_tera(directory: &str) -> Tera {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_crate_dir(e: &walkdir::DirEntry) -> bool {
|
||||
let cargo = e.path().file_stem().unwrap().to_str().unwrap().to_string();
|
||||
cargo == "Cargo".to_string()
|
||||
}
|
||||
|
||||
pub fn is_proto_file(e: &walkdir::DirEntry) -> bool {
|
||||
if e.path().extension().is_none() {
|
||||
return false;
|
||||
}
|
||||
let ext = e.path().extension().unwrap().to_str().unwrap().to_string();
|
||||
ext == "proto".to_string()
|
||||
}
|
||||
|
||||
pub fn is_hidden(entry: &walkdir::DirEntry) -> bool {
|
||||
entry
|
||||
.file_name()
|
||||
.to_str()
|
||||
.map(|s| s.starts_with("."))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn create_dir_if_not_exist(dir: &str) {
|
||||
if !std::path::Path::new(&dir).exists() {
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn walk_dir<F1, F2>(dir: &str, filter: F2, mut path_and_name: F1)
|
||||
where
|
||||
F1: FnMut(String, String),
|
||||
F2: Fn(&walkdir::DirEntry) -> bool,
|
||||
{
|
||||
for (path, name) in WalkDir::new(dir)
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|e| filter(e))
|
||||
.map(|e| {
|
||||
(
|
||||
e.path().to_str().unwrap().to_string(),
|
||||
e.path().file_stem().unwrap().to_str().unwrap().to_string(),
|
||||
)
|
||||
})
|
||||
{
|
||||
path_and_name(path, name);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
mod crate_config;
|
||||
mod file;
|
||||
|
||||
pub use crate_config::*;
|
||||
pub use file::*;
|
||||
|
Loading…
Reference in New Issue
Block a user