summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorkomaeda <819880950@qq.com>2019-01-23 22:04:01 +0100
committerGitHub <noreply@github.com>2019-01-23 22:04:01 +0100
commitdf3389cfb04d575b7fdee92e0dac42efd901a025 (patch)
tree1e6c3681a2c65933d52bfb7f0e2abaf734d1e403 /src
parent5a671079d6c4528fdab30937912099d45c029b49 (diff)
parent92072f39ac6b334c27f08de4b5c408b0e98784e2 (diff)
Merge pull request #106 from rustlings/new
rustlings v2
Diffstat (limited to 'src')
-rw-r--r--src/bin/generate_readme.rs49
-rw-r--r--src/main.rs96
-rw-r--r--src/run.rs55
-rw-r--r--src/util.rs5
-rw-r--r--src/verify.rs106
5 files changed, 262 insertions, 49 deletions
diff --git a/src/bin/generate_readme.rs b/src/bin/generate_readme.rs
deleted file mode 100644
index a502fea..0000000
--- a/src/bin/generate_readme.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-// This script reads README-template.md and generates the playground links
-// from the Rust source files in the various directories.
-
-// To add a new exercise, add it to the appropriate place in README-template.md
-// and then make sure to recompile this script (because the template gets
-// included at compile time and then run it to generate a new version of
-// README.md.
-
-extern crate handlebars;
-extern crate prlink;
-#[macro_use]
-extern crate serde_json;
-
-use handlebars::{Handlebars, Helper, RenderContext, RenderError};
-
-use std::fs::File;
-use std::io::prelude::*;
-use std::path::PathBuf;
-
-fn main() {
- let mut template_file = File::open("README-template.hbs").unwrap();
- let mut template = String::new();
- template_file.read_to_string(&mut template).unwrap();
-
- let autogenerated_notice = "This file was autogenerated by the script in src/bin/generate_readme.rs.
-Please edit either the script or the template in README-template.md in
-order to make changes here rather than committing the changes directly.";
-
- let mut generated_readme = File::create("README.md").unwrap();
-
- let mut hbs = Handlebars::new();
- hbs.register_helper("playground_link", Box::new(playground_link_helper));
-
- write!(
- generated_readme,
- "{}",
- hbs.render_template(
- &template,
- &json!({ "autogenerated_notice": autogenerated_notice }),
- ).unwrap()
- ).unwrap();
-}
-
-fn playground_link_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
- let filename = PathBuf::from(h.param(0).unwrap().value().as_str().unwrap());
- let link = prlink::linkify_file(&filename);
- rc.writer.write(link.into_bytes().as_ref())?;
- Ok(())
-}
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..8f9ccea
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,96 @@
+use crate::run::run;
+use crate::verify::verify;
+use clap::{crate_version, App, Arg, SubCommand};
+use notify::DebouncedEvent;
+use notify::{RecommendedWatcher, RecursiveMode, Watcher};
+use std::io::BufRead;
+use std::sync::mpsc::channel;
+use std::time::Duration;
+use syntect::easy::HighlightFile;
+use syntect::highlighting::{Style, ThemeSet};
+use syntect::parsing::SyntaxSet;
+use syntect::util::as_24_bit_terminal_escaped;
+
+mod run;
+mod util;
+mod verify;
+
+fn main() {
+ let matches = App::new("rustlings")
+ .version(crate_version!())
+ .author("Olivia Hugger, Carol Nichols")
+ .about("Rustlings is a collection of small exercises to get you used to writing and reading Rust code")
+ .subcommand(SubCommand::with_name("verify").alias("v").about("Verifies all exercises according to the recommended order"))
+ .subcommand(SubCommand::with_name("watch").alias("w").about("Reruns `verify` when files were edited"))
+ .subcommand(
+ SubCommand::with_name("run")
+ .alias("r")
+ .about("Runs/Tests a single exercise")
+ .arg(Arg::with_name("file").required(true).index(1))
+ .arg(Arg::with_name("test").short("t").long("test").help("Run the file as a test")),
+ )
+ .get_matches();
+
+ let ss = SyntaxSet::load_defaults_newlines();
+ let ts = ThemeSet::load_defaults();
+
+ if None == matches.subcommand_name() {
+ println!("");
+ println!(r#" welcome to... "#);
+ println!(r#" _ _ _ "#);
+ println!(r#" _ __ _ _ ___| |_| (_)_ __ __ _ ___ "#);
+ println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
+ println!(r#" | | | |_| \__ \ |_| | | | | | (_| \__ \ "#);
+ println!(r#" |_| \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
+ println!(r#" |___/ "#);
+ println!("");
+ }
+
+ if let Some(matches) = matches.subcommand_matches("run") {
+ run(matches.clone());
+ }
+
+ if let Some(_) = matches.subcommand_matches("verify") {
+ match verify() {
+ Ok(_) => {}
+ Err(_) => std::process::exit(1),
+ }
+ }
+
+ if let Some(_) = matches.subcommand_matches("watch") {
+ watch().unwrap();
+ }
+
+ if let None = matches.subcommand_name() {
+ let mut highlighter =
+ HighlightFile::new("default_out.md", &ss, &ts.themes["base16-eighties.dark"]).unwrap();
+ for maybe_line in highlighter.reader.lines() {
+ let line = maybe_line.unwrap();
+ let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
+ println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
+ }
+ }
+
+ println!("\x1b[0m");
+}
+
+fn watch() -> notify::Result<()> {
+ let (tx, rx) = channel();
+
+ let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
+ watcher.watch("./exercises", RecursiveMode::Recursive)?;
+
+ let _ignored = verify();
+
+ loop {
+ match rx.recv() {
+ Ok(event) => match event {
+ DebouncedEvent::Chmod(_) | DebouncedEvent::Write(_) => {
+ let _ignored = verify();
+ }
+ _ => {}
+ },
+ Err(e) => println!("watch error: {:?}", e),
+ }
+ }
+}
diff --git a/src/run.rs b/src/run.rs
new file mode 100644
index 0000000..809b79d
--- /dev/null
+++ b/src/run.rs
@@ -0,0 +1,55 @@
+use crate::util::clean;
+use crate::verify::test;
+use console::{style, Emoji};
+use indicatif::ProgressBar;
+use std::process::Command;
+
+pub fn run(matches: clap::ArgMatches) {
+ if let Some(filename) = matches.value_of("file") {
+ if matches.is_present("test") {
+ match test(filename) {
+ Ok(_) => (),
+ Err(_) => (),
+ }
+ std::process::exit(0);
+ }
+ let bar = ProgressBar::new_spinner();
+ bar.set_message(format!("Compiling {}...", filename).as_str());
+ bar.enable_steady_tick(100);
+ let compilecmd = Command::new("rustc")
+ .args(&[filename, "-o", "temp"])
+ .output()
+ .expect("fail");
+ bar.set_message(format!("Running {}...", filename).as_str());
+ if compilecmd.status.success() {
+ let runcmd = Command::new("./temp").output().expect("fail");
+ bar.finish_and_clear();
+
+ if runcmd.status.success() {
+ println!("{}", String::from_utf8_lossy(&runcmd.stdout));
+ let formatstr = format!("{} Successfully ran {}", Emoji("✅", "✓"), filename);
+ println!("{}", style(formatstr).green());
+ clean();
+ } else {
+ println!("{}", String::from_utf8_lossy(&runcmd.stdout));
+ println!("{}", String::from_utf8_lossy(&runcmd.stderr));
+
+ let formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), filename);
+ println!("{}", style(formatstr).red());
+ clean();
+ }
+ } else {
+ bar.finish_and_clear();
+ let formatstr = format!(
+ "{} Compilation of {} failed! Compiler error message:\n",
+ Emoji("⚠️ ", "!"),
+ filename
+ );
+ println!("{}", style(formatstr).red());
+ println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
+ clean();
+ }
+ } else {
+ panic!("Please supply a filename!");
+ }
+}
diff --git a/src/util.rs b/src/util.rs
new file mode 100644
index 0000000..37a2028
--- /dev/null
+++ b/src/util.rs
@@ -0,0 +1,5 @@
+use std::fs::remove_file;
+
+pub fn clean() {
+ let _ignored = remove_file("temp");
+}
diff --git a/src/verify.rs b/src/verify.rs
new file mode 100644
index 0000000..9aa3a4b
--- /dev/null
+++ b/src/verify.rs
@@ -0,0 +1,106 @@
+use crate::util::clean;
+use console::{style, Emoji};
+use indicatif::ProgressBar;
+use std::process::Command;
+
+pub fn verify() -> Result<(), ()> {
+ compile_only("exercises/variables/variables1.rs")?;
+ compile_only("exercises/variables/variables2.rs")?;
+ compile_only("exercises/variables/variables3.rs")?;
+ compile_only("exercises/variables/variables4.rs")?;
+ test("exercises/if/if1.rs")?;
+ compile_only("exercises/functions/functions1.rs")?;
+ compile_only("exercises/functions/functions2.rs")?;
+ compile_only("exercises/functions/functions3.rs")?;
+ compile_only("exercises/functions/functions4.rs")?;
+ compile_only("exercises/functions/functions5.rs")?;
+ compile_only("exercises/test1.rs")?;
+ compile_only("exercises/primitive_types/primitive_types1.rs")?;
+ compile_only("exercises/primitive_types/primitive_types2.rs")?;
+ compile_only("exercises/primitive_types/primitive_types3.rs")?;
+ compile_only("exercises/primitive_types/primitive_types4.rs")?;
+ compile_only("exercises/primitive_types/primitive_types5.rs")?;
+ compile_only("exercises/primitive_types/primitive_types6.rs")?;
+ test("exercises/tests/tests1.rs")?;
+ test("exercises/tests/tests2.rs")?;
+ test("exercises/tests/tests3.rs")?;
+ test("exercises/test2.rs")?;
+ compile_only("exercises/strings/strings1.rs")?;
+ compile_only("exercises/strings/strings2.rs")?;
+ compile_only("exercises/test3.rs")?;
+ compile_only("exercises/modules/modules1.rs")?;
+ compile_only("exercises/modules/modules2.rs")?;
+ compile_only("exercises/macros/macros1.rs")?;
+ compile_only("exercises/macros/macros2.rs")?;
+ compile_only("exercises/macros/macros3.rs")?;
+ compile_only("exercises/macros/macros4.rs")?;
+ compile_only("exercises/test4.rs")?;
+ compile_only("exercises/move_semantics/move_semantics1.rs")?;
+ compile_only("exercises/move_semantics/move_semantics2.rs")?;
+ compile_only("exercises/move_semantics/move_semantics3.rs")?;
+ compile_only("exercises/move_semantics/move_semantics4.rs")?;
+ test("exercises/error_handling/errors1.rs")?;
+ test("exercises/error_handling/errors2.rs")?;
+ test("exercises/error_handling/errors3.rs")?;
+ test("exercises/error_handling/errorsn.rs")?;
+ compile_only("exercises/error_handling/option1.rs")?;
+ test("exercises/error_handling/result1.rs")?;
+ Ok(())
+}
+
+fn compile_only(filename: &str) -> Result<(), ()> {
+ let bar = ProgressBar::new_spinner();
+ bar.set_message(format!("Compiling {}...", filename).as_str());
+ bar.enable_steady_tick(100);
+ let compilecmd = Command::new("rustc")
+ .args(&[filename, "-o", "temp", "--color", "always"])
+ .output()
+ .expect("fail");
+ bar.finish_and_clear();
+ if compilecmd.status.success() {
+ let formatstr = format!(
+ "{} Successfully compiled {}!",
+ Emoji("✅", "✓"),
+ filename
+ );
+ println!("{}", style(formatstr).green());
+ clean();
+ Ok(())
+ } else {
+ let formatstr = format!(
+ "{} Compilation of {} failed! Compiler error message:\n",
+ Emoji("⚠️ ", "!"),
+ filename
+ );
+ println!("{}", style(formatstr).red());
+ println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
+ clean();
+ Err(())
+ }
+}
+
+pub fn test(filename: &str) -> Result<(), ()> {
+ let bar = ProgressBar::new_spinner();
+ bar.set_message(format!("Testing {}...", filename).as_str());
+ bar.enable_steady_tick(100);
+ let testcmd = Command::new("rustc")
+ .args(&["--test", filename, "-o", "temp"])
+ .output()
+ .expect("fail");
+ bar.finish_and_clear();
+ if testcmd.status.success() {
+ let formatstr = format!("{} Successfully tested {}!", Emoji("✅", "✓"), filename);
+ println!("{}", style(formatstr).green());
+ clean();
+ Ok(())
+ } else {
+ let formatstr = format!(
+ "{} Testing of {} failed! Please try again.",
+ Emoji("⚠️ ", "!"),
+ filename
+ );
+ println!("{}", style(formatstr).red());
+ clean();
+ Err(())
+ }
+}