mirror of
https://github.com/notohh/rustlings.git
synced 2024-11-21 21:42:23 -05:00
Add "dev update"
This commit is contained in:
parent
30636e7cf3
commit
501b973c25
13 changed files with 181 additions and 205 deletions
9
Cargo.lock
generated
9
Cargo.lock
generated
|
@ -311,15 +311,6 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gen-dev-cargo-toml"
|
|
||||||
version = "0.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"serde",
|
|
||||||
"toml_edit",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.14.3"
|
version = "0.14.3"
|
||||||
|
|
14
Cargo.toml
14
Cargo.toml
|
@ -6,9 +6,6 @@ exclude = [
|
||||||
"tests/fixture/success",
|
"tests/fixture/success",
|
||||||
"dev",
|
"dev",
|
||||||
]
|
]
|
||||||
members = [
|
|
||||||
"gen-dev-cargo-toml",
|
|
||||||
]
|
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "6.0.0-alpha.0"
|
version = "6.0.0-alpha.0"
|
||||||
|
@ -20,11 +17,6 @@ authors = [
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[workspace.dependencies]
|
|
||||||
anyhow = "1.0.82"
|
|
||||||
serde = { version = "1.0.197", features = ["derive"] }
|
|
||||||
toml_edit = { version = "0.22.9", default-features = false, features = ["parse", "serde"] }
|
|
||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "rustlings"
|
name = "rustlings"
|
||||||
description = "Small exercises to get you used to reading and writing Rust code!"
|
description = "Small exercises to get you used to reading and writing Rust code!"
|
||||||
|
@ -42,15 +34,15 @@ include = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow.workspace = true
|
anyhow = "1.0.82"
|
||||||
clap = { version = "4.5.4", features = ["derive"] }
|
clap = { version = "4.5.4", features = ["derive"] }
|
||||||
crossterm = "0.27.0"
|
crossterm = "0.27.0"
|
||||||
hashbrown = "0.14.3"
|
hashbrown = "0.14.3"
|
||||||
notify-debouncer-mini = "0.4.1"
|
notify-debouncer-mini = "0.4.1"
|
||||||
ratatui = "0.26.2"
|
ratatui = "0.26.2"
|
||||||
rustlings-macros = { path = "rustlings-macros", version = "6.0.0-alpha.0" }
|
rustlings-macros = { path = "rustlings-macros", version = "6.0.0-alpha.0" }
|
||||||
serde.workspace = true
|
serde = { version = "1.0.197", features = ["derive"] }
|
||||||
toml_edit.workspace = true
|
toml_edit = { version = "0.22.9", default-features = false, features = ["parse", "serde"] }
|
||||||
which = "6.0.1"
|
which = "6.0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
# This file is a hack to allow using `cargo run` to test `rustlings` during development.
|
# Don't edit the `bin` list manually! It is updated by `cargo run -- dev update`
|
||||||
# You shouldn't edit it manually. It is created and updated by running `cargo run -p gen-dev-cargo-toml`.
|
|
||||||
|
|
||||||
bin = [
|
bin = [
|
||||||
{ name = "intro1", path = "../exercises/00_intro/intro1.rs" },
|
{ name = "intro1", path = "../exercises/00_intro/intro1.rs" },
|
||||||
{ name = "intro2", path = "../exercises/00_intro/intro2.rs" },
|
{ name = "intro2", path = "../exercises/00_intro/intro2.rs" },
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "gen-dev-cargo-toml"
|
|
||||||
publish = false
|
|
||||||
license.workspace = true
|
|
||||||
edition.workspace = true
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow.workspace = true
|
|
||||||
serde.workspace = true
|
|
||||||
toml_edit.workspace = true
|
|
|
@ -1,68 +0,0 @@
|
||||||
// Generates `dev/Cargo.toml` such that it is synced with `info.toml`.
|
|
||||||
// `dev/Cargo.toml` is a hack to allow using `cargo run` to test `rustlings`
|
|
||||||
// during development.
|
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
|
||||||
use serde::Deserialize;
|
|
||||||
use std::{
|
|
||||||
fs::{self, create_dir},
|
|
||||||
io::ErrorKind,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct ExerciseInfo {
|
|
||||||
name: String,
|
|
||||||
dir: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct InfoFile {
|
|
||||||
exercises: Vec<ExerciseInfo>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
|
||||||
let exercise_infos = toml_edit::de::from_str::<InfoFile>(
|
|
||||||
&fs::read_to_string("info.toml").context("Failed to read `info.toml`")?,
|
|
||||||
)
|
|
||||||
.context("Failed to deserialize `info.toml`")?
|
|
||||||
.exercises;
|
|
||||||
|
|
||||||
let mut buf = Vec::with_capacity(1 << 14);
|
|
||||||
|
|
||||||
buf.extend_from_slice(
|
|
||||||
b"# This file is a hack to allow using `cargo run` to test `rustlings` during development.
|
|
||||||
# You shouldn't edit it manually. It is created and updated by running `cargo run -p gen-dev-cargo-toml`.
|
|
||||||
|
|
||||||
bin = [\n",
|
|
||||||
);
|
|
||||||
|
|
||||||
for exercise_info in exercise_infos {
|
|
||||||
buf.extend_from_slice(b" { name = \"");
|
|
||||||
buf.extend_from_slice(exercise_info.name.as_bytes());
|
|
||||||
buf.extend_from_slice(b"\", path = \"../exercises/");
|
|
||||||
if let Some(dir) = &exercise_info.dir {
|
|
||||||
buf.extend_from_slice(dir.as_bytes());
|
|
||||||
buf.push(b'/');
|
|
||||||
}
|
|
||||||
buf.extend_from_slice(exercise_info.name.as_bytes());
|
|
||||||
buf.extend_from_slice(b".rs\" },\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.extend_from_slice(
|
|
||||||
br#"]
|
|
||||||
|
|
||||||
[package]
|
|
||||||
name = "rustlings-dev"
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
"#,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Err(e) = create_dir("dev") {
|
|
||||||
if e.kind() != ErrorKind::AlreadyExists {
|
|
||||||
bail!("Failed to create the `dev` directory: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::write("dev/Cargo.toml", buf).context("Failed to write `dev/Cargo.toml`")
|
|
||||||
}
|
|
|
@ -1,22 +1,23 @@
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use clap::Subcommand;
|
use clap::Subcommand;
|
||||||
|
|
||||||
use crate::info_file::InfoFile;
|
|
||||||
|
|
||||||
mod check;
|
mod check;
|
||||||
mod init;
|
mod init;
|
||||||
|
mod update;
|
||||||
|
|
||||||
#[derive(Subcommand)]
|
#[derive(Subcommand)]
|
||||||
pub enum DevCommands {
|
pub enum DevCommands {
|
||||||
Init,
|
Init,
|
||||||
Check,
|
Check,
|
||||||
|
Update,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DevCommands {
|
impl DevCommands {
|
||||||
pub fn run(self, info_file: InfoFile) -> Result<()> {
|
pub fn run(self) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
DevCommands::Init => init::init().context(INIT_ERR),
|
DevCommands::Init => init::init().context(INIT_ERR),
|
||||||
DevCommands::Check => check::check(info_file),
|
DevCommands::Check => check::check(),
|
||||||
|
DevCommands::Update => update::update(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,83 @@
|
||||||
|
use anyhow::{bail, Context, Result};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use crate::{
|
||||||
|
info_file::{ExerciseInfo, InfoFile},
|
||||||
|
DEVELOPING_OFFIFICAL_RUSTLINGS,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{info_file::InfoFile, init::cargo_toml};
|
pub fn bins_start_end_ind(cargo_toml: &str) -> Result<(usize, usize)> {
|
||||||
|
let start_ind = cargo_toml
|
||||||
|
.find("bin = [")
|
||||||
|
.context("Failed to find the start of the `bin` list (`bin = [`)")?
|
||||||
|
+ 7;
|
||||||
|
let end_ind = start_ind
|
||||||
|
+ cargo_toml
|
||||||
|
.get(start_ind..)
|
||||||
|
.and_then(|slice| slice.as_bytes().iter().position(|c| *c == b']'))
|
||||||
|
.context("Failed to find the end of the `bin` list (`]`)")?;
|
||||||
|
|
||||||
|
Ok((start_ind, end_ind))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append_bins(
|
||||||
|
buf: &mut Vec<u8>,
|
||||||
|
exercise_infos: &[ExerciseInfo],
|
||||||
|
exercise_path_prefix: &[u8],
|
||||||
|
) {
|
||||||
|
buf.push(b'\n');
|
||||||
|
for exercise_info in exercise_infos {
|
||||||
|
buf.extend_from_slice(b" { name = \"");
|
||||||
|
buf.extend_from_slice(exercise_info.name.as_bytes());
|
||||||
|
buf.extend_from_slice(b"\", path = \"");
|
||||||
|
buf.extend_from_slice(exercise_path_prefix);
|
||||||
|
buf.extend_from_slice(b"exercises/");
|
||||||
|
if let Some(dir) = &exercise_info.dir {
|
||||||
|
buf.extend_from_slice(dir.as_bytes());
|
||||||
|
buf.push(b'/');
|
||||||
|
}
|
||||||
|
buf.extend_from_slice(exercise_info.name.as_bytes());
|
||||||
|
buf.extend_from_slice(b".rs\" },\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_cargo_toml(
|
||||||
|
exercise_infos: &[ExerciseInfo],
|
||||||
|
current_cargo_toml: &str,
|
||||||
|
exercise_path_prefix: &[u8],
|
||||||
|
) -> Result<()> {
|
||||||
|
let (bins_start_ind, bins_end_ind) = bins_start_end_ind(current_cargo_toml)?;
|
||||||
|
|
||||||
|
let old_bins = ¤t_cargo_toml.as_bytes()[bins_start_ind..bins_end_ind];
|
||||||
|
let mut new_bins = Vec::with_capacity(1 << 13);
|
||||||
|
append_bins(&mut new_bins, exercise_infos, exercise_path_prefix);
|
||||||
|
|
||||||
|
if old_bins != new_bins {
|
||||||
|
bail!("`Cargo.toml` is outdated. Run `rustlings dev update` to update it");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check() -> Result<()> {
|
||||||
|
let info_file = InfoFile::parse()?;
|
||||||
|
|
||||||
pub fn check(info_file: InfoFile) -> Result<()> {
|
|
||||||
// TODO: Add checks
|
// TODO: Add checks
|
||||||
|
|
||||||
// TODO: Keep dependencies!
|
if DEVELOPING_OFFIFICAL_RUSTLINGS {
|
||||||
fs::write("Cargo.toml", cargo_toml(&info_file.exercises))
|
check_cargo_toml(
|
||||||
.context("Failed to update the file `Cargo.toml`")?;
|
&info_file.exercises,
|
||||||
println!("Updated `Cargo.toml`");
|
include_str!("../../dev/Cargo.toml"),
|
||||||
|
b"../",
|
||||||
|
)
|
||||||
|
.context("The file `dev/Cargo.toml` is outdated. Please run `cargo run -- dev update` to update it")?;
|
||||||
|
} else {
|
||||||
|
let current_cargo_toml =
|
||||||
|
fs::read_to_string("Cargo.toml").context("Failed to read the file `Cargo.toml`")?;
|
||||||
|
check_cargo_toml(&info_file.exercises, ¤t_cargo_toml, b"").context(
|
||||||
|
"The file `Cargo.toml` is outdated. Please run `rustlings dev update` to update it",
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
println!("\nEverything looks fine!");
|
println!("\nEverything looks fine!");
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use std::fs::{self, create_dir};
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
use std::fs::{self, create_dir};
|
||||||
|
|
||||||
use crate::CURRENT_FORMAT_VERSION;
|
use crate::CURRENT_FORMAT_VERSION;
|
||||||
|
|
||||||
|
@ -19,10 +18,7 @@ pub fn init() -> Result<()> {
|
||||||
)
|
)
|
||||||
.context("Failed to create the file `rustlings/info.toml`")?;
|
.context("Failed to create the file `rustlings/info.toml`")?;
|
||||||
|
|
||||||
fs::write(
|
fs::write("rustlings/Cargo.toml", CARGO_TOML)
|
||||||
"rustlings/Cargo.toml",
|
|
||||||
format!("{CARGO_TOML_COMMENT}{}", crate::init::CARGO_TOML_PACKAGE),
|
|
||||||
)
|
|
||||||
.context("Failed to create the file `rustlings/Cargo.toml`")?;
|
.context("Failed to create the file `rustlings/Cargo.toml`")?;
|
||||||
|
|
||||||
fs::write("rustlings/.gitignore", crate::init::GITIGNORE)
|
fs::write("rustlings/.gitignore", crate::init::GITIGNORE)
|
||||||
|
@ -80,10 +76,17 @@ mode = "test"
|
||||||
hint = """???"""
|
hint = """???"""
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
const CARGO_TOML_COMMENT: &str =
|
const CARGO_TOML: &[u8] =
|
||||||
"# You shouldn't edit this file manually! It is updated by `rustlings dev check`
|
br#"# Don't edit the `bin` list manually! It is updated by `rustlings dev update`
|
||||||
|
bin = []
|
||||||
|
|
||||||
";
|
[package]
|
||||||
|
name = "rustlings"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
"#;
|
||||||
|
|
||||||
const README: &str = "# Rustlings 🦀
|
const README: &str = "# Rustlings 🦀
|
||||||
|
|
||||||
|
|
53
src/dev/update.rs
Normal file
53
src/dev/update.rs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
info_file::{ExerciseInfo, InfoFile},
|
||||||
|
DEVELOPING_OFFIFICAL_RUSTLINGS,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::check::{append_bins, bins_start_end_ind};
|
||||||
|
|
||||||
|
fn update_cargo_toml(
|
||||||
|
exercise_infos: &[ExerciseInfo],
|
||||||
|
current_cargo_toml: &str,
|
||||||
|
cargo_toml_path: &str,
|
||||||
|
exercise_path_prefix: &[u8],
|
||||||
|
) -> Result<()> {
|
||||||
|
let (bins_start_ind, bins_end_ind) = bins_start_end_ind(current_cargo_toml)?;
|
||||||
|
|
||||||
|
let mut new_cargo_toml = Vec::with_capacity(1 << 13);
|
||||||
|
new_cargo_toml.extend_from_slice(current_cargo_toml[..bins_start_ind].as_bytes());
|
||||||
|
append_bins(&mut new_cargo_toml, exercise_infos, exercise_path_prefix);
|
||||||
|
new_cargo_toml.extend_from_slice(current_cargo_toml[bins_end_ind..].as_bytes());
|
||||||
|
|
||||||
|
fs::write(cargo_toml_path, new_cargo_toml).context("Failed to write the `Cargo.toml` file")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update() -> Result<()> {
|
||||||
|
let info_file = InfoFile::parse()?;
|
||||||
|
|
||||||
|
if DEVELOPING_OFFIFICAL_RUSTLINGS {
|
||||||
|
update_cargo_toml(
|
||||||
|
&info_file.exercises,
|
||||||
|
include_str!("../../dev/Cargo.toml"),
|
||||||
|
"dev/Cargo.toml",
|
||||||
|
b"../",
|
||||||
|
)
|
||||||
|
.context("Failed to update the file `dev/Cargo.toml`")?;
|
||||||
|
|
||||||
|
println!("Updated `dev/Cargo.toml`");
|
||||||
|
} else {
|
||||||
|
let current_cargo_toml =
|
||||||
|
fs::read_to_string("Cargo.toml").context("Failed to read the file `Cargo.toml`")?;
|
||||||
|
update_cargo_toml(&info_file.exercises, ¤t_cargo_toml, "Cargo.toml", b"")
|
||||||
|
.context("Failed to update the file `Cargo.toml`")?;
|
||||||
|
|
||||||
|
println!("Updated `Cargo.toml`");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ use std::{
|
||||||
use crate::{
|
use crate::{
|
||||||
embedded::{WriteStrategy, EMBEDDED_FILES},
|
embedded::{WriteStrategy, EMBEDDED_FILES},
|
||||||
info_file::Mode,
|
info_file::Mode,
|
||||||
|
DEVELOPING_OFFIFICAL_RUSTLINGS,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct TerminalFileLink<'a> {
|
pub struct TerminalFileLink<'a> {
|
||||||
|
@ -50,9 +51,7 @@ impl Exercise {
|
||||||
cmd.arg(command);
|
cmd.arg(command);
|
||||||
|
|
||||||
// A hack to make `cargo run` work when developing Rustlings.
|
// A hack to make `cargo run` work when developing Rustlings.
|
||||||
// Use `dev/Cargo.toml` when in the directory of the repository.
|
if DEVELOPING_OFFIFICAL_RUSTLINGS {
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
if std::path::Path::new("tests").exists() {
|
|
||||||
cmd.arg("--manifest-path").arg("dev/Cargo.toml");
|
cmd.arg("--manifest-path").arg("dev/Cargo.toml");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
39
src/init.rs
39
src/init.rs
|
@ -6,30 +6,19 @@ use std::{
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{embedded::EMBEDDED_FILES, info_file::ExerciseInfo};
|
use crate::embedded::EMBEDDED_FILES;
|
||||||
|
|
||||||
pub fn cargo_toml(exercise_infos: &[ExerciseInfo]) -> Vec<u8> {
|
const CARGO_TOML: &[u8] = {
|
||||||
let mut cargo_toml = Vec::with_capacity(1 << 13);
|
let cargo_toml = include_bytes!("../dev/Cargo.toml");
|
||||||
cargo_toml.extend_from_slice(b"bin = [\n");
|
// Skip the first line (comment).
|
||||||
for exercise_info in exercise_infos {
|
let mut start_ind = 0;
|
||||||
cargo_toml.extend_from_slice(b" { name = \"");
|
while cargo_toml[start_ind] != b'\n' {
|
||||||
cargo_toml.extend_from_slice(exercise_info.name.as_bytes());
|
start_ind += 1;
|
||||||
cargo_toml.extend_from_slice(b"\", path = \"exercises/");
|
|
||||||
if let Some(dir) = &exercise_info.dir {
|
|
||||||
cargo_toml.extend_from_slice(dir.as_bytes());
|
|
||||||
cargo_toml.push(b'/');
|
|
||||||
}
|
|
||||||
cargo_toml.extend_from_slice(exercise_info.name.as_bytes());
|
|
||||||
cargo_toml.extend_from_slice(b".rs\" },\n");
|
|
||||||
}
|
}
|
||||||
|
cargo_toml.split_at(start_ind + 1).1
|
||||||
|
};
|
||||||
|
|
||||||
cargo_toml.extend_from_slice(b"]\n\n");
|
pub fn init() -> Result<()> {
|
||||||
cargo_toml.extend_from_slice(CARGO_TOML_PACKAGE.as_bytes());
|
|
||||||
|
|
||||||
cargo_toml
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(exercise_infos: &[ExerciseInfo]) -> Result<()> {
|
|
||||||
if Path::new("exercises").is_dir() && Path::new("Cargo.toml").is_file() {
|
if Path::new("exercises").is_dir() && Path::new("Cargo.toml").is_file() {
|
||||||
bail!(PROBABLY_IN_RUSTLINGS_DIR_ERR);
|
bail!(PROBABLY_IN_RUSTLINGS_DIR_ERR);
|
||||||
}
|
}
|
||||||
|
@ -49,7 +38,7 @@ pub fn init(exercise_infos: &[ExerciseInfo]) -> Result<()> {
|
||||||
.init_exercises_dir()
|
.init_exercises_dir()
|
||||||
.context("Failed to initialize the `rustlings/exercises` directory")?;
|
.context("Failed to initialize the `rustlings/exercises` directory")?;
|
||||||
|
|
||||||
fs::write("Cargo.toml", cargo_toml(exercise_infos))
|
fs::write("Cargo.toml", CARGO_TOML)
|
||||||
.context("Failed to create the file `rustlings/Cargo.toml`")?;
|
.context("Failed to create the file `rustlings/Cargo.toml`")?;
|
||||||
|
|
||||||
fs::write(".gitignore", GITIGNORE)
|
fs::write(".gitignore", GITIGNORE)
|
||||||
|
@ -64,12 +53,6 @@ pub fn init(exercise_infos: &[ExerciseInfo]) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const CARGO_TOML_PACKAGE: &str = r#"[package]
|
|
||||||
name = "rustlings"
|
|
||||||
edition = "2021"
|
|
||||||
publish = false
|
|
||||||
"#;
|
|
||||||
|
|
||||||
pub const GITIGNORE: &[u8] = b"Cargo.lock
|
pub const GITIGNORE: &[u8] = b"Cargo.lock
|
||||||
.rustlings-state.txt
|
.rustlings-state.txt
|
||||||
target
|
target
|
||||||
|
|
27
src/main.rs
27
src/main.rs
|
@ -25,6 +25,17 @@ mod watch;
|
||||||
use self::{app_state::AppState, dev::DevCommands, info_file::InfoFile, watch::WatchExit};
|
use self::{app_state::AppState, dev::DevCommands, info_file::InfoFile, watch::WatchExit};
|
||||||
|
|
||||||
const CURRENT_FORMAT_VERSION: u8 = 1;
|
const CURRENT_FORMAT_VERSION: u8 = 1;
|
||||||
|
const DEVELOPING_OFFIFICAL_RUSTLINGS: bool = {
|
||||||
|
#[allow(unused_assignments, unused_mut)]
|
||||||
|
let mut debug_profile = false;
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
debug_profile = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_profile
|
||||||
|
};
|
||||||
|
|
||||||
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
|
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
|
@ -66,17 +77,11 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
which::which("cargo").context(CARGO_NOT_FOUND_ERR)?;
|
which::which("cargo").context(CARGO_NOT_FOUND_ERR)?;
|
||||||
|
|
||||||
let info_file = InfoFile::parse()?;
|
|
||||||
|
|
||||||
if info_file.format_version > CURRENT_FORMAT_VERSION {
|
|
||||||
bail!(FORMAT_VERSION_HIGHER_ERR);
|
|
||||||
}
|
|
||||||
|
|
||||||
match args.command {
|
match args.command {
|
||||||
Some(Subcommands::Init) => {
|
Some(Subcommands::Init) => {
|
||||||
return init::init(&info_file.exercises).context("Initialization failed");
|
return init::init().context("Initialization failed");
|
||||||
}
|
}
|
||||||
Some(Subcommands::Dev(dev_command)) => return dev_command.run(info_file),
|
Some(Subcommands::Dev(dev_command)) => return dev_command.run(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +90,12 @@ fn main() -> Result<()> {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let info_file = InfoFile::parse()?;
|
||||||
|
|
||||||
|
if info_file.format_version > CURRENT_FORMAT_VERSION {
|
||||||
|
bail!(FORMAT_VERSION_HIGHER_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
let (mut app_state, state_file_status) = AppState::new(
|
let (mut app_state, state_file_status) = AppState::new(
|
||||||
info_file.exercises,
|
info_file.exercises,
|
||||||
info_file.final_message.unwrap_or_default(),
|
info_file.final_message.unwrap_or_default(),
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
// Makes sure that `dev/Cargo.toml` is synced with `info.toml`.
|
|
||||||
// When this test fails, you just need to run `cargo run -p gen-dev-cargo-toml`.
|
|
||||||
|
|
||||||
use serde::Deserialize;
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct ExerciseInfo {
|
|
||||||
name: String,
|
|
||||||
dir: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct InfoFile {
|
|
||||||
exercises: Vec<ExerciseInfo>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn dev_cargo_bins() {
|
|
||||||
let cargo_toml = fs::read_to_string("dev/Cargo.toml").unwrap();
|
|
||||||
|
|
||||||
let exercise_infos =
|
|
||||||
toml_edit::de::from_str::<InfoFile>(&fs::read_to_string("info.toml").unwrap())
|
|
||||||
.unwrap()
|
|
||||||
.exercises;
|
|
||||||
|
|
||||||
let mut start_ind = 0;
|
|
||||||
for exercise_info in exercise_infos {
|
|
||||||
let name_start = start_ind + cargo_toml[start_ind..].find('"').unwrap() + 1;
|
|
||||||
let name_end = name_start + cargo_toml[name_start..].find('"').unwrap();
|
|
||||||
assert_eq!(exercise_info.name, &cargo_toml[name_start..name_end]);
|
|
||||||
|
|
||||||
let path_start = name_end + cargo_toml[name_end + 1..].find('"').unwrap() + 2;
|
|
||||||
let path_end = path_start + cargo_toml[path_start..].find('"').unwrap();
|
|
||||||
let expected_path = if let Some(dir) = exercise_info.dir {
|
|
||||||
format!("../exercises/{dir}/{}.rs", exercise_info.name)
|
|
||||||
} else {
|
|
||||||
format!("../exercises/{}.rs", exercise_info.name)
|
|
||||||
};
|
|
||||||
assert_eq!(expected_path, &cargo_toml[path_start..path_end]);
|
|
||||||
|
|
||||||
start_ind = path_end + 1;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue