mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-05-30 14:17:35 +02:00
Personally, I don’t always agree with Clippy, but it a very widely recommended tool for writing idiomatic Rust. So on balance, I think it’s overall a good idea to enable it for both our exercises and our tooling.
94 lines
3.0 KiB
Rust
94 lines
3.0 KiB
Rust
// Copyright 2023 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
use clap::Command;
|
|
use mdbook::MDBook;
|
|
use mdbook_course::course::Courses;
|
|
use mdbook_course::markdown::duration;
|
|
|
|
fn main() {
|
|
pretty_env_logger::init();
|
|
let app = Command::new("mdbook-course")
|
|
.about("mdbook preprocessor for Comprehensive Rust")
|
|
.subcommand(Command::new("sessions").about("Show session summary (default)"))
|
|
.subcommand(Command::new("segments").about("Show segment summary"))
|
|
.subcommand(Command::new("pr").about("Show summary for a PR"));
|
|
let matches = app.get_matches();
|
|
|
|
let root_dir = ".";
|
|
let mdbook = MDBook::load(root_dir).expect("Unable to load the book");
|
|
let (courses, _) = Courses::extract_structure(mdbook.book)
|
|
.expect("Unable to extract course structure");
|
|
|
|
match matches.subcommand() {
|
|
Some(("session", _)) | None => session_summary(&courses),
|
|
Some(("pr", _)) => pr_summary(&courses),
|
|
_ => unreachable!(),
|
|
}
|
|
}
|
|
|
|
fn timediff(actual: u64, target: u64, slop: u64) -> String {
|
|
if actual > target + slop {
|
|
format!(
|
|
"{} (\u{23f0} *{} too long*)",
|
|
duration(actual),
|
|
duration(actual - target),
|
|
)
|
|
} else if actual + slop < target {
|
|
format!("{}: ({} short)", duration(actual), duration(target - actual),)
|
|
} else {
|
|
duration(actual).to_string()
|
|
}
|
|
}
|
|
|
|
fn session_summary(courses: &Courses) {
|
|
for course in courses {
|
|
if course.target_minutes() == 0 {
|
|
return;
|
|
}
|
|
for session in course {
|
|
println!("### {} // {}", course.name, session.name);
|
|
println!(
|
|
"_{}_",
|
|
timediff(session.minutes(), session.target_minutes(), 15)
|
|
);
|
|
println!();
|
|
for segment in session {
|
|
println!("* {} - _{}_", segment.name, duration(segment.minutes()));
|
|
}
|
|
println!();
|
|
}
|
|
}
|
|
}
|
|
|
|
fn pr_summary(courses: &Courses) {
|
|
println!("## Course Schedule");
|
|
println!("With this pull request applied, the course schedule is as follows:");
|
|
for course in courses {
|
|
if course.target_minutes() == 0 {
|
|
return;
|
|
}
|
|
println!("### {}", course.name);
|
|
println!("_{}_", timediff(course.minutes(), course.target_minutes(), 15));
|
|
|
|
for session in course {
|
|
println!(
|
|
"* {} - _{}_",
|
|
session.name,
|
|
timediff(session.minutes(), session.target_minutes(), 5)
|
|
);
|
|
}
|
|
}
|
|
}
|