]>
Commit | Line | Data |
---|---|---|
74b04a01 XL |
1 | #[macro_use] |
2 | extern crate lazy_static; | |
13cf67c4 | 3 | |
74b04a01 | 4 | use std::collections::BTreeMap; |
13cf67c4 | 5 | use std::env; |
74b04a01 | 6 | use std::fs::{create_dir, read_dir, File}; |
13cf67c4 XL |
7 | use std::io; |
8 | use std::io::{Read, Write}; | |
13cf67c4 | 9 | use std::path::{Path, PathBuf}; |
74b04a01 | 10 | use std::process::exit; |
13cf67c4 XL |
11 | |
12 | use regex::Regex; | |
13 | ||
14 | static PATTERNS: &'static [(&'static str, &'static str)] = &[ | |
15 | (r"ch(\d\d)-\d\d-.*\.md", "chapter$1.md"), | |
16 | (r"appendix-(\d\d).*\.md", "appendix.md"), | |
17 | ]; | |
18 | ||
19 | lazy_static! { | |
20 | static ref MATCHERS: Vec<(Regex, &'static str)> = { | |
74b04a01 XL |
21 | PATTERNS |
22 | .iter() | |
13cf67c4 XL |
23 | .map(|&(expr, repl)| (Regex::new(expr).unwrap(), repl)) |
24 | .collect() | |
25 | }; | |
26 | } | |
27 | ||
28 | fn main() { | |
29 | let args: Vec<String> = env::args().collect(); | |
30 | ||
31 | if args.len() < 3 { | |
32 | println!("Usage: {} <src-dir> <target-dir>", args[0]); | |
33 | exit(1); | |
34 | } | |
35 | ||
36 | let source_dir = ensure_dir_exists(&args[1]).unwrap(); | |
37 | let target_dir = ensure_dir_exists(&args[2]).unwrap(); | |
38 | ||
39 | let mut matched_files = match_files(source_dir, target_dir); | |
40 | matched_files.sort(); | |
41 | ||
42 | for (target_path, source_paths) in group_by_target(matched_files) { | |
43 | concat_files(source_paths, target_path).unwrap(); | |
44 | } | |
45 | } | |
46 | ||
74b04a01 XL |
47 | fn match_files( |
48 | source_dir: &Path, | |
49 | target_dir: &Path, | |
50 | ) -> Vec<(PathBuf, PathBuf)> { | |
13cf67c4 XL |
51 | read_dir(source_dir) |
52 | .expect("Unable to read source directory") | |
53 | .filter_map(|maybe_entry| maybe_entry.ok()) | |
54 | .filter_map(|entry| { | |
55 | let source_filename = entry.file_name(); | |
74b04a01 XL |
56 | let source_filename = |
57 | &source_filename.to_string_lossy().into_owned(); | |
13cf67c4 XL |
58 | for &(ref regex, replacement) in MATCHERS.iter() { |
59 | if regex.is_match(source_filename) { | |
74b04a01 XL |
60 | let target_filename = |
61 | regex.replace_all(source_filename, replacement); | |
13cf67c4 XL |
62 | let source_path = entry.path(); |
63 | let mut target_path = PathBuf::from(&target_dir); | |
74b04a01 | 64 | target_path.push(target_filename.to_string()); |
13cf67c4 XL |
65 | return Some((source_path, target_path)); |
66 | } | |
67 | } | |
68 | None | |
69 | }) | |
70 | .collect() | |
71 | } | |
72 | ||
74b04a01 XL |
73 | fn group_by_target( |
74 | matched_files: Vec<(PathBuf, PathBuf)>, | |
75 | ) -> BTreeMap<PathBuf, Vec<PathBuf>> { | |
13cf67c4 XL |
76 | let mut grouped: BTreeMap<PathBuf, Vec<PathBuf>> = BTreeMap::new(); |
77 | for (source, target) in matched_files { | |
78 | if let Some(source_paths) = grouped.get_mut(&target) { | |
79 | source_paths.push(source); | |
80 | continue; | |
81 | } | |
82 | let source_paths = vec![source]; | |
83 | grouped.insert(target.clone(), source_paths); | |
84 | } | |
85 | grouped | |
86 | } | |
87 | ||
74b04a01 XL |
88 | fn concat_files( |
89 | source_paths: Vec<PathBuf>, | |
90 | target_path: PathBuf, | |
91 | ) -> io::Result<()> { | |
13cf67c4 | 92 | println!("Concatenating into {}:", target_path.to_string_lossy()); |
9fa01778 | 93 | let mut target = File::create(target_path)?; |
5099ac24 FG |
94 | |
95 | write!(target, "\ | |
96 | <!-- DO NOT EDIT THIS FILE. | |
97 | ||
98 | This file is periodically generated from the content in the `/src/` | |
99 | directory, so all fixes need to be made in `/src/`. | |
100 | --> | |
101 | ||
102 | [TOC] | |
103 | ")?; | |
13cf67c4 XL |
104 | |
105 | for path in source_paths { | |
106 | println!(" {}", path.to_string_lossy()); | |
9fa01778 | 107 | let mut source = File::open(path)?; |
13cf67c4 | 108 | let mut contents: Vec<u8> = Vec::new(); |
9fa01778 | 109 | source.read_to_end(&mut contents)?; |
13cf67c4 | 110 | |
9fa01778 XL |
111 | target.write_all(b"\n")?; |
112 | target.write_all(&contents)?; | |
113 | target.write_all(b"\n")?; | |
13cf67c4 XL |
114 | } |
115 | Ok(()) | |
116 | } | |
117 | ||
118 | fn ensure_dir_exists(dir_string: &str) -> io::Result<&Path> { | |
119 | let path = Path::new(dir_string); | |
120 | if !path.exists() { | |
9fa01778 | 121 | create_dir(path)?; |
13cf67c4 XL |
122 | } |
123 | Ok(&path) | |
124 | } |