-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathlib.rs
More file actions
127 lines (107 loc) · 3.31 KB
/
Copy pathlib.rs
File metadata and controls
127 lines (107 loc) · 3.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#[macro_use]
extern crate lazy_static;
extern crate serde_json;
use gherkin_rust::{Feature};
use uncode_core::StoryModel;
use walkdir::{WalkDir, DirEntry};
use std::fs;
use std::path::Path;
use regex::{Regex};
use std::time::{SystemTime};
lazy_static! {
static ref STATUS_REGEX: Regex = Regex::new(r"#\sstatus:\s(?P<status>.*)").unwrap();
static ref STORY_ID: Regex = Regex::new(r"(?P<story_id>\d{1,4})-(.*).feature").unwrap();
}
pub fn parse(content: &str, path: &Path) -> StoryModel {
let mut story = StoryModel::default();
story.path = format!("{}", path.display());
let mut status = "".to_string();
for line in content.lines().into_iter() {
if let Some(caps) = STATUS_REGEX.captures(line) {
status = caps["status"].to_string();
}
}
let result = Feature::parse(content, Default::default());
match result {
Ok(feature) => {
story.title = feature.name;
story.status = status;
story.description = feature.description.unwrap_or("".to_string());
}
Err(err) => {
println!("error: {:?}", err);
}
}
story
}
pub fn parse_dir<P: AsRef<Path>>(path: P) -> Vec<StoryModel> {
fn is_story(entry: &DirEntry) -> bool {
if entry.file_type().is_dir() {
return true;
}
entry.file_name()
.to_str()
.map(|s| s.ends_with(".feature"))
.unwrap_or(false)
}
let walker = WalkDir::new(path).into_iter();
let mut stories = vec![];
for entry in walker.filter_entry(|e| is_story(e)) {
if let Ok(dir) = entry {
if dir.file_type().is_file() {
let model = build_story(dir);
stories.push(model);
}
}
};
stories
}
fn build_story(file_entry: DirEntry) -> StoryModel {
let metadata = file_entry.metadata().expect("fail to get file metadata");
let file_path = file_entry.path();
let content = fs::read_to_string(file_path).expect("error to load file");
let mut model = parse(&*content, file_path);
if let Ok(time) = metadata.created() {
if let Ok(unix) = time.duration_since(SystemTime::UNIX_EPOCH) {
model.created = unix.as_secs();
}
}
if let Ok(time) = metadata.modified() {
if let Ok(unix) = time.duration_since(SystemTime::UNIX_EPOCH) {
model.modified = unix.as_secs();
}
}
if let Some(caps) = STORY_ID.captures(file_entry.file_name().to_str().expect("not a correct file name")) {
model.id = caps["story_id"].to_string();
}
model
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use crate::parse_dir;
#[test]
fn should_parse_demo_project_story() {
let d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let path = format!("{}", d.join("story").display());
let stories = parse_dir(path);
assert_eq!(1, stories.len());
assert_eq!("第一个用户故事", stories[0].title);
}
#[test]
fn should_parse_status() {
let d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let path = format!("{}", d.join("story").display());
let stories = parse_dir(path);
assert_eq!("done", stories[0].status);
}
#[test]
fn should_parse_file_info() {
let d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let path = format!("{}", d.join("story").display());
let stories = parse_dir(path);
assert_eq!(1619788569, stories[0].created);
assert_eq!("001", stories[0].id);
assert!(stories[0].path.contains("001-first-story.feature"))
}
}