1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
use anyhow::{Context, Result, bail};
use std::{
env::set_current_dir,
fs::{self, create_dir},
path::Path,
process::Command,
};
use crate::{CURRENT_FORMAT_VERSION, init::RUST_ANALYZER_TOML};
// Create a directory relative to the current directory and print its path.
fn create_rel_dir(dir_name: &str, current_dir: &str) -> Result<()> {
create_dir(dir_name)
.with_context(|| format!("Failed to create the directory {current_dir}/{dir_name}"))?;
println!("Created the directory {current_dir}/{dir_name}");
Ok(())
}
// Write a file relative to the current directory and print its path.
fn write_rel_file<C>(file_name: &str, current_dir: &str, content: C) -> Result<()>
where
C: AsRef<[u8]>,
{
fs::write(file_name, content)
.with_context(|| format!("Failed to create the file {current_dir}/{file_name}"))?;
// Space to align with `create_rel_dir`.
println!("Created the file {current_dir}/{file_name}");
Ok(())
}
pub fn new(path: &Path, no_git: bool) -> Result<()> {
let dir_path_str = path.to_string_lossy();
create_dir(path).with_context(|| format!("Failed to create the directory {dir_path_str}"))?;
println!("Created the directory {dir_path_str}");
set_current_dir(path)
.with_context(|| format!("Failed to set {dir_path_str} as the current directory"))?;
if !no_git
&& !Command::new("git")
.arg("init")
.status()
.context("Failed to run `git init`")?
.success()
{
bail!("`git init` didn't run successfully. See the possible error message above");
}
write_rel_file(".gitignore", &dir_path_str, GITIGNORE)?;
create_rel_dir("exercises", &dir_path_str)?;
create_rel_dir("solutions", &dir_path_str)?;
write_rel_file(
"info.toml",
&dir_path_str,
format!(
"{INFO_FILE_BEFORE_FORMAT_VERSION}{CURRENT_FORMAT_VERSION}{INFO_FILE_AFTER_FORMAT_VERSION}"
),
)?;
write_rel_file("Cargo.toml", &dir_path_str, CARGO_TOML)?;
write_rel_file("README.md", &dir_path_str, README)?;
write_rel_file("rust-analyzer.toml", &dir_path_str, RUST_ANALYZER_TOML)?;
create_rel_dir(".vscode", &dir_path_str)?;
write_rel_file(
".vscode/extensions.json",
&dir_path_str,
crate::init::VS_CODE_EXTENSIONS_JSON,
)?;
println!("\nInitialization done ✓");
Ok(())
}
pub const GITIGNORE: &[u8] = b"Cargo.lock
target/
.vscode/
!.vscode/extensions.json
";
const INFO_FILE_BEFORE_FORMAT_VERSION: &str =
"# The format version is an indicator of the compatibility of community exercises with the
# Rustlings program.
# The format version is not the same as the version of the Rustlings program.
# In case Rustlings makes an unavoidable breaking change to the expected format of community
# exercises, you would need to raise this version and adapt to the new format.
# Otherwise, the newest version of the Rustlings program won't be able to run these exercises.
format_version = ";
const INFO_FILE_AFTER_FORMAT_VERSION: &str = r#"
# Optional multi-line message to be shown to users when just starting with the exercises.
welcome_message = """Welcome to these community Rustlings exercises."""
# Optional multi-line message to be shown to users after finishing all exercises.
final_message = """We hope that you found the exercises helpful :D"""
# Repeat this section for every exercise.
[[exercises]]
# Exercise name which is the exercise file name without the `.rs` extension.
name = "???"
# Optional directory name to be provided if you want to organize exercises in directories.
# If `dir` is specified, the exercise path is `exercises/DIR/NAME.rs`
# Otherwise, the path is `exercises/NAME.rs`
# dir = "???"
# Rustlings expects the exercise to contain tests and run them.
# You can optionally disable testing by setting `test` to `false` (the default is `true`).
# In that case, the exercise will be considered done when it just successfully compiles.
# test = true
# Rustlings will always run Clippy on exercises.
# You can optionally set `strict_clippy` to `true` (the default is `false`) to only consider
# the exercise as done when there are no warnings left.
# strict_clippy = false
# A multi-line hint to be shown to users on request.
hint = """???"""
"#;
const CARGO_TOML: &[u8] =
br#"# Don't edit the `bin` list manually! It is updated by `rustlings dev update`
bin = []
[package]
name = "exercises"
edition = "2024"
# Don't publish the exercises on crates.io!
publish = false
[dependencies]
"#;
const README: &str = "# Rustlings 🦀
Welcome to these community Rustlings exercises 😃
First, [install Rustlings using the official instructions](https://github.com/rust-lang/rustlings) ✅
Then, clone this repository, open a terminal in this directory and run `rustlings` to get started with the exercises 🚀
";
|