chore: auto import pb file

This commit is contained in:
appflowy 2022-06-17 16:42:18 +08:00
parent 40bcb63627
commit d30d42e841
17 changed files with 120 additions and 37 deletions

View file

@ -1,6 +1,6 @@
syntax = "proto3"; syntax = "proto3";
import "field_entities.proto";
import "field_entities.proto";
message CreateSelectOptionPayload { message CreateSelectOptionPayload {
FieldIdentifierPayload field_identifier = 1; FieldIdentifierPayload field_identifier = 1;
string option_name = 2; string option_name = 2;

View file

@ -1,6 +1,6 @@
syntax = "proto3"; syntax = "proto3";
import "cell_entities.proto";
import "cell_entities.proto";
message DateTypeOption { message DateTypeOption {
DateFormat date_format = 1; DateFormat date_format = 1;
TimeFormat time_format = 2; TimeFormat time_format = 2;

View file

@ -1,6 +1,6 @@
syntax = "proto3"; syntax = "proto3";
import "format.proto";
import "format.proto";
message NumberTypeOption { message NumberTypeOption {
NumberFormat format = 1; NumberFormat format = 1;
uint32 scale = 2; uint32 scale = 2;

View file

@ -1,6 +1,7 @@
syntax = "proto3"; syntax = "proto3";
import "cell_entities.proto";
import "cell_entities.proto";
import "cell_entities.proto";
message SingleSelectTypeOption { message SingleSelectTypeOption {
repeated SelectOption options = 1; repeated SelectOption options = 1;
bool disable_color = 2; bool disable_color = 2;

View file

@ -1,5 +1,4 @@
syntax = "proto3"; syntax = "proto3";
enum ErrorCode { enum ErrorCode {
Internal = 0; Internal = 0;
UserUnauthorized = 2; UserUnauthorized = 2;

View file

@ -1,6 +1,6 @@
syntax = "proto3"; syntax = "proto3";
import "view.proto";
import "view.proto";
message App { message App {
string id = 1; string id = 1;
string workspace_id = 2; string workspace_id = 2;

View file

@ -1,6 +1,7 @@
syntax = "proto3"; syntax = "proto3";
import "view.proto";
import "view.proto";
import "view.proto";
message ViewInfo { message ViewInfo {
string id = 1; string id = 1;
string belong_to_id = 2; string belong_to_id = 2;

View file

@ -1,7 +1,7 @@
syntax = "proto3"; syntax = "proto3";
import "app.proto"; import "app.proto";
import "view.proto"; import "view.proto";
message Workspace { message Workspace {
string id = 1; string id = 1;
string name = 2; string name = 2;

View file

@ -1,5 +1,4 @@
syntax = "proto3"; syntax = "proto3";
message Field { message Field {
string id = 1; string id = 1;
string name = 2; string name = 2;

View file

@ -1,6 +1,5 @@
syntax = "proto3"; syntax = "proto3";
import "field.proto"; import "field.proto";
message Grid { message Grid {
string id = 1; string id = 1;
repeated FieldOrder field_orders = 2; repeated FieldOrder field_orders = 2;

View file

@ -1,5 +1,4 @@
syntax = "proto3"; syntax = "proto3";
message ViewExtData { message ViewExtData {
ViewFilter filter = 1; ViewFilter filter = 1;
ViewGroup group = 2; ViewGroup group = 2;

View file

@ -1,6 +1,7 @@
syntax = "proto3"; syntax = "proto3";
import "revision.proto";
import "revision.proto";
import "revision.proto";
message CreateTextBlockParams { message CreateTextBlockParams {
string id = 1; string id = 1;
RepeatedRevision revisions = 2; RepeatedRevision revisions = 2;

View file

@ -1,6 +1,6 @@
syntax = "proto3"; syntax = "proto3";
import "revision.proto";
import "revision.proto";
message ClientRevisionWSData { message ClientRevisionWSData {
string object_id = 1; string object_id = 1;
ClientRevisionWSDataType ty = 2; ClientRevisionWSDataType ty = 2;

View file

@ -2,7 +2,7 @@
#![allow(dead_code)] #![allow(dead_code)]
#![allow(unused_imports)] #![allow(unused_imports)]
#![allow(unused_results)] #![allow(unused_results)]
use crate::code_gen::protobuf_file::template::{EnumTemplate, StructTemplate}; use crate::code_gen::protobuf_file::template::{EnumTemplate, StructTemplate, RUST_TYPE_MAP};
use crate::code_gen::protobuf_file::{parse_crate_info_from_path, ProtoFile, ProtobufCrateContext}; use crate::code_gen::protobuf_file::{parse_crate_info_from_path, ProtoFile, ProtobufCrateContext};
use crate::code_gen::util::*; use crate::code_gen::util::*;
use fancy_regex::Regex; use fancy_regex::Regex;
@ -57,19 +57,28 @@ fn parse_files_protobuf(proto_crate_path: &Path, proto_output_path: &Path) -> Ve
let structs = get_ast_structs(&ast); let structs = get_ast_structs(&ast);
let proto_file = format!("{}.proto", &file_name); let proto_file = format!("{}.proto", &file_name);
let proto_file_path = path_string_with_component(proto_output_path, vec![&proto_file]); let proto_file_path = path_string_with_component(proto_output_path, vec![&proto_file]);
let mut proto_file_content = find_proto_syntax(proto_file_path.as_ref()); let proto_syntax = find_proto_syntax(proto_file_path.as_ref());
let mut proto_content = String::new();
// The types that are not defined in the current file.
let mut ref_types: Vec<String> = vec![];
structs.iter().for_each(|s| { structs.iter().for_each(|s| {
let mut struct_template = StructTemplate::new(); let mut struct_template = StructTemplate::new();
struct_template.set_message_struct_name(&s.name); struct_template.set_message_struct_name(&s.name);
s.fields.iter().filter(|f| f.attrs.pb_index().is_some()).for_each(|f| { s.fields
struct_template.set_field(f); .iter()
}); .filter(|field| field.attrs.pb_index().is_some())
.for_each(|field| {
ref_types.push(field.ty_as_str().to_string());
struct_template.set_field(field);
});
let s = struct_template.render().unwrap(); let s = struct_template.render().unwrap();
proto_file_content.push_str(s.as_ref());
proto_file_content.push('\n'); proto_content.push_str(s.as_ref());
proto_content.push('\n');
}); });
let enums = get_ast_enums(&ast); let enums = get_ast_enums(&ast);
@ -77,17 +86,26 @@ fn parse_files_protobuf(proto_crate_path: &Path, proto_output_path: &Path) -> Ve
let mut enum_template = EnumTemplate::new(); let mut enum_template = EnumTemplate::new();
enum_template.set_message_enum(e); enum_template.set_message_enum(e);
let s = enum_template.render().unwrap(); let s = enum_template.render().unwrap();
proto_file_content.push_str(s.as_ref()); proto_content.push_str(s.as_ref());
proto_file_content.push('\n'); ref_types.push(e.name.clone());
proto_content.push('\n');
}); });
if !enums.is_empty() || !structs.is_empty() { if !enums.is_empty() || !structs.is_empty() {
let structs: Vec<String> = structs.iter().map(|s| s.name.clone()).collect();
let enums: Vec<String> = enums.iter().map(|e| e.name.clone()).collect();
ref_types.retain(|s| !structs.contains(&s));
ref_types.retain(|s| !enums.contains(&s));
let info = ProtoFile { let info = ProtoFile {
file_path: path.clone(), file_path: path.clone(),
file_name: file_name.clone(), file_name: file_name.clone(),
structs: structs.iter().map(|s| s.name.clone()).collect(), ref_types,
enums: enums.iter().map(|e| e.name.clone()).collect(), structs,
generated_content: proto_file_content.clone(), enums,
syntax: proto_syntax,
content: proto_content,
}; };
gen_proto_vec.push(info); gen_proto_vec.push(info);
} }
@ -148,12 +166,12 @@ pub struct Struct<'a> {
lazy_static! { lazy_static! {
static ref SYNTAX_REGEX: Regex = Regex::new("syntax.*;").unwrap(); static ref SYNTAX_REGEX: Regex = Regex::new("syntax.*;").unwrap();
static ref IMPORT_REGEX: Regex = Regex::new("(import\\s).*;").unwrap(); // static ref IMPORT_REGEX: Regex = Regex::new("(import\\s).*;").unwrap();
} }
fn find_proto_syntax(path: &str) -> String { fn find_proto_syntax(path: &str) -> String {
if !Path::new(path).exists() { if !Path::new(path).exists() {
return String::from("syntax = \"proto3\";\n\n"); return String::from("syntax = \"proto3\";\n");
} }
let mut result = String::new(); let mut result = String::new();
@ -165,13 +183,12 @@ fn find_proto_syntax(path: &str) -> String {
////Result<Option<Match<'t>>> ////Result<Option<Match<'t>>>
if let Ok(Some(m)) = SYNTAX_REGEX.find(line) { if let Ok(Some(m)) = SYNTAX_REGEX.find(line) {
result.push_str(m.as_str()); result.push_str(m.as_str());
result.push('\n');
} }
if let Ok(Some(m)) = IMPORT_REGEX.find(line) { // if let Ok(Some(m)) = IMPORT_REGEX.find(line) {
result.push_str(m.as_str()); // result.push_str(m.as_str());
result.push('\n'); // result.push('\n');
} // }
}); });
result.push('\n'); result.push('\n');

View file

@ -7,6 +7,7 @@ use crate::code_gen::protobuf_file::proto_info::ProtobufCrateContext;
use crate::code_gen::protobuf_file::ProtoFile; use crate::code_gen::protobuf_file::ProtoFile;
use crate::code_gen::util::*; use crate::code_gen::util::*;
use crate::code_gen::ProtoCache; use crate::code_gen::ProtoCache;
use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::path::Path; use std::path::Path;
use std::{fs::OpenOptions, io::Write}; use std::{fs::OpenOptions, io::Write};
@ -49,16 +50,66 @@ impl ProtoGenerator {
} }
fn write_proto_files(crate_contexts: &[ProtobufCrateContext]) { fn write_proto_files(crate_contexts: &[ProtobufCrateContext]) {
let file_path_content_map = crate_contexts
.iter()
.map(|ctx| {
ctx.files
.iter()
.map(|file| {
(
file.file_path.clone(),
ProtoFileSymbol {
file_name: file.file_name.clone(),
symbols: file.symbols(),
},
)
})
.collect::<HashMap<String, ProtoFileSymbol>>()
})
.flatten()
.collect::<HashMap<String, ProtoFileSymbol>>();
for context in crate_contexts { for context in crate_contexts {
let dir = context.protobuf_crate.proto_output_path(); let dir = context.protobuf_crate.proto_output_path();
context.files.iter().for_each(|info| { context.files.iter().for_each(|file| {
let proto_file = format!("{}.proto", &info.file_name); // syntax
let mut file_content = file.syntax.clone();
// import
file_content.push_str(&gen_import_content(&file, &file_path_content_map));
// content
file_content.push_str(&file.content);
let proto_file = format!("{}.proto", &file.file_name);
let proto_file_path = path_string_with_component(&dir, vec![&proto_file]); let proto_file_path = path_string_with_component(&dir, vec![&proto_file]);
save_content_to_file_with_diff_prompt(&info.generated_content, proto_file_path.as_ref()); save_content_to_file_with_diff_prompt(&file_content, proto_file_path.as_ref());
}); });
} }
} }
fn gen_import_content(current_file: &ProtoFile, file_path_symbols_map: &HashMap<String, ProtoFileSymbol>) -> String {
let mut import_content = String::new();
file_path_symbols_map
.iter()
.for_each(|(file_path, proto_file_symbols)| {
if file_path != &current_file.file_path {
current_file.ref_types.iter().for_each(|ref_type| {
if proto_file_symbols.symbols.contains(ref_type) {
import_content.push_str(&format!("import \"{}.proto\";\n", proto_file_symbols.file_name));
}
});
}
});
import_content
}
struct ProtoFileSymbol {
file_name: String,
symbols: Vec<String>,
}
fn write_rust_crate_mod_file(crate_contexts: &[ProtobufCrateContext]) { fn write_rust_crate_mod_file(crate_contexts: &[ProtobufCrateContext]) {
for context in crate_contexts { for context in crate_contexts {
let mod_path = context.protobuf_crate.proto_model_mod_file(); let mod_path = context.protobuf_crate.proto_model_mod_file();

View file

@ -106,8 +106,24 @@ pub struct ProtoFile {
pub file_path: String, pub file_path: String,
pub file_name: String, pub file_name: String,
pub structs: Vec<String>, pub structs: Vec<String>,
pub ref_types: Vec<String>,
pub enums: Vec<String>, pub enums: Vec<String>,
pub generated_content: String, // proto syntax. "proto3" or "proto2"
pub syntax: String,
// proto message content
pub content: String,
}
impl ProtoFile {
pub fn symbols(&self) -> Vec<String> {
let mut symbols = self.structs.clone();
let mut enum_symbols = self.enums.clone();
symbols.append(&mut enum_symbols);
symbols
}
} }
pub fn parse_crate_info_from_path(roots: Vec<String>) -> Vec<ProtobufCrate> { pub fn parse_crate_info_from_path(roots: Vec<String>) -> Vec<ProtobufCrate> {

View file

@ -4,7 +4,7 @@ use phf::phf_map;
use tera::Context; use tera::Context;
// Protobuf data type : https://developers.google.com/protocol-buffers/docs/proto3 // Protobuf data type : https://developers.google.com/protocol-buffers/docs/proto3
static RUST_TYPE_MAP: phf::Map<&'static str, &'static str> = phf_map! { pub static RUST_TYPE_MAP: phf::Map<&'static str, &'static str> = phf_map! {
"String" => "string", "String" => "string",
"i64" => "int64", "i64" => "int64",
"i32" => "int32", "i32" => "int32",