bin.rs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. use std::{
  2. env, panic,
  3. path::{Path, PathBuf},
  4. process,
  5. };
  6. use clap::{clap_app, ArgMatches};
  7. use log::error;
  8. use librojo::commands;
  9. fn make_path_absolute(value: &Path) -> PathBuf {
  10. if value.is_absolute() {
  11. PathBuf::from(value)
  12. } else {
  13. let current_dir = env::current_dir().unwrap();
  14. current_dir.join(value)
  15. }
  16. }
  17. fn main() {
  18. let app = clap_app!(Rojo =>
  19. (version: env!("CARGO_PKG_VERSION"))
  20. (author: env!("CARGO_PKG_AUTHORS"))
  21. (about: env!("CARGO_PKG_DESCRIPTION"))
  22. (@arg verbose: --verbose -v +multiple +global "Sets verbosity level. Can be specified multiple times.")
  23. (@subcommand init =>
  24. (about: "Creates a new Rojo project.")
  25. (@arg PATH: "Path to the place to create the project. Defaults to the current directory.")
  26. (@arg kind: --kind +takes_value "The kind of project to create, 'place' or 'model'. Defaults to place.")
  27. )
  28. (@subcommand serve =>
  29. (about: "Serves the project's files for use with the Rojo Studio plugin.")
  30. (@arg PROJECT: "Path to the project to serve. Defaults to the current directory.")
  31. (@arg port: --port +takes_value "The port to listen on. Defaults to 34872.")
  32. )
  33. (@subcommand build =>
  34. (about: "Generates a model or place file from the project.")
  35. (@arg PROJECT: "Path to the project to serve. Defaults to the current directory.")
  36. (@arg output: --output -o +takes_value +required "Where to output the result.")
  37. )
  38. (@subcommand upload =>
  39. (about: "Generates a place or model file out of the project and uploads it to Roblox.")
  40. (@arg PROJECT: "Path to the project to upload. Defaults to the current directory.")
  41. (@arg kind: --kind +takes_value "The kind of asset to generate, 'place', or 'model'. Defaults to place.")
  42. (@arg cookie: --cookie +takes_value "Authenication cookie to use. If not specified, Rojo will attempt to find one from the system automatically.")
  43. (@arg asset_id: --asset_id +takes_value +required "Asset ID to upload to.")
  44. )
  45. );
  46. let matches = app.get_matches();
  47. {
  48. let verbosity = matches.occurrences_of("verbose");
  49. let log_filter = match verbosity {
  50. 0 => "warn",
  51. 1 => "warn,librojo=info",
  52. 2 => "warn,librojo=trace",
  53. _ => "trace",
  54. };
  55. let log_env = env_logger::Env::default().default_filter_or(log_filter);
  56. env_logger::Builder::from_env(log_env)
  57. .default_format_timestamp(false)
  58. .init();
  59. }
  60. let result = panic::catch_unwind(|| match matches.subcommand() {
  61. ("init", Some(sub_matches)) => start_init(sub_matches),
  62. ("serve", Some(sub_matches)) => start_serve(sub_matches),
  63. ("build", Some(sub_matches)) => start_build(sub_matches),
  64. ("upload", Some(sub_matches)) => start_upload(sub_matches),
  65. _ => eprintln!("Usage: rojo <SUBCOMMAND>\nUse 'rojo help' for more help."),
  66. });
  67. if let Err(error) = result {
  68. let message = match error.downcast_ref::<&str>() {
  69. Some(message) => message.to_string(),
  70. None => match error.downcast_ref::<String>() {
  71. Some(message) => message.clone(),
  72. None => "<no message>".to_string(),
  73. },
  74. };
  75. show_crash_message(&message);
  76. process::exit(1);
  77. }
  78. }
  79. fn show_crash_message(message: &str) {
  80. error!("Rojo crashed!");
  81. error!("This is a bug in Rojo.");
  82. error!("");
  83. error!("Please consider filing a bug: https://github.com/rojo-rbx/rojo/issues");
  84. error!("");
  85. error!("Details: {}", message);
  86. }
  87. fn start_init(sub_matches: &ArgMatches) {
  88. let fuzzy_project_path =
  89. make_path_absolute(Path::new(sub_matches.value_of("PATH").unwrap_or("")));
  90. let kind = sub_matches.value_of("kind");
  91. let options = commands::InitOptions {
  92. fuzzy_project_path,
  93. kind,
  94. };
  95. match commands::init(&options) {
  96. Ok(_) => {}
  97. Err(e) => {
  98. error!("{}", e);
  99. process::exit(1);
  100. }
  101. }
  102. }
  103. fn start_serve(sub_matches: &ArgMatches) {
  104. let fuzzy_project_path = match sub_matches.value_of("PROJECT") {
  105. Some(v) => make_path_absolute(Path::new(v)),
  106. None => std::env::current_dir().unwrap(),
  107. };
  108. let port = match sub_matches.value_of("port") {
  109. Some(v) => match v.parse::<u16>() {
  110. Ok(port) => Some(port),
  111. Err(_) => {
  112. error!("Invalid port {}", v);
  113. process::exit(1);
  114. }
  115. },
  116. None => None,
  117. };
  118. let options = commands::ServeOptions {
  119. fuzzy_project_path,
  120. port,
  121. };
  122. match commands::serve(&options) {
  123. Ok(_) => {}
  124. Err(e) => {
  125. error!("{}", e);
  126. process::exit(1);
  127. }
  128. }
  129. }
  130. fn start_build(sub_matches: &ArgMatches) {
  131. let fuzzy_project_path = match sub_matches.value_of("PROJECT") {
  132. Some(v) => make_path_absolute(Path::new(v)),
  133. None => std::env::current_dir().unwrap(),
  134. };
  135. let output_file = make_path_absolute(Path::new(sub_matches.value_of("output").unwrap()));
  136. let options = commands::BuildOptions {
  137. fuzzy_project_path,
  138. output_file,
  139. output_kind: None, // TODO: Accept from argument
  140. };
  141. match commands::build(&options) {
  142. Ok(_) => {}
  143. Err(e) => {
  144. error!("{}", e);
  145. process::exit(1);
  146. }
  147. }
  148. }
  149. fn start_upload(sub_matches: &ArgMatches) {
  150. let fuzzy_project_path = match sub_matches.value_of("PROJECT") {
  151. Some(v) => make_path_absolute(Path::new(v)),
  152. None => std::env::current_dir().unwrap(),
  153. };
  154. let kind = sub_matches.value_of("kind");
  155. let auth_cookie = sub_matches.value_of("cookie").map(Into::into);
  156. let asset_id: u64 = {
  157. let arg = sub_matches.value_of("asset_id").unwrap();
  158. match arg.parse() {
  159. Ok(v) => v,
  160. Err(_) => {
  161. error!("Invalid place ID {}", arg);
  162. process::exit(1);
  163. }
  164. }
  165. };
  166. let options = commands::UploadOptions {
  167. fuzzy_project_path,
  168. auth_cookie,
  169. asset_id,
  170. kind,
  171. };
  172. match commands::upload(options) {
  173. Ok(_) => {}
  174. Err(e) => {
  175. error!("{}", e);
  176. process::exit(1);
  177. }
  178. }
  179. }