Skip to content

Commit c75ca27

Browse files
committed
Allow for optional multiple shelves
1 parent 2903f07 commit c75ca27

File tree

3 files changed

+114
-47
lines changed

3 files changed

+114
-47
lines changed

src/cmd/shelf.rs

+61-41
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ use std::io::Read;
33
use std::io::Write;
44
use std::path::PathBuf;
55

6+
use mdbook::config::BookshelfConfig;
67
use resolve_path::PathResolveExt;
78

89
use super::command_prelude::*;
9-
use mdbook::config::ShelfConfig;
1010
use mdbook::errors::Result;
1111
use mdbook::MDBook;
1212

13-
const SHELF_DIR: &str = "shelf";
13+
const INDEX_BOOK_DIR: &str = "index";
1414
const REPOS_DIR: &str = "repositories";
1515
const INDEX_MD_FILE: &str = "index.md";
1616
const INDEX_HTML_FILE: &str = "index.html";
@@ -28,7 +28,7 @@ struct BookContext {
2828
authors: String,
2929
}
3030

31-
struct ShelfContext {
31+
struct BookshelfContext {
3232
book_dir: PathBuf,
3333
source_dir: PathBuf,
3434
url_prefix: String,
@@ -37,7 +37,7 @@ struct ShelfContext {
3737
summary_file_name: PathBuf,
3838
}
3939

40-
fn update_index(
40+
fn update_index_with_book(
4141
index_file: &mut File,
4242
summary_file: &mut File,
4343
shelf_source: &PathBuf,
@@ -46,7 +46,7 @@ fn update_index(
4646
) -> Result<()> {
4747
// Create post in index file
4848
let book_link = format!(
49-
"## [{title}](<{prefix}/{BOOKSHELF_DIR}/{BOOKS_DIR}/{title}/{INDEX_HTML_FILE}>)",
49+
"### [{title}](<{prefix}/{BOOKSHELF_DIR}/{BOOKS_DIR}/{title}/{INDEX_HTML_FILE}>)",
5050
title = context.title,
5151
prefix = root_prefix
5252
);
@@ -73,7 +73,6 @@ fn update_index(
7373
"- [{title}](./{file_name})",
7474
title = context.title
7575
)?;
76-
writeln!(summary_file)?;
7776

7877
Ok(())
7978
}
@@ -101,8 +100,8 @@ fn process_book(path: &str, books_dir: &PathBuf, shelf_url: &str) -> Result<Book
101100
Ok(book_context)
102101
}
103102

104-
fn setup_shelf_book(config: &ShelfConfig) -> Result<ShelfContext> {
105-
let book_dir = format!("{BOOKSHELF_DIR}/{SHELF_DIR}");
103+
fn setup_bookshelf_book(config: &BookshelfConfig) -> Result<BookshelfContext> {
104+
let book_dir = format!("{BOOKSHELF_DIR}/{INDEX_BOOK_DIR}");
106105
let book = MDBook::init(&book_dir).build()?;
107106
let build_dir = book.config.build.build_dir.to_str().unwrap_or_default();
108107
let url_prefix = if !config.root_url_prefix.is_empty() {
@@ -120,7 +119,7 @@ fn setup_shelf_book(config: &ShelfConfig) -> Result<ShelfContext> {
120119
let mut summary_file_name = book.source_dir();
121120
summary_file_name.push(SUMMARY_MD_FILE);
122121

123-
Ok(ShelfContext {
122+
Ok(BookshelfContext {
124123
book_dir: book_dir.into(),
125124
source_dir: book.source_dir(),
126125
url_prefix,
@@ -131,51 +130,64 @@ fn setup_shelf_book(config: &ShelfConfig) -> Result<ShelfContext> {
131130
}
132131

133132
pub fn execute(_args: &ArgMatches) -> Result<()> {
134-
let mut file = File::open("shelf.toml")?;
135-
let mut contents = String::new();
136-
file.read_to_string(&mut contents)?;
137-
let shelf_config: ShelfConfig = toml::from_str(&contents)?;
138-
133+
// Make sure everything is clean
139134
let _ = std::fs::remove_dir_all(BOOKSHELF_DIR);
140135
let _ = std::fs::remove_dir_all(REPOS_DIR);
141136

142-
let shelf_context = setup_shelf_book(&shelf_config)?;
137+
let mut file = File::open("shelf.toml")?;
138+
let mut contents = String::new();
139+
file.read_to_string(&mut contents)?;
140+
let bookshelf_config: BookshelfConfig = toml::from_str(&contents)?;
141+
let shelf_context = setup_bookshelf_book(&bookshelf_config)?;
143142

144143
let mut index_file = File::create(shelf_context.index_file_name).unwrap();
145-
writeln!(index_file, "# {title}", title = shelf_config.title)?;
144+
writeln!(index_file, "# {title}", title = bookshelf_config.title)?;
146145
writeln!(index_file)?;
147146

148147
let mut summary_file = File::create(shelf_context.summary_file_name).unwrap();
149148
writeln!(summary_file, "# Summary")?;
150149
writeln!(
151150
summary_file,
152-
"- [{title}](./{INDEX_MD_FILE})",
153-
title = shelf_config.title
151+
"[{title}](./{INDEX_MD_FILE})",
152+
title = bookshelf_config.title
154153
)?;
155154

156155
let mut books_build_dir = std::env::current_dir()?;
157156
books_build_dir.push(BOOKSHELF_DIR);
158157
books_build_dir.push(BOOKS_DIR);
158+
let books_build_dir = books_build_dir;
159159

160-
for sb in &shelf_config.books {
161-
let book_path = if let Some(url) = &sb.git_url {
162-
prepare_git(sb, url)
163-
} else if let Some(path) = &sb.path {
164-
Some(path.to_owned())
165-
} else {
166-
warn!("Neither path or git specified. Invalid book");
167-
None
168-
};
160+
let shelves = if let Some(shelves) = bookshelf_config.shelves {
161+
shelves
162+
} else if let Some(shelf) = bookshelf_config.shelf_config {
163+
vec![shelf]
164+
} else {
165+
error!("No shelves or default shelf found in config");
166+
Vec::new()
167+
};
169168

170-
if let Some(path) = book_path {
171-
let update_context = process_book(&path, &books_build_dir, &shelf_context.url)?;
172-
let _ = update_index(
173-
&mut index_file,
174-
&mut summary_file,
175-
&shelf_context.source_dir,
176-
&shelf_context.url_prefix,
177-
update_context,
178-
)?;
169+
for shelf_config in shelves {
170+
let _ = start_shelf(&mut index_file, &mut summary_file, &shelf_config.title);
171+
for sb in &shelf_config.books {
172+
let book_path = if let Some(url) = &sb.git_url {
173+
prepare_git(sb, url)
174+
} else if let Some(path) = &sb.path {
175+
Some(path.to_owned())
176+
} else {
177+
warn!("Neither path or git specified. Invalid book");
178+
None
179+
};
180+
181+
if let Some(path) = book_path {
182+
let update_context = process_book(&path, &books_build_dir, &shelf_context.url)?;
183+
let _ = update_index_with_book(
184+
&mut index_file,
185+
&mut summary_file,
186+
&shelf_context.source_dir,
187+
&shelf_context.url_prefix,
188+
update_context,
189+
)?;
190+
}
179191
}
180192
}
181193

@@ -185,6 +197,14 @@ pub fn execute(_args: &ArgMatches) -> Result<()> {
185197
Ok(())
186198
}
187199

200+
fn start_shelf(index_file: &mut File, summary_file: &mut File, title: &str) -> Result<()> {
201+
writeln!(summary_file, "# {title}")?;
202+
writeln!(summary_file)?;
203+
204+
writeln!(index_file, "## {title}")?;
205+
Ok(())
206+
}
207+
188208
fn prepare_git(sb: &mdbook::config::ShelfBook, url: &String) -> Option<String> {
189209
println!("{:?}", sb);
190210

@@ -252,20 +272,20 @@ git_url = "secondurl"
252272
[[book]]
253273
path = "../test_book"
254274
"#;
255-
let cfg: ShelfConfig = toml::from_str(&toml).unwrap();
275+
let cfg: BookshelfConfig = toml::from_str(&toml).unwrap();
256276
assert_eq!(cfg.root_url_prefix, "myprefix");
257277

258-
let book = &cfg.books[0];
278+
let book = &cfg.shelf_config.clone().unwrap().books[0];
259279
assert_eq!(book.git_url.clone().unwrap(), "firsturl");
260280
assert_eq!(book.git_ref.clone().unwrap(), "shelf");
261281
assert_eq!(book.path.clone().unwrap(), "guide");
262282

263-
let book = &cfg.books[1];
283+
let book = &cfg.shelf_config.clone().unwrap().books[1];
264284
assert_eq!(book.git_url.clone().unwrap(), "secondurl");
265285
assert!(book.git_ref.is_none());
266286
assert!(book.path.is_none());
267287

268-
let book = &cfg.books[2];
288+
let book = &cfg.shelf_config.clone().unwrap().books[2];
269289
assert_eq!(book.path.clone().unwrap(), "../test_book");
270290
}
271291

@@ -275,7 +295,7 @@ fn test_config_defaults() {
275295
[[book]]
276296
path = "../test_book"
277297
"#;
278-
let cfg: ShelfConfig = toml::from_str(&toml).unwrap();
298+
let cfg: BookshelfConfig = toml::from_str(&toml).unwrap();
279299
assert_eq!(cfg.root_url_prefix, "".to_owned());
280300
assert_eq!(cfg.title, "Bookshelf".to_owned());
281301
}

src/config.rs

+23-6
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ impl HtmlConfig {
637637
}
638638
}
639639

640-
#[derive(Deserialize, Debug)]
640+
#[derive(Deserialize, Debug, Clone)]
641641
/// Represents a book in a shelf
642642
pub struct ShelfBook {
643643
/// Path to filesystem local book
@@ -651,27 +651,44 @@ pub struct ShelfBook {
651651
pub git_ref: Option<String>,
652652
}
653653

654-
#[derive(Deserialize, Debug)]
654+
#[derive(Deserialize, Debug, Clone)]
655655
/// Represents a shelf that contains a lot of books
656656
pub struct ShelfConfig {
657657
/// The books in the shelf
658658
#[serde(alias = "book")]
659659
pub books: Vec<ShelfBook>,
660+
/// Name of the shelf
661+
#[serde(default = "default_shelf_title")]
662+
pub title: String,
663+
}
664+
fn default_shelf_title() -> String {
665+
"Bookshelf".to_owned()
666+
}
667+
668+
#[derive(Deserialize, Debug)]
669+
///
670+
pub struct BookshelfConfig {
671+
///
672+
#[serde(alias = "shelf")]
673+
pub shelves: Option<Vec<ShelfConfig>>,
674+
///
675+
#[serde(flatten)]
676+
pub shelf_config: Option<ShelfConfig>,
660677
/// this will be prepeneded to the backreference url
661678
/// Say you want to publish to www.example.com/mydocs
662679
/// you would set this to "mydocs" and then find your bookshelf at
663680
/// www.example.com/mydocs/bookshelf/shelf/book/index.html
664681
#[serde(default = "default_shelf_root_url")]
665682
pub root_url_prefix: String,
666-
/// Name of the shelf
667-
#[serde(default = "default_shelf_title")]
683+
///
684+
#[serde(default = "default_bookshelf_title")]
668685
pub title: String,
669686
}
670687
fn default_shelf_root_url() -> String {
671688
"".to_owned()
672689
}
673-
fn default_shelf_title() -> String {
674-
"Bookshelf".to_owned()
690+
fn default_bookshelf_title() -> String {
691+
"Overview".to_owned()
675692
}
676693

677694
/// Configuration for how to render the print icon, print.html, and print.css.

test_shelf/shelf.toml

+30
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# Set this to your full path /<full_path>/test_shelf to be able to browse locally
2+
# or any kind of prefix that you need for when you publish online
3+
root_url_prefix = ""
4+
5+
# Use the first setup here for the simple one shelf structure
6+
17
[[book]]
28
git_url = "https://github.com/Coi-l/mdBook.git"
39
git_ref = "shelf"
@@ -8,3 +14,27 @@ git_url = "https://github.com/rust-lang/book.git"
814

915
[[book]]
1016
path = "../test_book"
17+
18+
##########################
19+
##########################
20+
##########################
21+
# Uncomment the setup below to test the multishelf/category structure
22+
23+
24+
# title = "Documentation"
25+
26+
# [[shelf]]
27+
# title = "MdBook"
28+
29+
# [[shelf.book]]
30+
# git_url = "https://github.com/Coi-l/mdBook.git"
31+
# git_ref = "shelf"
32+
# path = "guide"
33+
34+
# [[shelf.book]]
35+
# path = "../test_book"
36+
37+
# [[shelf]]
38+
# title = "Rust"
39+
# [[shelf.book]]
40+
# git_url = "https://github.com/rust-lang/book.git"

0 commit comments

Comments
 (0)