mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-04-26 17:23:01 +02:00
Make exerciser an mdbook renderer.
This commit is contained in:
parent
b24b5b02f3
commit
edd9df042c
16
.github/workflows/build.yml
vendored
16
.github/workflows/build.yml
vendored
@ -86,22 +86,6 @@ jobs:
|
|||||||
working-directory: ${{ matrix.directory }}
|
working-directory: ${{ matrix.directory }}
|
||||||
run: cargo build
|
run: cargo build
|
||||||
|
|
||||||
exercises:
|
|
||||||
name: Build exercise templates
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: ./build-exercise-templates.sh
|
|
||||||
|
|
||||||
- name: Upload artifacts
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: exercise-templates
|
|
||||||
path: exercise-templates/
|
|
||||||
|
|
||||||
find-translations:
|
find-translations:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
|
3
.github/workflows/publish.yml
vendored
3
.github/workflows/publish.yml
vendored
@ -50,9 +50,6 @@ jobs:
|
|||||||
echo "::endgroup::"
|
echo "::endgroup::"
|
||||||
done
|
done
|
||||||
|
|
||||||
- name: Build exercise templates
|
|
||||||
run: ./build-exercise-templates.sh
|
|
||||||
|
|
||||||
- name: Setup Pages
|
- name: Setup Pages
|
||||||
uses: actions/configure-pages@v2
|
uses: actions/configure-pages@v2
|
||||||
|
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,5 @@
|
|||||||
# Build artifacts
|
# Build artifacts
|
||||||
/book/
|
/book/
|
||||||
/exercise-templates/
|
|
||||||
target/
|
target/
|
||||||
*.bin
|
*.bin
|
||||||
|
|
||||||
|
997
Cargo.lock
generated
997
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,12 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -euxo pipefail
|
|
||||||
|
|
||||||
rm -rf exercise-templates/ book/exercises.zip
|
|
||||||
|
|
||||||
mkdir exercise-templates
|
|
||||||
cargo run --bin exerciser src/exercises/bare-metal/compass.md exercise-templates/compass
|
|
||||||
cargo run --bin exerciser src/exercises/bare-metal/rtc.md exercise-templates/rtc
|
|
||||||
|
|
||||||
mkdir -p book
|
|
||||||
zip --recurse-paths book/exercises.zip exercise-templates/
|
|
@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "exerciser"
|
name = "mdbook-exerciser"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
@ -10,5 +10,6 @@ repository = "https://github.com/google/comprehensive-rust"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.68"
|
anyhow = "1.0.68"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
|
mdbook = "0.4.25"
|
||||||
pretty_env_logger = "0.4.0"
|
pretty_env_logger = "0.4.0"
|
||||||
pulldown-cmark = { version = "0.9.2", default-features = false }
|
pulldown-cmark = { version = "0.9.2", default-features = false }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# exerciser
|
# exerciser
|
||||||
|
|
||||||
This is a tool to generate templates for exercises from the Markdown source. Given a Markdown file
|
This is an mdBook renderer to generate templates for exercises from the Markdown source. Given a
|
||||||
with one or more sections like:
|
Markdown file `example.md` with one or more sections like:
|
||||||
|
|
||||||
````markdown
|
````markdown
|
||||||
<!-- File src/main.rs -->
|
<!-- File src/main.rs -->
|
||||||
@ -15,5 +15,5 @@ fn some_more_code() {
|
|||||||
```
|
```
|
||||||
````
|
````
|
||||||
|
|
||||||
You can run it like `cargo run my/markdown/file.md exercise-templates/example`, and it will create a
|
It will create a file `book/exerciser/exercise-templates/example/src/main.rs` with the appropriate
|
||||||
file `exercise-templates/example/src/main.rs` with the appropriate contents.
|
contents.
|
||||||
|
@ -13,42 +13,66 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use exerciser::process;
|
use log::trace;
|
||||||
|
use mdbook::{book::Book, renderer::RenderContext, BookItem};
|
||||||
|
use mdbook_exerciser::process;
|
||||||
use std::{
|
use std::{
|
||||||
env::args,
|
fs::{create_dir, remove_dir_all},
|
||||||
fs::{create_dir, read_to_string},
|
io::stdin,
|
||||||
path::Path,
|
path::Path,
|
||||||
process::exit,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
|
|
||||||
let args = args().collect::<Vec<_>>();
|
let context = RenderContext::from_json(&mut stdin()).context("Parsing stdin")?;
|
||||||
|
|
||||||
if args.len() != 3 {
|
let config = context
|
||||||
eprintln!("Usage:");
|
.config
|
||||||
eprintln!(
|
.get_renderer("exerciser")
|
||||||
" {} <src/exercises/exercise.md> <output directory>",
|
.context("Missing output.exerciser configuration")?;
|
||||||
args[0]
|
|
||||||
);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
let input_filename = Path::new(&args[1]);
|
let output_directory = Path::new(
|
||||||
let output_directory = Path::new(&args[2]);
|
config
|
||||||
|
.get("output-directory")
|
||||||
|
.context("Missing output.exerciser.output-directory configuration value")?
|
||||||
|
.as_str()
|
||||||
|
.context("Expected a string for output.exerciser.output-directory")?,
|
||||||
|
);
|
||||||
|
|
||||||
|
let _ = remove_dir_all(output_directory);
|
||||||
create_dir(output_directory).with_context(|| {
|
create_dir(output_directory).with_context(|| {
|
||||||
format!("Failed to create output directory {:?}", output_directory)
|
format!("Failed to create output directory {:?}", output_directory)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let input_directory = input_filename.parent().with_context(|| {
|
process_all(&context.book, output_directory)?;
|
||||||
format!("Input file {:?} has no parent directory.", input_filename)
|
|
||||||
})?;
|
Ok(())
|
||||||
let input_contents = read_to_string(input_filename)
|
}
|
||||||
.with_context(|| format!("Failed to open {:?}", input_filename))?;
|
|
||||||
|
fn process_all(book: &Book, output_directory: &Path) -> anyhow::Result<()> {
|
||||||
process(input_directory, output_directory, &input_contents)?;
|
for item in book.iter() {
|
||||||
|
if let BookItem::Chapter(chapter) = item {
|
||||||
|
trace!("Chapter {:?} / {:?}", chapter.path, chapter.source_path);
|
||||||
|
if let Some(chapter_path) = &chapter.path {
|
||||||
|
let chapter_parent_directory =
|
||||||
|
chapter_path.parent().with_context(|| {
|
||||||
|
format!("Chapter file {:?} has no parent directory", chapter_path)
|
||||||
|
})?;
|
||||||
|
// Put the exercises in a subdirectory named after the chapter file, without its
|
||||||
|
// parent directories.
|
||||||
|
let chapter_output_directory =
|
||||||
|
output_directory.join(chapter_path.file_stem().with_context(
|
||||||
|
|| format!("Chapter {:?} has no file stem", chapter_path),
|
||||||
|
)?);
|
||||||
|
process(
|
||||||
|
&chapter_parent_directory,
|
||||||
|
&chapter_output_directory,
|
||||||
|
&chapter.content,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user