This repository has been archived by the owner on Aug 24, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
Add cargo-spatial-codegen tool #49
Closed
randomPoison
wants to merge
35
commits into
jamiebrynes7:master
from
randomPoison:example-setup-script
Closed
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
2aaa589
Initial setup logic in project-example
randomPoison 14dda35
Run the schema compiler on all schema files
randomPoison aae6322
Run protoc and remove temp dir
randomPoison aa8a226
Simplify arguments for the setup subcommand
randomPoison 6b15455
Update README.md and remove setup.sh
randomPoison 7810b5d
Cleanup logic in main() around setup vs worker
randomPoison b2b611b
Fix slashes in paths in README.md
randomPoison 3245abb
Make setup its own binary in spatialos-sdk-tools
randomPoison e705498
Change globbing logic to match original bash script
randomPoison 9ffccf3
Fixup error handling
randomPoison 57bf2d0
Cleanup spacing and comments
randomPoison 52f7a3d
Cleanup error handling in example
randomPoison e7d788e
Add clearer comments in example
randomPoison 9041848
Rename schema_dir to output_dir
randomPoison f713abd
Normalize path separators
randomPoison a88d8c0
Run rustfmt
randomPoison 4a9b376
Generate bundle.json as part of setup
randomPoison 1a5171a
Allow user to specify more schema paths
randomPoison a105262
Fix #[structopt] attribute
randomPoison 877acc2
Fix the --schema_path argument to schema_compiler
randomPoison b788212
Don't append bin to output_dir
randomPoison 0c89058
Merge branch 'master' into example-setup-script
randomPoison 0f20be4
Add logging to setup
randomPoison 926f78f
Run code generation as part of setup
randomPoison d3d08b1
Delete codegen.sh
randomPoison dd1275a
Make the output dir a flag, update docs
randomPoison db68932
Remove leading ./ from paths because it trips up schema_compiler
randomPoison 5ef7ca3
Update docs and comments for setup
randomPoison ad94734
Delete and ignore generated bindings
randomPoison 661412d
Fix .gitignore for generated bindings
randomPoison 1cc6817
Rename setup to cargo-spatial-codegen
randomPoison 5baba10
Add add_schemas helper function
randomPoison 73477f5
Remove invocation of protoc
randomPoison 8f2a71e
Cleanup error handling for code generation
randomPoison 3ec7231
Actually check the exit status of schema_compiler
randomPoison File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
use log::*; | ||
use simplelog::*; | ||
use spatialos_sdk_code_generator::{generator, schema_bundle}; | ||
use std::ffi::OsString; | ||
use std::fs::{self, File}; | ||
use std::io::prelude::*; | ||
use std::path::*; | ||
use std::process::Command; | ||
use structopt::StructOpt; | ||
use tap::*; | ||
|
||
fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
let Opt { | ||
spatial_lib_dir, | ||
schema_paths, | ||
codegen, | ||
verbose, | ||
output_dir, | ||
} = Opt::from_args(); | ||
|
||
// Initialize the logger. | ||
let verbosity = if verbose { | ||
LevelFilter::Trace | ||
} else { | ||
LevelFilter::Warn | ||
}; | ||
SimpleLogger::init(verbosity, Default::default()).expect("Failed to setup logger"); | ||
|
||
let output_dir = normalize(output_dir); | ||
|
||
let spatial_lib_dir = spatial_lib_dir | ||
.or_else(|| std::env::var("SPATIAL_LIB_DIR").map(Into::into).ok()) | ||
.ok_or("--spatial-lib-dir argument must be specified or the SPATIAL_LIB_DIR environment variable must be set")?; | ||
|
||
// Determine the paths the the schema compiler and protoc relative the the lib | ||
// dir path. | ||
let schema_compiler_path = normalize(spatial_lib_dir.join("schema-compiler/schema_compiler")); | ||
let std_lib_path = normalize(spatial_lib_dir.join("std-lib")); | ||
|
||
// Calculate the various output directories relative to `output_dir`. | ||
let bundle_json_path = output_dir.join("bundle.json"); | ||
|
||
// Create the output directories if they don't already exist. | ||
fs::create_dir_all(&output_dir) | ||
.map_err(|_| format!("Failed to create {}", output_dir.display()))?; | ||
|
||
// Run the schema compiler for each of the schema files in std-lib/improbable. | ||
let schema_path_arg = OsString::from("--schema_path=").tap(|arg| arg.push(&std_lib_path)); | ||
let bundle_json_arg = | ||
OsString::from("--bundle_json_out=").tap(|arg| arg.push(&bundle_json_path)); | ||
let descriptor_out_arg = OsString::from("--descriptor_set_out=") | ||
.tap(|arg| arg.push(normalize(output_dir.join("schema.descriptor")))); | ||
let mut command = Command::new(&schema_compiler_path); | ||
command | ||
.arg(&schema_path_arg) | ||
.arg(&bundle_json_arg) | ||
.arg(&descriptor_out_arg) | ||
.arg("--load_all_schema_on_schema_path"); | ||
|
||
for schema_path in &schema_paths { | ||
let arg = OsString::from("--schema_path=").tap(|arg| arg.push(normalize(schema_path))); | ||
command.arg(&arg); | ||
} | ||
|
||
// Add all schema files in the std lib. | ||
add_schemas(&std_lib_path.join("improbable"), &mut command); | ||
|
||
// Add all user-provided schemas. | ||
for schema_path in &schema_paths { | ||
add_schemas(schema_path, &mut command); | ||
} | ||
|
||
trace!("{:#?}", command); | ||
let status = command | ||
.status() | ||
.map_err(|_| "Failed to compile schema files")?; | ||
|
||
if !status.success() { | ||
return Err("Failed to run schema compilation")?; | ||
} | ||
|
||
// If the user specified the `--codegen` flag, run code generation with the bundle file | ||
// that we just generated. | ||
if let Some(codegen_out_path) = codegen { | ||
// Load bundle.json, which describes the schema definitions for all components. | ||
let mut input_file = | ||
File::open(&bundle_json_path).map_err(|_| "Failed to open bundle.json")?; | ||
let mut contents = String::new(); | ||
input_file | ||
.read_to_string(&mut contents) | ||
.map_err(|_| "Failed to read contents of bundle.json")?; | ||
|
||
// Run code generation. | ||
let bundle = schema_bundle::load_bundle(&contents) | ||
.map_err(|_| "Failed to parse contents of bundle.json")?; | ||
let generated_file = generator::generate_code(bundle); | ||
|
||
// Write the generated code to the output file. | ||
File::create(codegen_out_path) | ||
.map_err(|_| "Unable to create codegen output file")? | ||
.write_all(generated_file.as_bytes()) | ||
.map_err(|_| "Failed to write generated code to file")?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
#[derive(Debug, StructOpt)] | ||
#[structopt( | ||
name = "cargo-spatial-codegen", | ||
rename_all = "kebab-case", | ||
about = "Perform schema compilation and code generation for a Rust SpatialOS project." | ||
)] | ||
struct Opt { | ||
/// The path to your local installation of the SpatialOS SDK | ||
/// | ||
/// If not specified, uses the SPATIAL_OS_DIR environment variable instead. Will fail | ||
/// with an error if neither is set. | ||
#[structopt(long, short = "l", parse(from_os_str))] | ||
spatial_lib_dir: Option<PathBuf>, | ||
|
||
/// A directory to search for schema files | ||
/// | ||
/// The directory will be searched recursively for all .schema files. Any schema | ||
/// files found will be included in compilation. Can be specified multiple times, | ||
/// e.g. `setup -s foo/schemas -s bar/schemas -o schemas/bin`. | ||
#[structopt(long = "schema-path", short = "s", parse(from_os_str))] | ||
schema_paths: Vec<PathBuf>, | ||
|
||
/// Display detailed log output | ||
#[structopt(long, short)] | ||
verbose: bool, | ||
|
||
/// Perform code generation and put the output in the specified file | ||
/// | ||
/// If not specified, will not perform code generation. | ||
#[structopt(long, short = "c", parse(from_os_str))] | ||
codegen: Option<PathBuf>, | ||
|
||
/// The path the output directory for the project | ||
#[structopt(long, short, parse(from_os_str))] | ||
output_dir: PathBuf, | ||
} | ||
|
||
/// HACK: Normalizes the separators in `path`. | ||
/// | ||
/// This is necessary in order to be robust on Windows, as well as work around | ||
/// some idiosyncrasies with schema_compiler and protoc. Currently, | ||
/// schema_compiler and protoc get tripped up if you have paths with mixed path | ||
/// separators (i.e. mixing '\' and '/'). This function normalizes paths to use | ||
/// the same separators everywhere, ensuring that we can be robust regardless of | ||
/// how the user specifies their paths. It also removes any current dir segments | ||
/// ("./"), as they can trip up schema_compiler and protoc as well. | ||
/// | ||
/// Improbable has noted that they are aware of these issues and will fix them | ||
/// at some point in the future. | ||
fn normalize<P: AsRef<std::path::Path>>(path: P) -> PathBuf { | ||
path.as_ref() | ||
.components() | ||
.filter(|&comp| comp != Component::CurDir) | ||
.collect() | ||
} | ||
|
||
/// Recursively searches `path` for `.schema` files and adds them to `command`. | ||
fn add_schemas(path: &PathBuf, command: &mut Command) { | ||
let schema_glob = path.join("**/*.schema"); | ||
for entry in glob::glob(schema_glob.to_str().unwrap()) | ||
.unwrap() | ||
.filter_map(Result::ok) | ||
{ | ||
command.arg(&entry); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Generated bindings to SpatialOS components, shouldn't be committed. | ||
generated_code.rs | ||
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an argument that while codegen is under heavy development, having some example code checked in makes it a lot easier to review rather than t4 templates
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's a fair point, though I think it would make more sense to have small, controlled examples as part of the spatialos-sdk-code-generator crate, rather than using the example project for that purpose. That said, I'm happy to restore
generated_code.rs
if you'd prefer 🙂