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
128
use failure::ResultExt;
use std::fs;
use std::io::{BufRead, BufReader};
use std::path::Path;
pub enum SourceFileType {
Rs,
Rscript,
}
pub struct SourceFile {
pub src: String,
pub file_type: SourceFileType,
pub file_name: String,
pub crates: Vec<CrateType>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct CrateType {
pub src_line: String,
pub cargo_name: String,
}
impl SourceFile {
pub fn load<P: AsRef<Path>>(file_path: &P) -> Result<Self, String> {
let file_path = file_path.as_ref();
let (filename, filetype) = {
let f = file_path
.file_name()
.map_or("papyrus-script".to_string(), |i| {
let s = String::from(i.to_string_lossy());
s.split('.')
.nth(0)
.expect("should have one element")
.to_string()
});
match file_path.extension() {
Some(e) => {
if e == "rs" {
Ok((f, SourceFileType::Rs))
} else if e == "rscript" {
Ok((f, SourceFileType::Rscript))
} else {
Err("expecting file type *.rs or *.rscript".to_string())
}
}
None => Err("expecting file type *.rs or *.rscript".to_string()),
}
}?;
let src = fs::read(&file_path)
.context(format!("failed to read {:?}", file_path))
.map_err(|e| e.to_string())?;
let (src, crates) = {
let reader = BufReader::new(&src[..]);
let mut contents = String::new();
let mut crates = Vec::new();
for line in reader.lines() {
let line = line.expect("should be something");
if line.contains("extern crate ") {
match line
.split(" ")
.nth(2)
.map(|s| s.replace(";", "").replace("_", "-"))
{
Some(s) => crates.push(CrateType {
src_line: line,
cargo_name: s,
}),
None => (),
}
} else {
contents.push_str(&line);
contents.push('\n');
}
}
(contents, crates)
};
Ok(SourceFile {
src: src,
file_type: filetype,
file_name: filename,
crates: crates,
})
}
}
impl CrateType {
pub fn parse_str(string: &str) -> Result<Self, &'static str> {
let line = match string.trim().split("\n").nth(0) {
Some(s) => Ok(s),
None => Err("string should have one line"),
}?;
if line.contains("extern crate ") {
match line
.split(" ")
.nth(2)
.map(|s| s.replace(";", "").replace("_", "-"))
{
Some(s) => Ok(CrateType {
src_line: line.to_string(),
cargo_name: s,
}),
None => Err("no crate name"),
}
} else {
Err("line needs `extern crate `")
}
}
}