Jelajahi Sumber

Implement markdown compiler & program argument.

* Fix #3 - Generate markdown compiler
* Fix #7 - read program parameters
Alexandre Leblanc 5 tahun lalu
induk
melakukan
4dc7a56b1d
6 mengubah file dengan 141 tambahan dan 27 penghapusan
  1. 1 0
      .gitignore
  2. 83 0
      Cargo.lock
  3. 2 1
      Cargo.toml
  4. 53 26
      src/main.rs
  5. 1 0
      src/tests/file1.md
  6. 1 0
      src/tests/recursive/file2.md

+ 1 - 0
.gitignore

@@ -1,2 +1,3 @@
 /target
 **/*.rs.bk
+./out

+ 83 - 0
Cargo.lock

@@ -116,6 +116,14 @@ dependencies = [
  "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "heck"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "hermit-abi"
 version = "0.1.11"
@@ -188,6 +196,30 @@ dependencies = [
  "sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "proc-macro-error"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro-error-attr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "proc-macro2"
 version = "1.0.10"
@@ -225,6 +257,7 @@ name = "rs-webmark"
 version = "0.1.0"
 dependencies = [
  "comrak 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -243,6 +276,28 @@ name = "strsim"
 version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "structopt"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt-derive 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro-error 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "syn"
 version = "1.0.17"
@@ -253,6 +308,16 @@ dependencies = [
  "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "syn-mid"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "textwrap"
 version = "0.11.0"
@@ -298,6 +363,11 @@ name = "unchecked-index"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "unicode-segmentation"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "unicode-width"
 version = "0.1.7"
@@ -318,6 +388,11 @@ name = "vec_map"
 version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "version_check"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "winapi"
 version = "0.3.8"
@@ -352,6 +427,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum entities 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca"
 "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
 "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
+"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
 "checksum hermit-abi 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8a0d737e0f947a1864e93d33fdef4af8445a00d1ed8dc0c8ddb73139ea6abf15"
 "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 "checksum libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
@@ -362,13 +438,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
 "checksum pest_generator 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
 "checksum pest_meta 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
+"checksum proc-macro-error 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98e9e4b82e0ef281812565ea4751049f1bdcdfccda7d3f459f2e138a40c08678"
+"checksum proc-macro-error-attr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4f5444ead4e9935abd7f27dc51f7e852a0569ac888096d5ec2499470794e2e53"
 "checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
 "checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
 "checksum regex 1.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692"
 "checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
 "checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
 "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+"checksum structopt 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "863246aaf5ddd0d6928dfeb1a9ca65f505599e4e1b399935ef7e75107516b4ef"
+"checksum structopt-derive 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d239ca4b13aee7a2142e6795cbd69e457665ff8037aed33b3effdc430d2f927a"
 "checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
+"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
 "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
 "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
 "checksum twoway 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6b40075910de3a912adbd80b5d8bad6ad10a23eeb1f5bf9d4006839e899ba5bc"
@@ -376,10 +457,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
 "checksum ucd-trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 "checksum unchecked-index 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c"
+"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
 "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
 "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
 "checksum unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
 "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
+"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
 "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
 "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

+ 2 - 1
Cargo.toml

@@ -7,4 +7,5 @@ edition = "2018"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-comrak = "0.7"
+comrak = "0.7"
+structopt = "0.3"

+ 53 - 26
src/main.rs

@@ -1,10 +1,24 @@
-use std::path::Path;
+use std::path::{PathBuf, Path};
 use std::{fs, vec::Vec};
 
 use comrak::{markdown_to_html, ComrakOptions};
 
-fn list_markdown_files(path: &Path) -> Vec<String> {
-    let mut files = Vec::<String>::new();
+use structopt::StructOpt;
+
+#[derive(Debug, StructOpt)]
+#[structopt(name = "rs-webmark", about = "A markdown-to-html website.")]
+struct Opt {
+    /// Input file
+    #[structopt(parse(from_os_str), long = "input-directory", default_value = ".")]
+    input: PathBuf,
+
+    /// Output directory
+    #[structopt(parse(from_os_str), long = "output-directory", default_value = "./out")]
+    output: PathBuf,
+}
+
+fn list_markdown_files(path: &Path) -> Vec<PathBuf> {
+    let mut files = Vec::<PathBuf>::new();
     let dir_entries = fs::read_dir(path);
 
     match dir_entries {
@@ -22,7 +36,7 @@ fn list_markdown_files(path: &Path) -> Vec<String> {
                             match extension_wrapped {
                                 Some(extension) => {
                                     if extension == "md" {
-                                        files.push(entry.path().to_str().expect("Couldn't use file path.").to_owned());
+                                        files.push(entry.path());
                                     }
                                 },
                                 None => {}
@@ -43,7 +57,7 @@ fn list_markdown_files(path: &Path) -> Vec<String> {
     files
 }
 
-fn md_to_html(file: String) -> Result<String, String> {
+fn md_to_html(file: &Path) -> Result<String, String> {
     let content = fs::read_to_string(file);
 
     match content {
@@ -52,6 +66,23 @@ fn md_to_html(file: String) -> Result<String, String> {
     }
 }
 
+fn create_output_file_path(opt: &Opt, file: &Path) -> Result<(), Box<dyn std::error::Error + 'static>> {
+    let mut p = file.to_path_buf();
+    p.pop();
+    let s = format!("{}/{}", opt.output.to_str().unwrap(), p.to_str().unwrap());
+    fs::create_dir_all(&s)?;
+
+    Ok(())
+}
+
+fn get_dest_file_path(opt: &Opt, file: &PathBuf) -> Result<PathBuf, Box<dyn std::error::Error>> {
+    let mut file_stripped = file.strip_prefix(&opt.input).unwrap().to_owned();
+    let filename = format!("{}.html", file_stripped.file_stem().unwrap().to_str().unwrap());
+    file_stripped.pop();
+
+    Ok(opt.output.join(file_stripped).join(filename))
+}
+
 #[cfg(test)]
 mod tests_listing {
     use std::env;
@@ -75,43 +106,39 @@ mod tests_listing {
 }
 
 fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
-    let files = list_markdown_files(Path::new(""));
-    let base_directory = "";
-    let header_path = format!("{}/header.html", base_directory);
+    let opt: Opt = Opt::from_args();
+
+    let files = list_markdown_files(Path::new(&opt.input));
+
+    let header_path = format!("{}/header.html", opt.input.to_str().unwrap_or("."));
     let header_path = Path::new(&header_path);
-    let footer_path = format!("{}/footer.html", base_directory);
+    let footer_path = format!("{}/footer.html", opt.input.to_str().unwrap_or("."));
     let footer_path = Path::new(&footer_path);
 
     if !header_path.exists() {
         println!("[warning] No header.html found.");
     }
 
-    if footer_path.exists() {
+    if !footer_path.exists() {
         println!("[warning] No footer.html found.");
     }
 
-    let header_content = fs::read_to_string(header_path)?;
-    let footer_content = fs::read_to_string(footer_path)?;
-
-    // TODO:
-    // 1. Get working directory from args program -d <input_directory> -o <output_directory>
-    // 2. Get relative paths from input_directory. e.g.: /this/is/folder/[get/this/part/only]
-    //    to be able to construct same relative paths in output.
-    // 3. Convert content to new content and save file. (md_to_html should do it)
-    //
+    let header_content = fs::read_to_string(header_path).unwrap_or("".to_owned());
+    let footer_content = fs::read_to_string(footer_path).unwrap_or("".to_owned());
 
     for file in files {
+        // Create the folders path (equivalent to mkdir -p <path>)
+        create_output_file_path(&opt, &file)?;
 
-        let html_content = md_to_html(file)?;
-        let assembled = format!("{}{}{}", header_content, html_content, footer_content);
+        let html_content = md_to_html(&file)?;
+        let assembled_content = format!("{}{}{}", header_content, html_content, footer_content);
 
-        if fs::write(Path::new(base_directory), assembled).is_err() {
-            println!("Couldn't not write to file.");
-        }
+        let dest_path = get_dest_file_path(&opt, &file)?;
 
-        // Minification of HTML?
+        if fs::write(Path::new(&dest_path), assembled_content).is_err() {
+            println!("[error] Couldn't not write to file: {}", dest_path.to_str().unwrap());
+        }
     }
 
     Ok(())
 }
-

+ 1 - 0
src/tests/file1.md

@@ -0,0 +1 @@
+# Test

+ 1 - 0
src/tests/recursive/file2.md

@@ -0,0 +1 @@
+# TEst 2