1
0
mirror of https://github.com/rust-lang/rustlings.git synced 2025-12-26 00:11:49 +02:00

Compare commits

...

7 Commits
1.0.0 ... 1.0.1

Author SHA1 Message Date
lyn
999601d828 1.0.1 2019-03-06 21:58:10 +01:00
lyn
10d4d61d19 rework contribution guide for the new toml file 2019-03-06 21:55:48 +01:00
lyn
70e59cca3c standardize exercise running via an external toml file 2019-03-06 21:47:33 +01:00
komaeda
7d6e2812fb Merge pull request #117 from shaunbennett/master
Watch for file creation events in watch mode
2019-03-06 20:28:29 +01:00
lyn
05e8f02d0a edit readme to use the install script 2019-03-06 20:25:27 +01:00
lyn
9a14d72f08 add a basic install script 2019-03-06 20:16:31 +01:00
Shaun Bennett
04d0f78a2c Fix file watching for vim swap files 2019-03-06 18:38:55 +00:00
7 changed files with 357 additions and 106 deletions

View File

@@ -1,6 +1,6 @@
[package]
name = "rustlings"
version = "1.0.0"
version = "1.0.1"
authors = ["Lynn <819880950@qq.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com"]
edition = "2018"
@@ -10,3 +10,4 @@ indicatif = "0.9.0"
console = "0.6.2"
syntect = "3.0.2"
notify = "4.0.0"
toml = "0.4.10"

View File

@@ -13,27 +13,36 @@ Alternatively, for a first-time Rust learner, there's several other resources:
## Getting Started
To use `rustlings` you need to have [Rust](https://www.rust-lang.org/) installed on your computer. To install Rust, go to [rustup.rs](https://rustup.rs/).
Once Rust is installed, clone the `rustlings` repository and enter the resulting directory:
```bash
git clone https://github.com/rust-lang/rustlings.git
cd rustlings
```
_Note: If you're on MacOS, make sure you've installed Xcode and its developer tools by typing `xcode-select --install`._
_Note: If you have Xcode 10+ installed, you also need to install the package file found at `/Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg`._
Once in the directory you can install `rustlings` on your machine and run the introduction:
You will need to have Rust installed. You can get it by visiting https://rustup.rs. This'll also install Cargo, Rust's package/project manager.
## MacOS/Linux
Just run:
```bash
cargo install --path .
rustlings
curl -L https://git.io/rustlings | bash
# Or if you want it to be installed to a different path:
curl -L https://git.io/rustlings | bash -s mypath/
```
If you choose to not install the `rustlings` command, just replace `rustlings` with `cargo run` in the rest of this text.
This will install Rustlings and give you access to the `rustlings` command. Run it to get started!
## Windows/Manually
Basically: Clone the repository, checkout to the latest tag, run `cargo install`.
```bash
git clone https://github.com/rust-lang/rustlings
cd rustlings
git checkout tags/1.0.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
cargo install --force --path .
```
Same as above, run `rustlings` to get started.
## Doing exercises
@@ -96,18 +105,20 @@ If you are interested in improving or adding new ones, please feel free to contr
First step is to add the exercise! Call it `exercises/yourTopic/yourTopicN.rs`, make sure to
put in some helpful links, and link to sections of the book in `exercises/yourTopic/README.md`.
Then, you'll want to make sure it gets verified when you run `rustlings verify`. Open `src/verify.rs` and
put your exercise somewhere in there:
Next you want to make sure it runs when using `rustlings`. All exercises are stored in `info.toml`, under the `exercises` array. They're ordered by the order they're ran when using `rustlings verify`.
You want to make sure where in the file you add your exercise. If you're not sure, add it at the bottom and ask in your pull request. To add an exercise, edit the file like this:
```diff
...
compile_only("exercises/functions5.rs")?;
+ compile_only("exercises/yourTopic/yourTopicN.rs")?;
compile_only("exercises/test1.rs")?;
+ [[exercises]]
+ path = "exercises/yourTopic/yourTopicN.rs"
+ mode = "compile"
...
```
That's all!
The `mode` attribute decides whether Rustlings will only compile your exercise, or compile and test it. If you have tests to verify in your exercise, choose `test`, otherwise `compile`.
That's all! Feel free to put up a pull request.
### Working on the source code

199
info.toml Normal file
View File

@@ -0,0 +1,199 @@
# VARIABLES
[[exercises]]
path = "exercises/variables/variables1.rs"
mode = "compile"
[[exercises]]
path = "exercises/variables/variables2.rs"
mode = "compile"
[[exercises]]
path = "exercises/variables/variables3.rs"
mode = "compile"
[[exercises]]
path = "exercises/variables/variables4.rs"
mode = "compile"
# IF
[[exercises]]
path = "exercises/if/if1.rs"
mode = "test"
# FUNCTIONS
[[exercises]]
path = "exercises/functions/functions1.rs"
mode = "compile"
[[exercises]]
path = "exercises/functions/functions2.rs"
mode = "compile"
[[exercises]]
path = "exercises/functions/functions3.rs"
mode = "compile"
[[exercises]]
path = "exercises/functions/functions4.rs"
mode = "compile"
[[exercises]]
path = "exercises/functions/functions5.rs"
mode = "compile"
# TEST 1
[[exercises]]
path = "exercises/test1.rs"
mode = "test"
# PRIMITIVE TYPES
[[exercises]]
path = "exercises/primitive_types/primitive_types1.rs"
mode = "compile"
[[exercises]]
path = "exercises/primitive_types/primitive_types2.rs"
mode = "compile"
[[exercises]]
path = "exercises/primitive_types/primitive_types3.rs"
mode = "compile"
[[exercises]]
path = "exercises/primitive_types/primitive_types4.rs"
mode = "compile"
[[exercises]]
path = "exercises/primitive_types/primitive_types5.rs"
mode = "compile"
[[exercises]]
path = "exercises/primitive_types/primitive_types6.rs"
mode = "compile"
# TESTS
[[exercises]]
path = "exercises/tests/tests1.rs"
mode = "test"
[[exercises]]
path = "exercises/tests/tests2.rs"
mode = "test"
[[exercises]]
path = "exercises/tests/tests3.rs"
mode = "test"
# TEST 2
[[exercises]]
path = "exercises/test2.rs"
mode = "test"
# STRINGS
[[exercises]]
path = "exercises/strings/strings1.rs"
mode = "compile"
[[exercises]]
path = "exercises/strings/strings2.rs"
mode = "compile"
# TEST 3
[[exercises]]
path = "exercises/test3.rs"
mode = "compile"
# MODULES
[[exercises]]
path = "exercises/modules/modules1.rs"
mode = "compile"
[[exercises]]
path = "exercises/modules/modules2.rs"
mode = "compile"
# MACROS
[[exercises]]
path = "exercises/macros/macros1.rs"
mode = "compile"
[[exercises]]
path = "exercises/macros/macros2.rs"
mode = "compile"
[[exercises]]
path = "exercises/macros/macros3.rs"
mode = "compile"
[[exercises]]
path = "exercises/macros/macros4.rs"
mode = "compile"
# TEST 4
[[exercises]]
path = "exercises/test4.rs"
mode = "compile"
# MOVE SEMANTICS
[[exercises]]
path = "exercises/move_semantics/move_semantics1.rs"
mode = "compile"
[[exercises]]
path = "exercises/move_semantics/move_semantics2.rs"
mode = "compile"
[[exercises]]
path = "exercises/move_semantics/move_semantics3.rs"
mode = "compile"
[[exercises]]
path = "exercises/move_semantics/move_semantics4.rs"
mode = "compile"
# ERROR HANDLING
[[exercises]]
path = "exercises/error_handling/errors1.rs"
mode = "test"
[[exercises]]
path = "exercises/error_handling/errors2.rs"
mode = "test"
[[exercises]]
path = "exercises/error_handling/errors3.rs"
mode = "test"
[[exercises]]
path = "exercises/error_handling/errorsn.rs"
mode = "test"
# OPTIONS / RESULTS
[[exercises]]
path = "exercises/error_handling/option1.rs"
mode = "compile"
[[exercises]]
path = "exercises/error_handling/result1.rs"
mode = "test"
# THREADS
[[exercises]]
path = "exercises/threads/threads1.rs"
mode = "compile"

51
install.sh Executable file
View File

@@ -0,0 +1,51 @@
#!/usr/bin/env bash
echo "Let's get you set up with Rustlings!"
echo "Checking requirements..."
if [ -x "$(git)" ]
then
echo "WARNING: Git does not seem to be installed."
echo "Please download Git using your package manager or over https://git-scm.com/!"
exit 1
else
echo "SUCCESS: Git is installed"
fi
if [ -x "$(rustc)" ]
then
echo "WARNING: Rust does not seem to be installed."
echo "Please download Rust using https://rustup.rs!"
exit 1
else
echo "SUCCESS: Rust is installed"
fi
if [ -x "$(cargo)" ]
then
echo "WARNING: Cargo does not seem to be installed."
echo "Please download Rust and Cargo using https://rustup.rs!"
exit 1
else
echo "SUCCESS: Cargo is installed"
fi
Path=${1:-rustlings/}
echo "Cloning Rustlings at $Path..."
git clone -q https://github.com/rust-lang/rustlings $Path
Version=$(curl -s https://api.github.com/repos/rust-lang/rustlings/releases/latest | python -c "import json,sys;obj=json.load(sys.stdin);print(obj['tag_name']);")
echo "Checking out version $Version..."
cd $Path
git checkout -q tags/$Version
echo "Installing the 'rustlings' executable..."
cargo install --force --path .
if [ -x "$(rustlings)" ]
then
echo "WARNING: Please check that you have '~/.cargo/bin' in your PATH environment variable!"
fi
echo "All done! Run 'rustlings' to get started."

View File

@@ -3,6 +3,7 @@ use crate::verify::verify;
use clap::{crate_version, App, Arg, SubCommand};
use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::ffi::OsStr;
use std::io::BufRead;
use std::sync::mpsc::channel;
use std::time::Duration;
@@ -47,7 +48,7 @@ fn main() {
}
if let Some(matches) = matches.subcommand_matches("run") {
run(matches.clone());
run(matches.clone()).unwrap();
}
if let Some(_) = matches.subcommand_matches("verify") {
@@ -85,8 +86,10 @@ fn watch() -> notify::Result<()> {
loop {
match rx.recv() {
Ok(event) => match event {
DebouncedEvent::Chmod(_) | DebouncedEvent::Write(_) => {
let _ignored = verify();
DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
if b.extension() == Some(OsStr::new("rs")) {
let _ignored = verify();
}
}
_ => {}
},

View File

@@ -2,54 +2,71 @@ use crate::util::clean;
use crate::verify::test;
use console::{style, Emoji};
use indicatif::ProgressBar;
use std::fs;
use std::process::Command;
use toml::Value;
pub fn run(matches: clap::ArgMatches) {
pub fn run(matches: clap::ArgMatches) -> Result<(), ()> {
if let Some(filename) = matches.value_of("file") {
if matches.is_present("test") {
match test(filename) {
Ok(_) => (),
Err(_) => (),
}
std::process::exit(0);
let toml: Value = fs::read_to_string("info.toml").unwrap().parse().unwrap();
let tomlvec: &Vec<Value> = toml.get("exercises").unwrap().as_array().unwrap();
let mut exercises = tomlvec.clone();
exercises.retain(|i| i.get("path").unwrap().as_str().unwrap() == filename);
if exercises.is_empty() {
println!("No exercise found for your filename!");
std::process::exit(1);
}
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.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();
let exercise: &Value = &exercises[0];
match exercise.get("mode").unwrap().as_str().unwrap() {
"test" => test(exercise.get("path").unwrap().as_str().unwrap())?,
"compile" => compile_and_run(exercise.get("path").unwrap().as_str().unwrap())?,
_ => (),
}
Ok(())
} else {
panic!("Please supply a filename!");
}
}
pub fn compile_and_run(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.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();
Ok(())
} 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();
Err(())
}
} 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();
Err(())
}
}

View File

@@ -1,51 +1,20 @@
use crate::util::clean;
use console::{style, Emoji};
use indicatif::ProgressBar;
use std::fs;
use std::process::Command;
use toml::Value;
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")?;
test("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")?;
compile_only("exercises/threads/threads1.rs")?;
let toml: Value = fs::read_to_string("info.toml").unwrap().parse().unwrap();
let tomlvec: &Vec<Value> = toml.get("exercises").unwrap().as_array().unwrap();
for i in tomlvec {
match i.get("mode").unwrap().as_str().unwrap() {
"test" => test(i.get("path").unwrap().as_str().unwrap())?,
"compile" => compile_only(i.get("path").unwrap().as_str().unwrap())?,
_ => (),
}
}
Ok(())
}