Browse Source

Get tests to pass in parallel

master
Dylan Baker 5 years ago
parent
commit
5bc14208ac
8 changed files with 721 additions and 593 deletions
  1. 118
    0
      Cargo.lock
  2. 1
    0
      Cargo.toml
  3. 0
    551
      src/commands.rs
  4. 18
    19
      src/entry.rs
  5. 263
    0
      src/lib.rs
  6. 18
    20
      src/main.rs
  7. 0
    3
      test
  8. 303
    0
      tests/integration_test.rs

+ 118
- 0
Cargo.lock View File

@@ -24,6 +24,11 @@ dependencies = [
24 24
  "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
25 25
 ]
26 26
 
27
+[[package]]
28
+name = "autocfg"
29
+version = "0.1.2"
30
+source = "registry+https://github.com/rust-lang/crates.io-index"
31
+
27 32
 [[package]]
28 33
 name = "bitflags"
29 34
 version = "0.7.0"
@@ -59,6 +64,7 @@ dependencies = [
59 64
  "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
60 65
  "notify 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
61 66
  "regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
67
+ "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
62 68
  "toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
63 69
  "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
64 70
 ]
@@ -413,6 +419,32 @@ dependencies = [
413 419
  "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
414 420
 ]
415 421
 
422
+[[package]]
423
+name = "rand"
424
+version = "0.6.4"
425
+source = "registry+https://github.com/rust-lang/crates.io-index"
426
+dependencies = [
427
+ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
428
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
429
+ "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
430
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
431
+ "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
432
+ "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
433
+ "rand_os 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
434
+ "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
435
+ "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
436
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
437
+]
438
+
439
+[[package]]
440
+name = "rand_chacha"
441
+version = "0.1.1"
442
+source = "registry+https://github.com/rust-lang/crates.io-index"
443
+dependencies = [
444
+ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
445
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
446
+]
447
+
416 448
 [[package]]
417 449
 name = "rand_core"
418 450
 version = "0.2.2"
@@ -426,6 +458,60 @@ name = "rand_core"
426 458
 version = "0.3.0"
427 459
 source = "registry+https://github.com/rust-lang/crates.io-index"
428 460
 
461
+[[package]]
462
+name = "rand_hc"
463
+version = "0.1.0"
464
+source = "registry+https://github.com/rust-lang/crates.io-index"
465
+dependencies = [
466
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
467
+]
468
+
469
+[[package]]
470
+name = "rand_isaac"
471
+version = "0.1.1"
472
+source = "registry+https://github.com/rust-lang/crates.io-index"
473
+dependencies = [
474
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
475
+]
476
+
477
+[[package]]
478
+name = "rand_os"
479
+version = "0.1.1"
480
+source = "registry+https://github.com/rust-lang/crates.io-index"
481
+dependencies = [
482
+ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
483
+ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
484
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
485
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
486
+ "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
487
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
488
+]
489
+
490
+[[package]]
491
+name = "rand_pcg"
492
+version = "0.1.1"
493
+source = "registry+https://github.com/rust-lang/crates.io-index"
494
+dependencies = [
495
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
496
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
497
+]
498
+
499
+[[package]]
500
+name = "rand_xorshift"
501
+version = "0.1.1"
502
+source = "registry+https://github.com/rust-lang/crates.io-index"
503
+dependencies = [
504
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
505
+]
506
+
507
+[[package]]
508
+name = "rdrand"
509
+version = "0.4.0"
510
+source = "registry+https://github.com/rust-lang/crates.io-index"
511
+dependencies = [
512
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
513
+]
514
+
429 515
 [[package]]
430 516
 name = "redox_syscall"
431 517
 version = "0.1.42"
@@ -459,6 +545,14 @@ dependencies = [
459 545
  "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
460 546
 ]
461 547
 
548
+[[package]]
549
+name = "remove_dir_all"
550
+version = "0.5.1"
551
+source = "registry+https://github.com/rust-lang/crates.io-index"
552
+dependencies = [
553
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
554
+]
555
+
462 556
 [[package]]
463 557
 name = "rustc_version"
464 558
 version = "0.2.3"
@@ -539,6 +633,19 @@ dependencies = [
539 633
  "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
540 634
 ]
541 635
 
636
+[[package]]
637
+name = "tempfile"
638
+version = "3.0.5"
639
+source = "registry+https://github.com/rust-lang/crates.io-index"
640
+dependencies = [
641
+ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
642
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
643
+ "rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
644
+ "redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
645
+ "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
646
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
647
+]
648
+
542 649
 [[package]]
543 650
 name = "termion"
544 651
 version = "1.5.1"
@@ -747,6 +854,7 @@ dependencies = [
747 854
 "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
748 855
 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
749 856
 "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
857
+"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
750 858
 "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
751 859
 "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
752 860
 "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
@@ -790,12 +898,21 @@ dependencies = [
790 898
 "checksum pest_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3294f437119209b084c797604295f40227cffa35c57220b1e99a6ff3bf8ee4"
791 899
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
792 900
 "checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
901
+"checksum rand 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3906503e80ac6cbcacb2c2973fa8e473f24d7e2747c8c92bb230c2441cad96b5"
902
+"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
793 903
 "checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372"
794 904
 "checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
905
+"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
906
+"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
907
+"checksum rand_os 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46fbd5550acf75b0c2730f5dd1873751daf9beb8f11b44027778fae50d7feca"
908
+"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05"
909
+"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
910
+"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
795 911
 "checksum redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "cf8fb82a4d1c9b28f1c26c574a5b541f5ffb4315f6c9a791fa47b6a04438fe93"
796 912
 "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
797 913
 "checksum regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ee84f70c8c08744ea9641a731c7fadb475bf2ecc52d7f627feb833e0b3990467"
798 914
 "checksum regex-syntax 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fbc557aac2b708fe84121caf261346cc2eed71978024337e42eb46b8a252ac6e"
915
+"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
799 916
 "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
800 917
 "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
801 918
 "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
@@ -808,6 +925,7 @@ dependencies = [
808 925
 "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
809 926
 "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
810 927
 "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
928
+"checksum tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2"
811 929
 "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
812 930
 "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
813 931
 "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"

+ 1
- 0
Cargo.toml View File

@@ -15,5 +15,6 @@ fs_extra = "1.1.0"
15 15
 lazy_static = "1.2.0"
16 16
 notify = "4.0.0"
17 17
 regex = "1"
18
+tempfile = "3"
18 19
 toml = "0.4.8"
19 20
 uuid = { version = "0.7", features = ["v4"] }

+ 0
- 551
src/commands.rs View File

@@ -1,551 +0,0 @@
1
-use std::sync::mpsc::channel;
2
-use std::time::Duration;
3
-use std::{env, fs, path};
4
-
5
-use fs_extra::dir;
6
-use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
7
-use toml::Value;
8
-
9
-use config::Config;
10
-use entry::{parse_entry, read_entry_dir, write_entry, write_entry_listing, Entry};
11
-
12
-pub fn build(include_drafts: bool) {
13
-    let cwd = env::current_dir().expect("Couldn't read current directory");
14
-    let config = match fs::read_to_string(cwd.join("casaubon.toml")) {
15
-        Ok(contents) => match contents.parse::<Value>() {
16
-            Ok(config) => Config {
17
-                site_name: String::from(config["site_name"].as_str().unwrap()),
18
-            },
19
-            Err(_) => panic!("Invalid casaubon.toml"),
20
-        },
21
-        Err(_) => {
22
-            panic!("Can't find casaubon.toml");
23
-        }
24
-    };
25
-
26
-    match fs::read_dir(cwd.join("public")) {
27
-        Ok(_) => {
28
-            fs::remove_dir_all(cwd.join("public")).unwrap();
29
-        }
30
-        Err(_) => {}
31
-    }
32
-
33
-    fs::create_dir(cwd.join("public")).expect("Couldn't create public directory");
34
-    fs::create_dir(cwd.join("public").join("posts")).expect("Couldn't create posts directory");
35
-
36
-    let layout_template = fs::read_to_string(&cwd.join("templates").join("layout.html"))
37
-        .expect("Couldn't find layout template");
38
-    let post_template = fs::read_to_string(cwd.join("templates").join("post.html"))
39
-        .expect("Couldn't find post template");
40
-    let post_listing_template = fs::read_to_string(cwd.join("templates").join("post_listing.html"))
41
-        .expect("Couldn't find post listing item template");
42
-    let post_item_template =
43
-        fs::read_to_string(cwd.join("templates").join("post_listing_item.html"))
44
-            .expect("Couldn't find post listing item template");
45
-    let page_template = fs::read_to_string(cwd.join("templates").join("page.html"))
46
-        .expect("Couldn't find page template");
47
-
48
-    let post_paths = match include_drafts {
49
-        true => {
50
-            let mut posts = read_entry_dir(&cwd.join("posts"));
51
-            posts.append(&mut read_entry_dir(&cwd.join("drafts")));
52
-            posts
53
-        }
54
-        false => read_entry_dir(&cwd.join("posts")),
55
-    };
56
-
57
-    let page_paths = read_entry_dir(&cwd.join("pages"));
58
-
59
-    let mut posts: Vec<Entry> = post_paths
60
-        .into_iter()
61
-        .map(|entry| {
62
-            let path = entry.path();
63
-            let contents = fs::read_to_string(&path).expect("Couldn't read post file");
64
-            parse_entry(&contents, path)
65
-        })
66
-        .collect::<Vec<Entry>>();
67
-
68
-    posts.sort_by(|a, b| b.date.cmp(&a.date));
69
-
70
-    for post in &posts {
71
-        write_entry(&cwd, &layout_template, &post_template, &post, &config);
72
-    }
73
-
74
-    for entry in page_paths.into_iter() {
75
-        let path = entry.path();
76
-        let contents = fs::read_to_string(&path).expect("Couldn't read page file");
77
-        let page = parse_entry(&contents, path);
78
-        write_entry(&cwd, &layout_template, &page_template, &page, &config);
79
-    }
80
-
81
-    write_entry_listing(
82
-        &cwd,
83
-        &layout_template,
84
-        &post_listing_template,
85
-        &post_item_template,
86
-        &posts,
87
-        &config,
88
-    );
89
-
90
-    fs_extra::copy_items(
91
-        &vec![cwd.join("css"), cwd.join("js")],
92
-        cwd.join("public"),
93
-        &dir::CopyOptions::new(),
94
-    )
95
-    .expect("Couldn't copy css/js directories");
96
-}
97
-
98
-pub fn new(name: &str) {
99
-    let cwd = env::current_dir().expect("Couldn't read current directory");
100
-    let project_path = cwd.join(name);
101
-
102
-    fs::create_dir(&project_path).expect(&format!("Couldn't create directory '{}'", &name));
103
-    fs::write(
104
-        project_path.join("casaubon.toml"),
105
-        format!("site_name = \"{}\"", &name),
106
-    )
107
-    .expect("Could not create casaubon.toml");
108
-
109
-    for dir in &[
110
-        "drafts",
111
-        "posts",
112
-        "pages",
113
-        "public",
114
-        "templates",
115
-        "css",
116
-        "js",
117
-    ] {
118
-        fs::create_dir(&project_path.join(&dir))
119
-            .expect(&format!("Couldn't create {} directory", &dir));
120
-    }
121
-
122
-    fs::write(project_path.join("css").join("style.css"), "")
123
-        .expect("Couldn't create css/style.css");
124
-    fs::write(project_path.join("js").join("index.js"), "").expect("Couldn't create js/index.js");
125
-
126
-    let default_layout_template = format!(
127
-        "<html>
128
-  <head>
129
-    <title>{}</title>
130
-  </head>
131
-  <body>
132
-    <h1>{}</h1>
133
-    {{{{ contents }}}}
134
-  </body>
135
-</html>\n",
136
-        name, name
137
-    );
138
-    let default_post_listing_template = format!(
139
-        "<div>
140
-  <h3>Posts</h3>
141
-  <ul>{{{{ post_listing }}}}</ul>
142
-</div>\n"
143
-    );
144
-    let default_post_template = format!(
145
-        "<article>
146
-  <h1>{{{{ title }}}}</h1>
147
-  <div>{{{{ body }}}}</div>
148
-</article>\n"
149
-    );
150
-    let default_page_template = format!(
151
-        "<article>
152
-  <h1>{{{{ title }}}}</h1>
153
-  <div>{{{{ body }}}}</div>
154
-</article>\n"
155
-    );
156
-    let default_post_listing_item_template = format!(
157
-        "<li>
158
-  {{ date }} <a href=\"/posts/{{{{ slug }}}}/\">{{{{ title }}}}</a>
159
-</li>\n"
160
-    );
161
-
162
-    for (filename, contents) in &[
163
-        ("layout", &default_layout_template),
164
-        ("post_listing", &default_post_listing_template),
165
-        ("post", &default_post_template),
166
-        ("page", &default_page_template),
167
-        ("post_listing_item", &default_post_listing_item_template),
168
-    ] {
169
-        fs::write(
170
-            &project_path
171
-                .join("templates")
172
-                .join(format!("{}.html", filename)),
173
-            &contents,
174
-        )
175
-        .expect(&format!("Couldn't write templates/{}.html", filename));
176
-    }
177
-}
178
-
179
-fn should_rebuild(cwd: &path::PathBuf, path: &path::PathBuf) -> bool {
180
-    let path_string = path.to_str().unwrap().to_string();
181
-    let change_is_from_public = path_string.contains(cwd.join("public").to_str().unwrap());
182
-    let change_is_from_git = path_string.contains(cwd.join(".git").to_str().unwrap());
183
-
184
-    !change_is_from_public && !change_is_from_git
185
-}
186
-
187
-pub fn watch(include_drafts: bool) -> notify::Result<()> {
188
-    let cwd = env::current_dir().expect("Couldn't read current directory");
189
-    let (tx, rx) = channel();
190
-    let mut watcher: RecommendedWatcher = try!(Watcher::new(tx, Duration::from_secs(2)));
191
-    try!(watcher.watch(&cwd, RecursiveMode::Recursive));
192
-    println!("Watching {}", cwd.to_str().unwrap());
193
-
194
-    let handle_event = |path: &path::PathBuf| {
195
-        if should_rebuild(&cwd, &path) {
196
-            println!("Rebuilding");
197
-            build(include_drafts);
198
-        }
199
-    };
200
-
201
-    loop {
202
-        match rx.recv() {
203
-            Ok(e) => match e {
204
-                DebouncedEvent::Create(path) => {
205
-                    handle_event(&path);
206
-                }
207
-                DebouncedEvent::Write(path) => {
208
-                    handle_event(&path);
209
-                }
210
-                _ => {}
211
-            },
212
-            Err(e) => println!("watch error: {:?}", e),
213
-        }
214
-    }
215
-}
216
-
217
-#[cfg(test)]
218
-mod tests {
219
-    #[allow(unused_imports)]
220
-    use super::*;
221
-    #[allow(unused_imports)]
222
-    use uuid::Uuid;
223
-
224
-    #[test]
225
-    fn test_new() {
226
-        let temp_dir = env::temp_dir();
227
-        env::set_current_dir(&temp_dir).unwrap();
228
-
229
-        let uuid = Uuid::new_v4().to_string();
230
-        let project_dir = temp_dir.join(&uuid);
231
-        new(&uuid);
232
-
233
-        for dir in &["public", "pages", "posts", "templates"] {
234
-            fs::read_dir(&project_dir.join(dir)).unwrap();
235
-        }
236
-
237
-        assert_eq!(
238
-            format!(
239
-                "<html><head><title>{}</title></head><body><h1>{}</h1>{{{{ contents }}}}</body></html>",
240
-                uuid, uuid
241
-            ),
242
-            fs::read_to_string(&project_dir.join("templates").join("layout.html"))
243
-                .unwrap()
244
-                .replace("\n", "")
245
-                .replace("  ", "")
246
-        );
247
-        assert_eq!(
248
-            format!("<div><h3>Posts</h3><ul>{{{{ post_listing }}}}</ul></div>"),
249
-            fs::read_to_string(&project_dir.join("templates").join("post_listing.html"))
250
-                .unwrap()
251
-                .replace("\n", "")
252
-                .replace("  ", "")
253
-        );
254
-        assert_eq!(
255
-            format!("<li>{{ date }} <a href=\"/posts/{{{{ slug }}}}/\">{{{{ title }}}}</a></li>"),
256
-            fs::read_to_string(&project_dir.join("templates").join("post_listing_item.html"))
257
-                .unwrap()
258
-                .replace("\n", "")
259
-                .replace("  ", "")
260
-        );
261
-        assert_eq!(
262
-            format!("<article><h1>{{{{ title }}}}</h1><div>{{{{ body }}}}</div></article>"),
263
-            fs::read_to_string(&project_dir.join("templates").join("post.html"))
264
-                .unwrap()
265
-                .replace("\n", "")
266
-                .replace("  ", "")
267
-        );
268
-        assert_eq!(
269
-            format!("<article><h1>{{{{ title }}}}</h1><div>{{{{ body }}}}</div></article>"),
270
-            fs::read_to_string(&project_dir.join("templates").join("page.html"))
271
-                .unwrap()
272
-                .replace("\n", "")
273
-                .replace("  ", "")
274
-        );
275
-        assert_eq!(
276
-            "",
277
-            fs::read_to_string(&project_dir.join("css").join("style.css")).unwrap()
278
-        );
279
-        assert_eq!(
280
-            "",
281
-            fs::read_to_string(&project_dir.join("js").join("index.js")).unwrap()
282
-        );
283
-        assert_eq!(
284
-            format!("site_name = \"{}\"", &uuid),
285
-            fs::read_to_string(&project_dir.join("casaubon.toml")).unwrap()
286
-        );
287
-
288
-        fs::remove_dir_all(project_dir).unwrap();
289
-    }
290
-
291
-    #[test]
292
-    fn test_build() {
293
-        let temp_dir = env::temp_dir();
294
-        let uuid = Uuid::new_v4().to_string();
295
-        let project_dir = temp_dir.join(&uuid);
296
-        fs::create_dir(&project_dir).unwrap();
297
-        env::set_current_dir(&project_dir).unwrap();
298
-
299
-        fs::create_dir(project_dir.join("posts")).unwrap();
300
-        fs::create_dir(project_dir.join("pages")).unwrap();
301
-        fs::create_dir(project_dir.join("public")).unwrap();
302
-        fs::create_dir(project_dir.join("public").join("posts")).unwrap();
303
-        fs::create_dir(project_dir.join("templates")).unwrap();
304
-        fs::create_dir(project_dir.join("css")).unwrap();
305
-        fs::create_dir(project_dir.join("js")).unwrap();
306
-
307
-        fs::write(
308
-            project_dir.join("css").join("style.css"),
309
-            "body { background: blue; }",
310
-        )
311
-        .unwrap();
312
-        fs::write(
313
-            project_dir.join("js").join("index.js"),
314
-            "window.onload = function () { alert() }",
315
-        )
316
-        .unwrap();
317
-        fs::write(
318
-            project_dir.join("templates").join("layout.html"),
319
-            "<html><head><title>{{ page_title }}</title></head><body>{{ contents }}</body></html>",
320
-        )
321
-        .unwrap();
322
-        fs::write(
323
-            project_dir.join("templates").join("post.html"),
324
-            "<article><h1>{{ title }}</h1><div>{{ body }}</div></article>",
325
-        )
326
-        .unwrap();
327
-        fs::write(
328
-            project_dir.join("templates").join("page.html"),
329
-            "<article class=\"page\"><h1>{{ title }}</h1><div>{{ body }}</div></article>",
330
-        )
331
-        .unwrap();
332
-        fs::write(
333
-            project_dir.join("templates").join("post_listing.html"),
334
-            "<ul>{{ post_listing }}</ul>",
335
-        )
336
-        .unwrap();
337
-        fs::write(
338
-            project_dir.join("templates").join("post_listing_item.html"),
339
-            "<li><a href=\"/{{ slug }}\">{{ title }}</a></li>",
340
-        )
341
-        .unwrap();
342
-        fs::write(
343
-            project_dir.join("posts").join("first-post.md"),
344
-            "# First post | 2019-01-01\n\nThis is the first post\n\nIt has multiple paragraphs",
345
-        )
346
-        .unwrap();
347
-        fs::write(
348
-            project_dir.join("pages").join("first-page.md"),
349
-            "# First page\n\nThis is the first page\n\nIt has multiple paragraphs",
350
-        )
351
-        .unwrap();
352
-        fs::write(
353
-            project_dir.join("casaubon.toml"),
354
-            "site_name = \"Test Site\"",
355
-        )
356
-        .unwrap();
357
-
358
-        build(false);
359
-
360
-        assert_eq!(
361
-            "<html><head><title>Test Site</title></head><body><ul><li><a href=\"/fir\
362
-             st-post\">First post</a></li></ul></body></html>",
363
-            fs::read_to_string(project_dir.join("public").join("index.html")).unwrap(),
364
-        );
365
-
366
-        assert_eq!(
367
-            "<html><head><title>First post | Test Site</title></head><body><article><h1>First pos\
368
-             t</h1><div><p>This is the first post</p><p>It has multiple paragra\
369
-             phs</p></div></article></body></html>",
370
-            fs::read_to_string(
371
-                project_dir
372
-                    .join("public")
373
-                    .join("posts")
374
-                    .join("first-post")
375
-                    .join("index.html")
376
-            )
377
-            .unwrap()
378
-            .replace("\n", ""),
379
-        );
380
-
381
-        assert_eq!(
382
-            "<html><head><title>First page | Test Site</title></head><body><article class=\"page\"><h1>First pag\
383
-             e</h1><div><p>This is the first page</p><p>It has multiple paragra\
384
-             phs</p></div></article></body></html>",
385
-            fs::read_to_string(
386
-                project_dir
387
-                    .join("public")
388
-                    .join("first-page")
389
-                    .join("index.html")
390
-            )
391
-            .unwrap()
392
-            .replace("\n", ""),
393
-        );
394
-
395
-        assert_eq!(
396
-            "body { background: blue; }",
397
-            fs::read_to_string(project_dir.join("public").join("css").join("style.css")).unwrap()
398
-        );
399
-
400
-        assert_eq!(
401
-            "window.onload = function () { alert() }",
402
-            fs::read_to_string(project_dir.join("public").join("js").join("index.js")).unwrap()
403
-        );
404
-
405
-        fs::remove_dir_all(project_dir).unwrap();
406
-    }
407
-
408
-    #[test]
409
-    fn test_build_drafts() {
410
-        let temp_dir = env::temp_dir();
411
-        let uuid = Uuid::new_v4().to_string();
412
-        let project_dir = temp_dir.join(&uuid);
413
-        fs::create_dir(&project_dir).unwrap();
414
-        env::set_current_dir(&project_dir).unwrap();
415
-
416
-        fs::create_dir(project_dir.join("drafts")).unwrap();
417
-        fs::create_dir(project_dir.join("posts")).unwrap();
418
-        fs::create_dir(project_dir.join("pages")).unwrap();
419
-        fs::create_dir(project_dir.join("public")).unwrap();
420
-        fs::create_dir(project_dir.join("public").join("posts")).unwrap();
421
-        fs::create_dir(project_dir.join("templates")).unwrap();
422
-        fs::create_dir(project_dir.join("css")).unwrap();
423
-        fs::create_dir(project_dir.join("js")).unwrap();
424
-
425
-        fs::write(
426
-            project_dir.join("css").join("style.css"),
427
-            "body { background: blue; }",
428
-        )
429
-        .unwrap();
430
-        fs::write(
431
-            project_dir.join("js").join("index.js"),
432
-            "window.onload = function () { alert() }",
433
-        )
434
-        .unwrap();
435
-        fs::write(
436
-            project_dir.join("templates").join("layout.html"),
437
-            "<html><head><title>{{ page_title }}</title></head><body>{{ contents }}</body></html>",
438
-        )
439
-        .unwrap();
440
-        fs::write(
441
-            project_dir.join("templates").join("post.html"),
442
-            "<article><h1>{{ title }}</h1><div>{{ body }}</div></article>",
443
-        )
444
-        .unwrap();
445
-        fs::write(
446
-            project_dir.join("templates").join("page.html"),
447
-            "<article class=\"page\"><h1>{{ title }}</h1><div>{{ body }}</div></article>",
448
-        )
449
-        .unwrap();
450
-        fs::write(
451
-            project_dir.join("templates").join("post_listing.html"),
452
-            "<ul>{{ post_listing }}</ul>",
453
-        )
454
-        .unwrap();
455
-        fs::write(
456
-            project_dir.join("templates").join("post_listing_item.html"),
457
-            "<li><a href=\"/{{ slug }}\">{{ title }}</a></li>",
458
-        )
459
-        .unwrap();
460
-        fs::write(
461
-            project_dir.join("posts").join("first-post.md"),
462
-            "# First post | 2019-01-01\n\nThis is the first post",
463
-        )
464
-        .unwrap();
465
-        fs::write(
466
-            project_dir.join("pages").join("first-page.md"),
467
-            "# First page\n\nThis is the first page",
468
-        )
469
-        .unwrap();
470
-        fs::write(
471
-            project_dir.join("drafts").join("first-draft.md"),
472
-            "# First draft | 2019-01-01\n\nThis is the first draft",
473
-        )
474
-        .unwrap();
475
-        fs::write(
476
-            project_dir.join("casaubon.toml"),
477
-            "site_name = \"Test Site\"",
478
-        )
479
-        .unwrap();
480
-
481
-        build(true);
482
-
483
-        assert_eq!(
484
-            "<html><head><title>Test Site</title></head><body><ul><li><a href=\"/first-post\">First post</a></li><li><a href=\"/first-draft\">First draft</a></li></ul></body></html>",
485
-            fs::read_to_string(project_dir.join("public").join("index.html")).unwrap().replace("\n", ""),
486
-        );
487
-
488
-        assert_eq!(
489
-            "<html><head><title>First post | Test Site</title></head><body><article><h1>First post</h1><div><p>This is the first post</p></div></article></body></html>",
490
-            fs::read_to_string(
491
-                project_dir
492
-                    .join("public")
493
-                    .join("posts")
494
-                    .join("first-post")
495
-                    .join("index.html")
496
-            ).unwrap()
497
-            .replace("\n", ""),
498
-        );
499
-
500
-        assert_eq!(
501
-            "<html><head><title>First page | Test Site</title></head><body><article class=\"page\"><h1>First page</h1><div><p>This is the first page</p></div></article></body></html>",
502
-            fs::read_to_string(
503
-                project_dir
504
-                    .join("public")
505
-                    .join("first-page")
506
-                    .join("index.html")
507
-            ).unwrap()
508
-            .replace("\n", ""),
509
-        );
510
-
511
-        assert_eq!(
512
-            "<html><head><title>First draft | Test Site</title></head><body><article><h1>First draft</h1><div><p>This is the first draft</p></div></article></body></html>",
513
-            fs::read_to_string(
514
-                project_dir
515
-                    .join("public")
516
-                    .join("posts")
517
-                    .join("first-draft")
518
-                    .join("index.html")
519
-            ).unwrap()
520
-            .replace("\n", ""),
521
-        );
522
-
523
-        fs::remove_dir_all(project_dir).unwrap();
524
-    }
525
-
526
-    #[test]
527
-    fn test_should_rebuild() {
528
-        let cwd = env::current_dir().unwrap();
529
-        assert_eq!(
530
-            false,
531
-            should_rebuild(&cwd, &cwd.join("public").join("index.html"))
532
-        );
533
-        assert_eq!(
534
-            false,
535
-            should_rebuild(&cwd, &cwd.join(".git").join("index.html"))
536
-        );
537
-        assert_eq!(
538
-            true,
539
-            should_rebuild(&cwd, &cwd.join("posts").join("test.md"))
540
-        );
541
-        assert_eq!(
542
-            true,
543
-            should_rebuild(&cwd, &cwd.join("drafts").join("test.md"))
544
-        );
545
-        assert_eq!(
546
-            true,
547
-            should_rebuild(&cwd, &cwd.join("css").join("style.css"))
548
-        );
549
-        assert_eq!(true, should_rebuild(&cwd, &cwd.join("js").join("index.js")));
550
-    }
551
-}

+ 18
- 19
src/entry.rs View File

@@ -38,14 +38,14 @@ impl Entry {
38 38
     }
39 39
 }
40 40
 
41
-pub fn read_entry_dir(cwd: &path::PathBuf) -> Vec<fs::DirEntry> {
41
+pub fn read_entry_dir(cwd: &path::Path) -> Vec<fs::DirEntry> {
42 42
     match fs::read_dir(cwd) {
43 43
         Ok(entries) => entries.into_iter().map(|entry| entry.unwrap()).collect(),
44 44
         Err(err) => panic!(err),
45 45
     }
46 46
 }
47 47
 
48
-pub fn parse_entry(contents: &str, path: path::PathBuf) -> Entry {
48
+pub fn parse_entry(contents: &str, path: &path::Path) -> Entry {
49 49
     lazy_static! {
50 50
         static ref re_with_date: Regex =
51 51
             Regex::new(r"^# (?P<title>.*) \| (?P<date>\d{4}-\d{2}-\d{2})\n\n(?s)(?P<body>.*)")
@@ -96,7 +96,7 @@ pub fn parse_entry(contents: &str, path: path::PathBuf) -> Entry {
96 96
 }
97 97
 
98 98
 pub fn write_entry(
99
-    cwd: &path::PathBuf,
99
+    cwd: &path::Path,
100 100
     layout: &str,
101 101
     post_template: &str,
102 102
     entry: &Entry,
@@ -125,7 +125,7 @@ pub fn write_entry(
125 125
 }
126 126
 
127 127
 pub fn write_entry_listing(
128
-    cwd: &path::PathBuf,
128
+    cwd: &path::Path,
129 129
     layout: &str,
130 130
     post_listing_template: &str,
131 131
     post_item_template: &str,
@@ -249,13 +249,11 @@ mod tests {
249 249
     #[test]
250 250
     fn test_write_entry() {
251 251
         let temp_dir = env::temp_dir();
252
-        let working_dir = temp_dir.join(&Uuid::new_v4().to_string());
253
-        fs::create_dir(&working_dir).unwrap();
254
-        env::set_current_dir(&working_dir).unwrap();
252
+        let project_dir = temp_dir.join(&Uuid::new_v4().to_string());
253
+        fs::create_dir(&project_dir).unwrap();
255 254
 
256
-        let cwd = env::current_dir().unwrap();
257
-        fs::create_dir(cwd.join("public")).unwrap();
258
-        fs::create_dir(cwd.join("public").join("posts")).unwrap();
255
+        fs::create_dir(project_dir.join("public")).unwrap();
256
+        fs::create_dir(project_dir.join("public").join("posts")).unwrap();
259 257
 
260 258
         let layout =
261 259
             "<html><head><title>{{ page_title }}</title></head><body>{{ contents }}</body></html>";
@@ -271,10 +269,11 @@ mod tests {
271 269
             site_name: "Test Site".to_string(),
272 270
         };
273 271
 
274
-        write_entry(&cwd, &layout, &post_template, &post, &config);
272
+        write_entry(&project_dir, &layout, &post_template, &post, &config);
275 273
 
276 274
         let content = fs::read_to_string(
277
-            cwd.join("public")
275
+            project_dir
276
+                .join("public")
278 277
                 .join("posts")
279 278
                 .join("hello-world")
280 279
                 .join("index.html"),
@@ -286,15 +285,15 @@ mod tests {
286 285
 	    content.replace("\n", "")
287 286
 	);
288 287
 
289
-        fs::remove_dir_all(temp_dir.join(&working_dir)).unwrap();
288
+        fs::remove_dir_all(temp_dir.join(&project_dir)).unwrap();
290 289
     }
291 290
 
292 291
     #[test]
293 292
     fn test_write_post_listing() {
294 293
         let temp_dir = env::temp_dir();
295
-        let working_dir = temp_dir.join(&Uuid::new_v4().to_string());
296
-        fs::create_dir(&working_dir).unwrap();
297
-        env::set_current_dir(&working_dir).unwrap();
294
+        let project_dir = temp_dir.join(&Uuid::new_v4().to_string());
295
+        fs::create_dir(&project_dir).unwrap();
296
+        env::set_current_dir(&project_dir).unwrap();
298 297
 
299 298
         let cwd = env::current_dir().unwrap();
300 299
         fs::create_dir(cwd.join("public")).unwrap();
@@ -348,14 +347,14 @@ mod tests {
348 347
                 .replace("\n", ""),
349 348
         );
350 349
 
351
-        fs::remove_dir_all(temp_dir.join(&working_dir)).unwrap();
350
+        fs::remove_dir_all(temp_dir.join(&project_dir)).unwrap();
352 351
     }
353 352
 
354 353
     #[test]
355 354
     fn test_parse_post_entry() {
356 355
         let post = parse_entry(
357 356
             "# Test Title | 2000-01-01\n\nThis is the body",
358
-            path::PathBuf::from("posts/one.md"),
357
+            path::PathBuf::from("posts/one.md").as_path(),
359 358
         );
360 359
 
361 360
         assert_eq!(post.kind, EntryKind::Post);
@@ -369,7 +368,7 @@ mod tests {
369 368
     fn test_parse_page_entry() {
370 369
         let post = parse_entry(
371 370
             "# Test Title\n\nThis is the body",
372
-            path::PathBuf::from("pages/one.md"),
371
+            path::PathBuf::from("pages/one.md").as_path(),
373 372
         );
374 373
 
375 374
         assert_eq!(post.kind, EntryKind::Page);

+ 263
- 0
src/lib.rs View File

@@ -0,0 +1,263 @@
1
+extern crate chrono;
2
+extern crate comrak;
3
+extern crate fs_extra;
4
+#[macro_use]
5
+extern crate lazy_static;
6
+extern crate notify;
7
+extern crate regex;
8
+extern crate toml;
9
+extern crate uuid;
10
+
11
+use std::sync::mpsc::channel;
12
+use std::time::Duration;
13
+use std::{fs, path};
14
+
15
+use fs_extra::dir;
16
+use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
17
+use toml::Value;
18
+
19
+use config::Config;
20
+use entry::{parse_entry, read_entry_dir, write_entry, write_entry_listing, Entry};
21
+
22
+mod config;
23
+mod entry;
24
+mod page;
25
+mod post;
26
+
27
+pub fn build(include_drafts: bool, cwd: &path::Path) {
28
+    let config = match fs::read_to_string(cwd.join("casaubon.toml")) {
29
+        Ok(contents) => match contents.parse::<Value>() {
30
+            Ok(config) => Config {
31
+                site_name: String::from(config["site_name"].as_str().unwrap()),
32
+            },
33
+            Err(_) => panic!("Invalid casaubon.toml"),
34
+        },
35
+        Err(_) => {
36
+            panic!("Can't find casaubon.toml");
37
+        }
38
+    };
39
+
40
+    match fs::read_dir(cwd.join("public")) {
41
+        Ok(_) => {
42
+            fs::remove_dir_all(cwd.join("public")).unwrap();
43
+        }
44
+        Err(_) => {}
45
+    }
46
+
47
+    fs::create_dir(cwd.join("public")).expect("Couldn't create public directory");
48
+    fs::create_dir(cwd.join("public").join("posts")).expect("Couldn't create posts directory");
49
+
50
+    let layout_template = fs::read_to_string(&cwd.join("templates").join("layout.html"))
51
+        .expect("Couldn't find layout template");
52
+    let post_template = fs::read_to_string(cwd.join("templates").join("post.html"))
53
+        .expect("Couldn't find post template");
54
+    let post_listing_template = fs::read_to_string(cwd.join("templates").join("post_listing.html"))
55
+        .expect("Couldn't find post listing item template");
56
+    let post_item_template =
57
+        fs::read_to_string(cwd.join("templates").join("post_listing_item.html"))
58
+            .expect("Couldn't find post listing item template");
59
+    let page_template = fs::read_to_string(cwd.join("templates").join("page.html"))
60
+        .expect("Couldn't find page template");
61
+
62
+    let post_paths = match include_drafts {
63
+        true => {
64
+            let mut posts = read_entry_dir(&cwd.join("posts"));
65
+            posts.append(&mut read_entry_dir(&cwd.join("drafts")));
66
+            posts
67
+        }
68
+        false => read_entry_dir(&cwd.join("posts")),
69
+    };
70
+
71
+    let page_paths = read_entry_dir(&cwd.join("pages"));
72
+
73
+    let mut posts: Vec<Entry> = post_paths
74
+        .into_iter()
75
+        .map(|entry| {
76
+            let path = entry.path();
77
+            let contents = fs::read_to_string(&path).expect("Couldn't read post file");
78
+            parse_entry(&contents, &path)
79
+        })
80
+        .collect::<Vec<Entry>>();
81
+
82
+    posts.sort_by(|a, b| b.date.cmp(&a.date));
83
+
84
+    for post in &posts {
85
+        write_entry(&cwd, &layout_template, &post_template, &post, &config);
86
+    }
87
+
88
+    for entry in page_paths.into_iter() {
89
+        let path = entry.path();
90
+        let contents = fs::read_to_string(&path).expect("Couldn't read page file");
91
+        let page = parse_entry(&contents, &path);
92
+        write_entry(&cwd, &layout_template, &page_template, &page, &config);
93
+    }
94
+
95
+    write_entry_listing(
96
+        &cwd,
97
+        &layout_template,
98
+        &post_listing_template,
99
+        &post_item_template,
100
+        &posts,
101
+        &config,
102
+    );
103
+
104
+    fs_extra::copy_items(
105
+        &vec![cwd.join("css"), cwd.join("js")],
106
+        cwd.join("public"),
107
+        &dir::CopyOptions::new(),
108
+    )
109
+    .expect("Couldn't copy css/js directories");
110
+}
111
+
112
+pub fn new(name: &str, cwd: &path::Path) {
113
+    let project_path = cwd.join(name);
114
+
115
+    fs::create_dir(&project_path).expect(&format!("Couldn't create directory '{}'", &name));
116
+    fs::write(
117
+        project_path.join("casaubon.toml"),
118
+        format!("site_name = \"{}\"", &name),
119
+    )
120
+    .expect("Could not create casaubon.toml");
121
+
122
+    for dir in &[
123
+        "drafts",
124
+        "posts",
125
+        "pages",
126
+        "public",
127
+        "templates",
128
+        "css",
129
+        "js",
130
+    ] {
131
+        fs::create_dir(&project_path.join(&dir))
132
+            .expect(&format!("Couldn't create {} directory", &dir));
133
+    }
134
+
135
+    fs::write(project_path.join("css").join("style.css"), "")
136
+        .expect("Couldn't create css/style.css");
137
+    fs::write(project_path.join("js").join("index.js"), "").expect("Couldn't create js/index.js");
138
+
139
+    let default_layout_template = format!(
140
+        "<html>
141
+  <head>
142
+    <title>{}</title>
143
+  </head>
144
+  <body>
145
+    <h1>{}</h1>
146
+    {{{{ contents }}}}
147
+  </body>
148
+</html>\n",
149
+        name, name
150
+    );
151
+    let default_post_listing_template = format!(
152
+        "<div>
153
+  <h3>Posts</h3>
154
+  <ul>{{{{ post_listing }}}}</ul>
155
+</div>\n"
156
+    );
157
+    let default_post_template = format!(
158
+        "<article>
159
+  <h1>{{{{ title }}}}</h1>
160
+  <div>{{{{ body }}}}</div>
161
+</article>\n"
162
+    );
163
+    let default_page_template = format!(
164
+        "<article>
165
+  <h1>{{{{ title }}}}</h1>
166
+  <div>{{{{ body }}}}</div>
167
+</article>\n"
168
+    );
169
+    let default_post_listing_item_template = format!(
170
+        "<li>
171
+  {{ date }} <a href=\"/posts/{{{{ slug }}}}/\">{{{{ title }}}}</a>
172
+</li>\n"
173
+    );
174
+
175
+    for (filename, contents) in &[
176
+        ("layout", &default_layout_template),
177
+        ("post_listing", &default_post_listing_template),
178
+        ("post", &default_post_template),
179
+        ("page", &default_page_template),
180
+        ("post_listing_item", &default_post_listing_item_template),
181
+    ] {
182
+        fs::write(
183
+            &project_path
184
+                .join("templates")
185
+                .join(format!("{}.html", filename)),
186
+            &contents,
187
+        )
188
+        .expect(&format!("Couldn't write templates/{}.html", filename));
189
+    }
190
+}
191
+
192
+fn should_rebuild(cwd: &path::Path, path: &path::PathBuf) -> bool {
193
+    let path_string = path.to_str().unwrap().to_string();
194
+    let change_is_from_public = path_string.contains(cwd.join("public").to_str().unwrap());
195
+    let change_is_from_git = path_string.contains(cwd.join(".git").to_str().unwrap());
196
+
197
+    !change_is_from_public && !change_is_from_git
198
+}
199
+
200
+pub fn watch(include_drafts: bool, cwd: &path::Path) -> notify::Result<()> {
201
+    let (tx, rx) = channel();
202
+    let mut watcher: RecommendedWatcher = try!(Watcher::new(tx, Duration::from_secs(2)));
203
+    try!(watcher.watch(&cwd, RecursiveMode::Recursive));
204
+    println!("Watching {}", cwd.to_str().unwrap());
205
+
206
+    let handle_event = |path: &path::PathBuf| {
207
+        if should_rebuild(&cwd, &path) {
208
+            println!("Rebuilding");
209
+            build(include_drafts, &cwd);
210
+        }
211
+    };
212
+
213
+    loop {
214
+        match rx.recv() {
215
+            Ok(e) => match e {
216
+                DebouncedEvent::Create(path) => {
217
+                    handle_event(&path);
218
+                }
219
+                DebouncedEvent::Write(path) => {
220
+                    handle_event(&path);
221
+                }
222
+                _ => {}
223
+            },
224
+            Err(e) => println!("watch error: {:?}", e),
225
+        }
226
+    }
227
+}
228
+
229
+#[cfg(test)]
230
+mod tests {
231
+    #[allow(unused_imports)]
232
+    use super::*;
233
+    #[allow(unused_imports)]
234
+    use uuid::Uuid;
235
+
236
+    use std::env;
237
+
238
+    #[test]
239
+    fn test_should_rebuild() {
240
+        let cwd = env::current_dir().unwrap();
241
+        assert_eq!(
242
+            false,
243
+            should_rebuild(&cwd, &cwd.join("public").join("index.html"))
244
+        );
245
+        assert_eq!(
246
+            false,
247
+            should_rebuild(&cwd, &cwd.join(".git").join("index.html"))
248
+        );
249
+        assert_eq!(
250
+            true,
251
+            should_rebuild(&cwd, &cwd.join("posts").join("test.md"))
252
+        );
253
+        assert_eq!(
254
+            true,
255
+            should_rebuild(&cwd, &cwd.join("drafts").join("test.md"))
256
+        );
257
+        assert_eq!(
258
+            true,
259
+            should_rebuild(&cwd, &cwd.join("css").join("style.css"))
260
+        );
261
+        assert_eq!(true, should_rebuild(&cwd, &cwd.join("js").join("index.js")));
262
+    }
263
+}

+ 18
- 20
src/main.rs View File

@@ -1,23 +1,8 @@
1
-extern crate chrono;
2 1
 extern crate clap;
3
-extern crate comrak;
4
-extern crate fs_extra;
5
-#[macro_use]
6
-extern crate lazy_static;
7
-extern crate notify;
8
-extern crate regex;
9
-extern crate toml;
10
-extern crate uuid;
11 2
 
12 3
 use clap::{App, Arg};
13 4
 
14
-use commands::{build, new, watch};
15
-
16
-mod commands;
17
-mod config;
18
-mod entry;
19
-mod page;
20
-mod post;
5
+use std::env;
21 6
 
22 7
 fn main() {
23 8
     let matches = App::new("casaubon")
@@ -46,11 +31,24 @@ fn main() {
46 31
 
47 32
     let command = matches.value_of("command").unwrap();
48 33
     if command == "build" {
49
-        build(include_drafts);
34
+        casaubon::build(
35
+            include_drafts,
36
+            &env::current_dir().expect("Can't read current directory"),
37
+        );
50 38
     } else if command == "new" {
51
-        new(&matches.value_of("name").unwrap());
39
+        casaubon::new(
40
+            &matches.value_of("name").unwrap(),
41
+            &env::current_dir().expect("Can't read current directory"),
42
+        );
52 43
     } else if command == "watch" {
53
-        build(include_drafts);
54
-        watch(include_drafts).expect("Error while watching posts directory");
44
+        casaubon::build(
45
+            include_drafts,
46
+            &env::current_dir().expect("Can't read current directory"),
47
+        );
48
+        casaubon::watch(
49
+            include_drafts,
50
+            &env::current_dir().expect("Can't read current directory"),
51
+        )
52
+        .expect("Error while watching posts directory");
55 53
     }
56 54
 }

+ 0
- 3
test View File

@@ -1,3 +0,0 @@
1
-#!/usr/bin/env sh
2
-
3
-cargo test -- --test-threads=1

+ 303
- 0
tests/integration_test.rs View File

@@ -0,0 +1,303 @@
1
+extern crate chrono;
2
+extern crate tempfile;
3
+extern crate uuid;
4
+
5
+use uuid::Uuid;
6
+
7
+use std::{env, fs};
8
+
9
+#[test]
10
+fn test_build() {
11
+    let uuid = Uuid::new_v4().to_string();
12
+    let temp_dir = tempfile::tempdir().unwrap();
13
+    let project_dir = temp_dir.path().join(&uuid);
14
+
15
+    fs::create_dir(&project_dir).unwrap();
16
+    fs::create_dir(&project_dir.join("css")).unwrap();
17
+    fs::create_dir(&project_dir.join("drafts")).unwrap();
18
+    fs::create_dir(&project_dir.join("js")).unwrap();
19
+    fs::create_dir(&project_dir.join("pages")).unwrap();
20
+    fs::create_dir(&project_dir.join("posts")).unwrap();
21
+    fs::create_dir(&project_dir.join("public")).unwrap();
22
+    fs::create_dir(&project_dir.join("public").join("posts")).unwrap();
23
+    fs::create_dir(&project_dir.join("templates")).unwrap();
24
+
25
+    fs::write(
26
+        project_dir.join("css").join("style.css"),
27
+        "body { background: blue; }",
28
+    )
29
+    .unwrap();
30
+    fs::write(
31
+        project_dir.join("js").join("index.js"),
32
+        "window.onload = function () { alert() }",
33
+    )
34
+    .unwrap();
35
+    fs::write(
36
+        project_dir.join("templates").join("layout.html"),
37
+        "<html><head><title>{{ page_title }}</title></head><body>{{ contents }}</body></html>",
38
+    )
39
+    .unwrap();
40
+    fs::write(
41
+        project_dir.join("templates").join("post.html"),
42
+        "<article><h1>{{ title }}</h1><div>{{ body }}</div></article>",
43
+    )
44
+    .unwrap();
45
+    fs::write(
46
+        project_dir.join("templates").join("page.html"),
47
+        "<article class=\"page\"><h1>{{ title }}</h1><div>{{ body }}</div></article>",
48
+    )
49
+    .unwrap();
50
+    fs::write(
51
+        project_dir.join("templates").join("post_listing.html"),
52
+        "<ul>{{ post_listing }}</ul>",
53
+    )
54
+    .unwrap();
55
+    fs::write(
56
+        project_dir.join("templates").join("post_listing_item.html"),
57
+        "<li><a href=\"/{{ slug }}\">{{ title }}</a></li>",
58
+    )
59
+    .unwrap();
60
+    fs::write(
61
+        project_dir.join("posts").join("first-post.md"),
62
+        "# First post | 2019-01-01\n\nThis is the first post\n\nIt has multiple paragraphs",
63
+    )
64
+    .unwrap();
65
+    fs::write(
66
+        project_dir.join("pages").join("first-page.md"),
67
+        "# First page\n\nThis is the first page\n\nIt has multiple paragraphs",
68
+    )
69
+    .unwrap();
70
+    fs::write(
71
+        project_dir.join("casaubon.toml"),
72
+        "site_name = \"Test Site\"",
73
+    )
74
+    .unwrap();
75
+
76
+    casaubon::build(false, &project_dir);
77
+
78
+    assert_eq!(
79
+        "<html><head><title>Test Site</title></head><body><ul><li><a href=\"/fir\
80
+         st-post\">First post</a></li></ul></body></html>",
81
+        fs::read_to_string(project_dir.join("public").join("index.html")).unwrap(),
82
+    );
83
+
84
+    assert_eq!(
85
+        "<html><head><title>First post | Test Site</title></head><body><article><h1>First pos\
86
+         t</h1><div><p>This is the first post</p><p>It has multiple paragra\
87
+         phs</p></div></article></body></html>",
88
+        fs::read_to_string(
89
+            project_dir
90
+                .join("public")
91
+                .join("posts")
92
+                .join("first-post")
93
+                .join("index.html")
94
+        )
95
+        .unwrap()
96
+        .replace("\n", ""),
97
+    );
98
+
99
+    assert_eq!(
100
+        "<html><head><title>First page | Test Site</title></head><body><article class=\"page\"><h1>First pag\
101
+         e</h1><div><p>This is the first page</p><p>It has multiple paragra\
102
+         phs</p></div></article></body></html>",
103
+        fs::read_to_string(
104
+            project_dir
105
+                .join("public")
106
+                .join("first-page")
107
+                .join("index.html")
108
+        )
109
+        .unwrap()
110
+        .replace("\n", ""),
111
+    );
112
+
113
+    assert_eq!(
114
+        "body { background: blue; }",
115
+        fs::read_to_string(project_dir.join("public").join("css").join("style.css")).unwrap()
116
+    );
117
+
118
+    assert_eq!(
119
+        "window.onload = function () { alert() }",
120
+        fs::read_to_string(project_dir.join("public").join("js").join("index.js")).unwrap()
121
+    );
122
+}
123
+
124
+#[test]
125
+fn test_build_drafts() {
126
+    let uuid = Uuid::new_v4().to_string();
127
+    let temp_dir = tempfile::tempdir().unwrap();
128
+    let project_dir = temp_dir.path().join(&uuid);
129
+
130
+    fs::create_dir(&project_dir).unwrap();
131
+    env::set_current_dir(&project_dir).unwrap();
132
+
133
+    fs::create_dir(&project_dir.join("css")).unwrap();
134
+    fs::create_dir(&project_dir.join("drafts")).unwrap();
135
+    fs::create_dir(&project_dir.join("js")).unwrap();
136
+    fs::create_dir(&project_dir.join("pages")).unwrap();
137
+    fs::create_dir(&project_dir.join("posts")).unwrap();
138
+    fs::create_dir(&project_dir.join("public")).unwrap();
139
+    fs::create_dir(&project_dir.join("public").join("posts")).unwrap();
140
+    fs::create_dir(&project_dir.join("templates")).unwrap();
141
+
142
+    fs::write(
143
+        project_dir.join("css").join("style.css"),
144
+        "body { background: blue; }",
145
+    )
146
+    .unwrap();
147
+    fs::write(
148
+        project_dir.join("js").join("index.js"),
149
+        "window.onload = function () { alert() }",
150
+    )
151
+    .unwrap();
152
+    fs::write(
153
+        project_dir.join("templates").join("layout.html"),
154
+        "<html><head><title>{{ page_title }}</title></head><body>{{ contents }}</body></html>",
155
+    )
156
+    .unwrap();
157
+    fs::write(
158
+        project_dir.join("templates").join("post.html"),
159
+        "<article><h1>{{ title }}</h1><div>{{ body }}</div></article>",
160
+    )
161
+    .unwrap();
162
+    fs::write(
163
+        project_dir.join("templates").join("page.html"),
164
+        "<article class=\"page\"><h1>{{ title }}</h1><div>{{ body }}</div></article>",
165
+    )
166
+    .unwrap();
167
+    fs::write(
168
+        project_dir.join("templates").join("post_listing.html"),
169
+        "<ul>{{ post_listing }}</ul>",
170
+    )
171
+    .unwrap();
172
+    fs::write(
173
+        project_dir.join("templates").join("post_listing_item.html"),
174
+        "<li><a href=\"/{{ slug }}\">{{ title }}</a></li>",
175
+    )
176
+    .unwrap();
177
+    fs::write(
178
+        project_dir.join("posts").join("first-post.md"),
179
+        "# First post | 2019-01-01\n\nThis is the first post",
180
+    )
181
+    .unwrap();
182
+    fs::write(
183
+        project_dir.join("pages").join("first-page.md"),
184
+        "# First page\n\nThis is the first page",
185
+    )
186
+    .unwrap();
187
+    fs::write(
188
+        project_dir.join("drafts").join("first-draft.md"),
189
+        "# First draft | 2019-01-01\n\nThis is the first draft",
190
+    )
191
+    .unwrap();
192
+    fs::write(
193
+        project_dir.join("casaubon.toml"),
194
+        "site_name = \"Test Site\"",
195
+    )
196
+    .unwrap();
197
+
198
+    casaubon::build(true, &project_dir);
199
+
200
+    assert_eq!(
201
+        "<html><head><title>Test Site</title></head><body><ul><li><a href=\"/first-post\">First post</a></li><li><a href=\"/first-draft\">First draft</a></li></ul></body></html>",
202
+        fs::read_to_string(project_dir.join("public").join("index.html")).unwrap().replace("\n", ""),
203
+    );
204
+
205
+    assert_eq!(
206
+        "<html><head><title>First post | Test Site</title></head><body><article><h1>First post</h1><div><p>This is the first post</p></div></article></body></html>",
207
+        fs::read_to_string(
208
+            project_dir
209
+                .join("public")
210
+                .join("posts")
211
+                .join("first-post")
212
+                .join("index.html")
213
+        ).unwrap()
214
+        .replace("\n", ""),
215
+    );
216
+
217
+    assert_eq!(
218
+        "<html><head><title>First page | Test Site</title></head><body><article class=\"page\"><h1>First page</h1><div><p>This is the first page</p></div></article></body></html>",
219
+        fs::read_to_string(
220
+            project_dir
221
+                .join("public")
222
+                .join("first-page")
223
+                .join("index.html")
224
+        ).unwrap()
225
+        .replace("\n", ""),
226
+    );
227
+
228
+    assert_eq!(
229
+        "<html><head><title>First draft | Test Site</title></head><body><article><h1>First draft</h1><div><p>This is the first draft</p></div></article></body></html>",
230
+        fs::read_to_string(
231
+            project_dir
232
+                .join("public")
233
+                .join("posts")
234
+                .join("first-draft")
235
+                .join("index.html")
236
+        ).unwrap()
237
+        .replace("\n", ""),
238
+    );
239
+}
240
+
241
+#[test]
242
+fn test_new() {
243
+    let uuid = Uuid::new_v4().to_string();
244
+    let temp_dir = tempfile::tempdir().unwrap();
245
+    let project_dir = temp_dir.path().join(&uuid);
246
+
247
+    casaubon::new(&uuid, &temp_dir.path());
248
+
249
+    for dir in &["public", "pages", "posts", "templates"] {
250
+        fs::read_dir(&project_dir.join(dir)).unwrap();
251
+    }
252
+
253
+    assert_eq!(
254
+        format!(
255
+            "<html><head><title>{}</title></head><body><h1>{}</h1>{{{{ contents }}}}</body></html>",
256
+            uuid, uuid
257
+        ),
258
+        fs::read_to_string(&project_dir.join("templates").join("layout.html"))
259
+            .unwrap()
260
+            .replace("\n", "")
261
+            .replace("  ", "")
262
+    );
263
+    assert_eq!(
264
+        format!("<div><h3>Posts</h3><ul>{{{{ post_listing }}}}</ul></div>"),
265
+        fs::read_to_string(&project_dir.join("templates").join("post_listing.html"))
266
+            .unwrap()
267
+            .replace("\n", "")
268
+            .replace("  ", "")
269
+    );
270
+    assert_eq!(
271
+        format!("<li>{{ date }} <a href=\"/posts/{{{{ slug }}}}/\">{{{{ title }}}}</a></li>"),
272
+        fs::read_to_string(&project_dir.join("templates").join("post_listing_item.html"))
273
+            .unwrap()
274
+            .replace("\n", "")
275
+            .replace("  ", "")
276
+    );
277
+    assert_eq!(
278
+        format!("<article><h1>{{{{ title }}}}</h1><div>{{{{ body }}}}</div></article>"),
279
+        fs::read_to_string(&project_dir.join("templates").join("post.html"))
280
+            .unwrap()
281
+            .replace("\n", "")
282
+            .replace("  ", "")
283
+    );
284
+    assert_eq!(
285
+        format!("<article><h1>{{{{ title }}}}</h1><div>{{{{ body }}}}</div></article>"),
286
+        fs::read_to_string(&project_dir.join("templates").join("page.html"))
287
+            .unwrap()
288
+            .replace("\n", "")
289
+            .replace("  ", "")
290
+    );
291
+    assert_eq!(
292
+        "",
293
+        fs::read_to_string(&project_dir.join("css").join("style.css")).unwrap()
294
+    );
295
+    assert_eq!(
296
+        "",
297
+        fs::read_to_string(&project_dir.join("js").join("index.js")).unwrap()
298
+    );
299
+    assert_eq!(
300
+        format!("site_name = \"{}\"", &uuid),
301
+        fs::read_to_string(&project_dir.join("casaubon.toml")).unwrap()
302
+    );
303
+}

Loading…
Cancel
Save