diff --git a/juniper-from-schema-build-tests/file/build.rs b/juniper-from-schema-build-tests/file/build.rs index b629682..170114d 100644 --- a/juniper-from-schema-build-tests/file/build.rs +++ b/juniper-from-schema-build-tests/file/build.rs @@ -1,5 +1,5 @@ fn main() { - juniper_from_schema_build::configure_for_file("schema.graphql") + juniper_from_schema_build::configure_for_files(vec!["schema/*.graphql"]) .context_type("()") .error_type("MyError") .compile() diff --git a/juniper-from-schema-build-tests/file/schema.graphql b/juniper-from-schema-build-tests/file/schema/schema1.graphql similarity index 69% rename from juniper-from-schema-build-tests/file/schema.graphql rename to juniper-from-schema-build-tests/file/schema/schema1.graphql index bd94ae1..295db89 100644 --- a/juniper-from-schema-build-tests/file/schema.graphql +++ b/juniper-from-schema-build-tests/file/schema/schema1.graphql @@ -3,5 +3,5 @@ schema { } type Query { - ping: Boolean! + foo: Foo } diff --git a/juniper-from-schema-build-tests/file/schema/schema2.graphql b/juniper-from-schema-build-tests/file/schema/schema2.graphql new file mode 100644 index 0000000..061e5fd --- /dev/null +++ b/juniper-from-schema-build-tests/file/schema/schema2.graphql @@ -0,0 +1,3 @@ +type Foo { + ping: Boolean! +} \ No newline at end of file diff --git a/juniper-from-schema-build/src/lib.rs b/juniper-from-schema-build/src/lib.rs index 1532adb..bfaaeae 100644 --- a/juniper-from-schema-build/src/lib.rs +++ b/juniper-from-schema-build/src/lib.rs @@ -73,19 +73,19 @@ pub fn configure_for_schema_literal(schema: &str) -> CodeGen { } /// Simple compilation of a GraphQL schema file. -pub fn compile_file>(path: P) -> Result<(), Box> { - configure_for_file(path).compile() +pub fn compile_files>(paths: Vec

) -> Result<(), Box> { + configure_for_files(paths).compile() } /// Configure a [`CodeGen`] with a GraphQL schema file. /// /// [`CodeGen`]: struct.CodeGen.html -pub fn configure_for_file>(path: P) -> CodeGen { +pub fn configure_for_files>(paths: Vec

) -> CodeGen { let root = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); - let path = root.join(path); + let paths = paths.into_iter().map(|path| root.join(path)).collect(); CodeGen { - schema: SchemaLocation::File(path), + schema: SchemaLocation::Files(paths), context_type: None, error_type: None, } @@ -101,7 +101,7 @@ pub struct CodeGen { #[derive(Debug)] enum SchemaLocation { - File(PathBuf), + Files(Vec), Literal(String), } @@ -132,8 +132,8 @@ impl CodeGen { let dest_path = Path::new(&out_dir).join("juniper_from_schema_graphql_schema.rs"); let mut code_gen = match self.schema { - SchemaLocation::File(path) => { - juniper_from_schema_code_gen::CodeGen::build_from_schema_file(path) + SchemaLocation::Files(paths) => { + juniper_from_schema_code_gen::CodeGen::build_from_schema_files(paths) } SchemaLocation::Literal(schema) => { juniper_from_schema_code_gen::CodeGen::build_from_schema_literal(schema) diff --git a/juniper-from-schema-code-gen/Cargo.toml b/juniper-from-schema-code-gen/Cargo.toml index 204c2cf..b8e7dcf 100644 --- a/juniper-from-schema-code-gen/Cargo.toml +++ b/juniper-from-schema-code-gen/Cargo.toml @@ -19,6 +19,7 @@ graphql-parser = "0.3" proc-macro2 = "1" heck = "0.3" colored = "1.8" +glob = "0.3" [dev_dependencies] version-sync = "0.8" diff --git a/juniper-from-schema-code-gen/src/lib.rs b/juniper-from-schema-code-gen/src/lib.rs index 960ff98..aa46034 100644 --- a/juniper-from-schema-code-gen/src/lib.rs +++ b/juniper-from-schema-code-gen/src/lib.rs @@ -35,9 +35,9 @@ pub struct CodeGen { } impl CodeGen { - pub fn build_from_schema_file(path: PathBuf) -> CodeGenBuilder { + pub fn build_from_schema_files(paths: Vec) -> CodeGenBuilder { CodeGenBuilder { - schema: SchemaLocation::File(path), + schema: SchemaLocation::Files(paths), context_type: None, error_type: None, } @@ -52,12 +52,32 @@ impl CodeGen { } pub fn generate_code(self) -> Result { - let (schema, schema_path) = match self.schema { - SchemaLocation::File(path) => ( - std::fs::read_to_string(&path).map_err(Error::Io)?, - Some(path), - ), - SchemaLocation::Literal(schema) => (schema, None), + let (schema, schema_paths) = match self.schema { + SchemaLocation::Files(glob_patterns) => { + // Each input path is a glob pattern, expand each one and concat + // them all together + let mut paths: Vec = Vec::new(); + for path in glob_patterns { + let globbed_paths = glob::glob( + path.to_str() + .expect("Invalid UTF-8 characters in file name"), + ) + .map_err(Error::SchemaPathError)?; + for path in globbed_paths { + let path = path.map_err(Error::SchemaGlobError)?; + paths.push(path); + } + } + + // Read each schema file and put it all in one string + let schema: String = paths + .iter() + .map(|path| std::fs::read_to_string(&path)) + .collect::>() + .map_err(Error::Io)?; + (schema, paths) + } + SchemaLocation::Literal(schema) => (schema, Vec::new()), }; let doc = match parse_schema(&schema) { @@ -84,7 +104,8 @@ impl CodeGen { eprintln!("{}", tokens); } - if let Some(path) = schema_path { + // Force a Rust recompile whenever the schema changes + for path in schema_paths { include_literal_schema(&mut tokens, path.as_path()); } @@ -118,6 +139,10 @@ fn include_literal_schema(tokens: &mut proc_macro2::TokenStream, schema_path: &P #[derive(Debug)] pub enum Error { + /// User passed an invalid glob pattern + SchemaPathError(glob::PatternError), + /// Glob pattern couldn't be expanded (e.g. permission denied) + SchemaGlobError(glob::GlobError), SchemaParseError(graphql_parser::schema::ParseError), CodeGenErrors { errors: Vec, @@ -129,6 +154,8 @@ pub enum Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + Error::SchemaPathError(inner) => write!(f, "{}", inner), + Error::SchemaGlobError(inner) => write!(f, "{}", inner), Error::SchemaParseError(inner) => write!(f, "{}", inner), Error::CodeGenErrors { errors, schema } => { assert!( @@ -186,7 +213,7 @@ impl CodeGenBuilder { #[derive(Debug)] enum SchemaLocation { - File(PathBuf), + Files(Vec), Literal(String), } diff --git a/juniper-from-schema-proc-macro/src/lib.rs b/juniper-from-schema-proc-macro/src/lib.rs index 0708b10..694e1ab 100644 --- a/juniper-from-schema-proc-macro/src/lib.rs +++ b/juniper-from-schema-proc-macro/src/lib.rs @@ -21,7 +21,7 @@ use parse_input::GraphqlSchemaFromFileInput; #[proc_macro] pub fn graphql_schema_from_file(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let GraphqlSchemaFromFileInput { - schema_path, + schema_paths, context_type, error_type, } = match syn::parse::(input) { @@ -29,7 +29,7 @@ pub fn graphql_schema_from_file(input: proc_macro::TokenStream) -> proc_macro::T Err(e) => return e.to_compile_error().into(), }; - let mut builder = CodeGen::build_from_schema_file(schema_path); + let mut builder = CodeGen::build_from_schema_files(schema_paths); if let Some(context_type) = context_type { builder = builder.context_type(context_type); } diff --git a/juniper-from-schema-proc-macro/src/parse_input.rs b/juniper-from-schema-proc-macro/src/parse_input.rs index f8c3359..bae132b 100644 --- a/juniper-from-schema-proc-macro/src/parse_input.rs +++ b/juniper-from-schema-proc-macro/src/parse_input.rs @@ -7,7 +7,7 @@ use syn::{ #[derive(Debug)] pub struct GraphqlSchemaFromFileInput { - pub schema_path: PathBuf, + pub schema_paths: Vec, pub error_type: Option, pub context_type: Option, } @@ -56,7 +56,9 @@ impl Parse for GraphqlSchemaFromFileInput { } Ok(GraphqlSchemaFromFileInput { - schema_path, + // Only supporting single paths for macro, since long term we're + // moving towards the build.rs style + schema_paths: vec![schema_path], error_type, context_type, })