Add 'shelf' command
Initial processing of the shelf.toml file. Build the books in the current_dir.
This commit is contained in:
parent
bd323fb930
commit
2903f0711f
|
@ -221,6 +221,7 @@ version = "1.0.83"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
]
|
||||
|
||||
|
@ -372,6 +373,26 @@ dependencies = [
|
|||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "doc-comment"
|
||||
version = "0.3.3"
|
||||
|
@ -571,6 +592,21 @@ version = "0.28.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.18.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "232e6a7bfe35766bf715e55a88b39a700596c0ccfd88cd3680b4cdb40d66ef70"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"libc",
|
||||
"libgit2-sys",
|
||||
"log",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.14"
|
||||
|
@ -816,6 +852,15 @@ version = "1.0.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.67"
|
||||
|
@ -851,6 +896,57 @@ version = "0.2.153"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.16.2+1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"libssh2-sys",
|
||||
"libz-sys",
|
||||
"openssl-sys",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
|
||||
dependencies = [
|
||||
"bitflags 2.4.2",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libssh2-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"libz-sys",
|
||||
"openssl-sys",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.13"
|
||||
|
@ -924,6 +1020,7 @@ dependencies = [
|
|||
"elasticlunr-rs",
|
||||
"env_logger",
|
||||
"futures-util",
|
||||
"git2",
|
||||
"handlebars",
|
||||
"ignore",
|
||||
"log",
|
||||
|
@ -937,6 +1034,7 @@ dependencies = [
|
|||
"pretty_assertions",
|
||||
"pulldown-cmark",
|
||||
"regex",
|
||||
"resolve-path",
|
||||
"select",
|
||||
"semver",
|
||||
"serde",
|
||||
|
@ -1089,6 +1187,24 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
|
@ -1239,6 +1355,12 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
|
@ -1366,6 +1488,17 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.3"
|
||||
|
@ -1395,6 +1528,15 @@ version = "0.8.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "resolve-path"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "321e5e41b3b192dab6f1e75b9deacb6688b4b8c5e68906a78e8f43e7c2887bb5"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
|
@ -1893,6 +2035,12 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
|
|
@ -35,6 +35,8 @@ shlex = "1.3.0"
|
|||
tempfile = "3.4.0"
|
||||
toml = "0.5.11" # Do not update, see https://github.com/rust-lang/mdBook/issues/2037
|
||||
topological-sort = "0.2.2"
|
||||
resolve-path = "0.1.0"
|
||||
git2 = "0.18.3"
|
||||
|
||||
# Watch feature
|
||||
notify = { version = "6.1.1", optional = true }
|
||||
|
|
|
@ -6,6 +6,7 @@ pub mod command_prelude;
|
|||
pub mod init;
|
||||
#[cfg(feature = "serve")]
|
||||
pub mod serve;
|
||||
pub mod shelf;
|
||||
pub mod test;
|
||||
#[cfg(feature = "watch")]
|
||||
pub mod watch;
|
||||
|
|
|
@ -0,0 +1,281 @@
|
|||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use resolve_path::PathResolveExt;
|
||||
|
||||
use super::command_prelude::*;
|
||||
use mdbook::config::ShelfConfig;
|
||||
use mdbook::errors::Result;
|
||||
use mdbook::MDBook;
|
||||
|
||||
const SHELF_DIR: &str = "shelf";
|
||||
const REPOS_DIR: &str = "repositories";
|
||||
const INDEX_MD_FILE: &str = "index.md";
|
||||
const INDEX_HTML_FILE: &str = "index.html";
|
||||
const BOOKS_DIR: &str = "books";
|
||||
const BOOKSHELF_DIR: &str = "bookshelf";
|
||||
const SUMMARY_MD_FILE: &str = "SUMMARY.md";
|
||||
|
||||
pub fn make_subcommand() -> Command {
|
||||
Command::new("shelf").about("Build a bookshelf from shelf.toml file")
|
||||
}
|
||||
|
||||
struct BookContext {
|
||||
title: String,
|
||||
desc: String,
|
||||
authors: String,
|
||||
}
|
||||
|
||||
struct ShelfContext {
|
||||
book_dir: PathBuf,
|
||||
source_dir: PathBuf,
|
||||
url_prefix: String,
|
||||
url: String,
|
||||
index_file_name: PathBuf,
|
||||
summary_file_name: PathBuf,
|
||||
}
|
||||
|
||||
fn update_index(
|
||||
index_file: &mut File,
|
||||
summary_file: &mut File,
|
||||
shelf_source: &PathBuf,
|
||||
root_prefix: &str,
|
||||
context: BookContext,
|
||||
) -> Result<()> {
|
||||
// Create post in index file
|
||||
let book_link = format!(
|
||||
"## [{title}](<{prefix}/{BOOKSHELF_DIR}/{BOOKS_DIR}/{title}/{INDEX_HTML_FILE}>)",
|
||||
title = context.title,
|
||||
prefix = root_prefix
|
||||
);
|
||||
writeln!(index_file, "{book_link}")?;
|
||||
writeln!(index_file)?;
|
||||
writeln!(index_file, "{desc}", desc = context.desc)?;
|
||||
|
||||
// Create a separate chapter file for the book
|
||||
let fixed_title = context.title.replace(' ', "_");
|
||||
let file_name = format!("{fixed_title}.md");
|
||||
let mut file_path = shelf_source.clone();
|
||||
file_path.push(&file_name);
|
||||
let mut bf = File::create(file_path)?;
|
||||
writeln!(bf, "{book_link}")?;
|
||||
writeln!(bf)?;
|
||||
writeln!(bf, "{desc}", desc = context.desc)?;
|
||||
writeln!(bf)?;
|
||||
writeln!(bf)?;
|
||||
writeln!(bf, "*{authors}*", authors = context.authors)?;
|
||||
|
||||
// Add the chapter to the summary
|
||||
writeln!(
|
||||
summary_file,
|
||||
"- [{title}](./{file_name})",
|
||||
title = context.title
|
||||
)?;
|
||||
writeln!(summary_file)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_book(path: &str, books_dir: &PathBuf, shelf_url: &str) -> Result<BookContext> {
|
||||
let book_dir = path.try_resolve()?;
|
||||
let book_dir = std::fs::canonicalize(book_dir)?;
|
||||
let mut book = MDBook::load(book_dir)?;
|
||||
|
||||
// Build book
|
||||
let title = book.config.book.title.clone().unwrap();
|
||||
let mut build_path = books_dir.to_owned();
|
||||
build_path.push(title);
|
||||
book.config.build.build_dir = build_path;
|
||||
// Create back reference to bookshelf
|
||||
book.config.book.shelf_url = Some(shelf_url.to_owned());
|
||||
book.build()?;
|
||||
|
||||
let book_context = BookContext {
|
||||
title: book.config.book.title.unwrap_or_default(),
|
||||
desc: book.config.book.description.unwrap_or_default(),
|
||||
authors: book.config.book.authors.join(", "),
|
||||
};
|
||||
|
||||
Ok(book_context)
|
||||
}
|
||||
|
||||
fn setup_shelf_book(config: &ShelfConfig) -> Result<ShelfContext> {
|
||||
let book_dir = format!("{BOOKSHELF_DIR}/{SHELF_DIR}");
|
||||
let book = MDBook::init(&book_dir).build()?;
|
||||
let build_dir = book.config.build.build_dir.to_str().unwrap_or_default();
|
||||
let url_prefix = if !config.root_url_prefix.is_empty() {
|
||||
let mut full_prefix = "/".to_owned();
|
||||
full_prefix.push_str(&config.root_url_prefix);
|
||||
full_prefix
|
||||
} else {
|
||||
config.root_url_prefix.to_owned()
|
||||
};
|
||||
let url = format!("{url_prefix}/{book_dir}/{build_dir}/{INDEX_HTML_FILE}");
|
||||
|
||||
let mut index_file_name = book.source_dir();
|
||||
index_file_name.push(INDEX_MD_FILE);
|
||||
|
||||
let mut summary_file_name = book.source_dir();
|
||||
summary_file_name.push(SUMMARY_MD_FILE);
|
||||
|
||||
Ok(ShelfContext {
|
||||
book_dir: book_dir.into(),
|
||||
source_dir: book.source_dir(),
|
||||
url_prefix,
|
||||
url,
|
||||
index_file_name,
|
||||
summary_file_name,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn execute(_args: &ArgMatches) -> Result<()> {
|
||||
let mut file = File::open("shelf.toml")?;
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)?;
|
||||
let shelf_config: ShelfConfig = toml::from_str(&contents)?;
|
||||
|
||||
let _ = std::fs::remove_dir_all(BOOKSHELF_DIR);
|
||||
let _ = std::fs::remove_dir_all(REPOS_DIR);
|
||||
|
||||
let shelf_context = setup_shelf_book(&shelf_config)?;
|
||||
|
||||
let mut index_file = File::create(shelf_context.index_file_name).unwrap();
|
||||
writeln!(index_file, "# {title}", title = shelf_config.title)?;
|
||||
writeln!(index_file)?;
|
||||
|
||||
let mut summary_file = File::create(shelf_context.summary_file_name).unwrap();
|
||||
writeln!(summary_file, "# Summary")?;
|
||||
writeln!(
|
||||
summary_file,
|
||||
"- [{title}](./{INDEX_MD_FILE})",
|
||||
title = shelf_config.title
|
||||
)?;
|
||||
|
||||
let mut books_build_dir = std::env::current_dir()?;
|
||||
books_build_dir.push(BOOKSHELF_DIR);
|
||||
books_build_dir.push(BOOKS_DIR);
|
||||
|
||||
for sb in &shelf_config.books {
|
||||
let book_path = if let Some(url) = &sb.git_url {
|
||||
prepare_git(sb, url)
|
||||
} else if let Some(path) = &sb.path {
|
||||
Some(path.to_owned())
|
||||
} else {
|
||||
warn!("Neither path or git specified. Invalid book");
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(path) = book_path {
|
||||
let update_context = process_book(&path, &books_build_dir, &shelf_context.url)?;
|
||||
let _ = update_index(
|
||||
&mut index_file,
|
||||
&mut summary_file,
|
||||
&shelf_context.source_dir,
|
||||
&shelf_context.url_prefix,
|
||||
update_context,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
let shelf = MDBook::load(&shelf_context.book_dir)?;
|
||||
shelf.build()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn prepare_git(sb: &mdbook::config::ShelfBook, url: &String) -> Option<String> {
|
||||
println!("{:?}", sb);
|
||||
|
||||
// Prepare checkout directory name
|
||||
let path = sb.path.clone().unwrap_or("root".to_owned());
|
||||
let repo_raw_name = url.split('/').last().unwrap_or(&path);
|
||||
let repo_name = format!("{repo_raw_name}-{path}");
|
||||
let mut checkout_path = PathBuf::from(REPOS_DIR);
|
||||
checkout_path.push(repo_name);
|
||||
|
||||
let book_path = if let Some(path) = &sb.path {
|
||||
let mut bp = checkout_path.clone();
|
||||
bp.push(path);
|
||||
bp
|
||||
} else {
|
||||
checkout_path.clone()
|
||||
};
|
||||
|
||||
let repo = match git2::Repository::open(&checkout_path) {
|
||||
Ok(repo) => repo,
|
||||
Err(_) => match git2::Repository::clone(&url, &checkout_path) {
|
||||
Ok(repo) => repo,
|
||||
Err(e) => panic!("failed to clone: {}", e),
|
||||
},
|
||||
};
|
||||
|
||||
if let Some(refname) = &sb.git_ref {
|
||||
// branch or a tag (v0.1.1) or a commit (8e8128)
|
||||
let (object, reference) = if let Ok((object, reference)) = repo.revparse_ext(refname) {
|
||||
(object, reference)
|
||||
} else if let Ok((object, reference)) = repo.revparse_ext(&format!("origin/{refname}")) {
|
||||
(object, reference)
|
||||
} else {
|
||||
panic!("Could not checkout {refname}");
|
||||
};
|
||||
|
||||
repo.checkout_tree(&object, None)
|
||||
.expect("Failed to checkout");
|
||||
|
||||
match reference {
|
||||
// gref is an actual reference like branches or tags
|
||||
Some(gref) => repo.set_head(gref.name().unwrap()),
|
||||
// this is a commit, not a reference
|
||||
None => repo.set_head_detached(object.id()),
|
||||
}
|
||||
.expect("Failed to set HEAD");
|
||||
}
|
||||
|
||||
Some(book_path.to_str().unwrap().to_owned())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_toml() {
|
||||
let toml = r#"
|
||||
root_url_prefix = "myprefix"
|
||||
|
||||
[[book]]
|
||||
git_url = "firsturl"
|
||||
git_ref = "shelf"
|
||||
path = "guide"
|
||||
|
||||
[[book]]
|
||||
git_url = "secondurl"
|
||||
|
||||
[[book]]
|
||||
path = "../test_book"
|
||||
"#;
|
||||
let cfg: ShelfConfig = toml::from_str(&toml).unwrap();
|
||||
assert_eq!(cfg.root_url_prefix, "myprefix");
|
||||
|
||||
let book = &cfg.books[0];
|
||||
assert_eq!(book.git_url.clone().unwrap(), "firsturl");
|
||||
assert_eq!(book.git_ref.clone().unwrap(), "shelf");
|
||||
assert_eq!(book.path.clone().unwrap(), "guide");
|
||||
|
||||
let book = &cfg.books[1];
|
||||
assert_eq!(book.git_url.clone().unwrap(), "secondurl");
|
||||
assert!(book.git_ref.is_none());
|
||||
assert!(book.path.is_none());
|
||||
|
||||
let book = &cfg.books[2];
|
||||
assert_eq!(book.path.clone().unwrap(), "../test_book");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_defaults() {
|
||||
let toml = r#"
|
||||
[[book]]
|
||||
path = "../test_book"
|
||||
"#;
|
||||
let cfg: ShelfConfig = toml::from_str(&toml).unwrap();
|
||||
assert_eq!(cfg.root_url_prefix, "".to_owned());
|
||||
assert_eq!(cfg.title, "Bookshelf".to_owned());
|
||||
}
|
|
@ -414,6 +414,9 @@ pub struct BookConfig {
|
|||
/// The direction of text in the book: Left-to-right (LTR) or Right-to-left (RTL).
|
||||
/// When not specified, the text direction is derived from [`BookConfig::language`].
|
||||
pub text_direction: Option<TextDirection>,
|
||||
/// Indicates if the book is part of a bookshelf
|
||||
/// and how to return to the index of the shelf if so
|
||||
pub shelf_url: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for BookConfig {
|
||||
|
@ -426,6 +429,7 @@ impl Default for BookConfig {
|
|||
multilingual: false,
|
||||
language: Some(String::from("en")),
|
||||
text_direction: None,
|
||||
shelf_url: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -633,6 +637,43 @@ impl HtmlConfig {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
/// Represents a book in a shelf
|
||||
pub struct ShelfBook {
|
||||
/// Path to filesystem local book
|
||||
/// or if git_url is specified, the path inside the git
|
||||
/// where the book is located
|
||||
pub path: Option<String>,
|
||||
/// git url
|
||||
pub git_url: Option<String>,
|
||||
/// reference to checkout in git
|
||||
/// This can be a branch, commit or tag
|
||||
pub git_ref: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
/// Represents a shelf that contains a lot of books
|
||||
pub struct ShelfConfig {
|
||||
/// The books in the shelf
|
||||
#[serde(alias = "book")]
|
||||
pub books: Vec<ShelfBook>,
|
||||
/// this will be prepeneded to the backreference url
|
||||
/// Say you want to publish to www.example.com/mydocs
|
||||
/// you would set this to "mydocs" and then find your bookshelf at
|
||||
/// www.example.com/mydocs/bookshelf/shelf/book/index.html
|
||||
#[serde(default = "default_shelf_root_url")]
|
||||
pub root_url_prefix: String,
|
||||
/// Name of the shelf
|
||||
#[serde(default = "default_shelf_title")]
|
||||
pub title: String,
|
||||
}
|
||||
fn default_shelf_root_url() -> String {
|
||||
"".to_owned()
|
||||
}
|
||||
fn default_shelf_title() -> String {
|
||||
"Bookshelf".to_owned()
|
||||
}
|
||||
|
||||
/// Configuration for how to render the print icon, print.html, and print.css.
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(default, rename_all = "kebab-case")]
|
||||
|
@ -837,6 +878,7 @@ mod tests {
|
|||
src: PathBuf::from("source"),
|
||||
language: Some(String::from("ja")),
|
||||
text_direction: None,
|
||||
shelf_url: None,
|
||||
};
|
||||
let build_should_be = BuildConfig {
|
||||
build_dir: PathBuf::from("outputs"),
|
||||
|
|
|
@ -34,6 +34,7 @@ fn main() {
|
|||
#[cfg(feature = "serve")]
|
||||
Some(("serve", sub_matches)) => cmd::serve::execute(sub_matches),
|
||||
Some(("test", sub_matches)) => cmd::test::execute(sub_matches),
|
||||
Some(("shelf", sub_matches)) => cmd::shelf::execute(sub_matches),
|
||||
Some(("completions", sub_matches)) => (|| {
|
||||
let shell = sub_matches
|
||||
.get_one::<Shell>("shell")
|
||||
|
@ -84,7 +85,8 @@ fn create_clap_command() -> Command {
|
|||
.value_name("SHELL")
|
||||
.required(true),
|
||||
),
|
||||
);
|
||||
)
|
||||
.subcommand(cmd::shelf::make_subcommand());
|
||||
|
||||
#[cfg(feature = "watch")]
|
||||
let app = app.subcommand(cmd::watch::make_subcommand());
|
||||
|
|
|
@ -715,6 +715,10 @@ fn make_data(
|
|||
data.insert("fold_enable".to_owned(), json!(html_config.fold.enable));
|
||||
data.insert("fold_level".to_owned(), json!(html_config.fold.level));
|
||||
|
||||
if let Some(shelf_url) = &config.book.shelf_url {
|
||||
data.insert("book_shelf_url".to_owned(), json!(shelf_url));
|
||||
}
|
||||
|
||||
let search = html_config.search.clone();
|
||||
if cfg!(feature = "search") {
|
||||
let search = search.unwrap_or_default();
|
||||
|
|
|
@ -184,6 +184,11 @@
|
|||
<i id="git-edit-button" class="fa fa-edit"></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
{{#if book_shelf_url}}
|
||||
<a href="{{ book_shelf_url }}" title="Return to bookshelf" aria-label="Return to bookshelf">
|
||||
<i id="shelf-button" class="fa fa-book"></i>
|
||||
</a>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
*
|
|
@ -0,0 +1,10 @@
|
|||
[[book]]
|
||||
git_url = "https://github.com/Coi-l/mdBook.git"
|
||||
git_ref = "shelf"
|
||||
path = "guide"
|
||||
|
||||
[[book]]
|
||||
git_url = "https://github.com/rust-lang/book.git"
|
||||
|
||||
[[book]]
|
||||
path = "../test_book"
|
Loading…
Reference in New Issue