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
use super::LIBRARY_NAME;
use crate::{
code::{self, CrateType, ModsMap, StaticFiles},
linking,
};
use std::{
fs,
io::{self, Write},
path::Path,
};
pub fn build_compile_dir<P>(
compile_dir: P,
mods_map: &ModsMap,
linking_config: &linking::LinkingConfiguration,
static_files: &StaticFiles,
) -> io::Result<()>
where
P: AsRef<Path>,
{
let compile_dir = compile_dir.as_ref();
let crates = mods_map
.iter()
.flat_map(|kvp| kvp.1.crates.iter())
.chain(static_files.iter().flat_map(|x| x.crates.iter()));
let crates = dedup_crates(crates);
create_file_and_dir(compile_dir.join("Cargo.toml"))?
.write_all(cargotoml_contents(LIBRARY_NAME, crates.into_iter()).as_bytes())?;
let (src_code, _map) = code::construct_source_code(mods_map, linking_config, static_files);
create_file_and_dir(compile_dir.join("src/lib.rs"))?.write_all(src_code.as_bytes())?;
Ok(())
}
fn dedup_crates<'a>(crates: impl Iterator<Item = &'a CrateType>) -> Vec<&'a CrateType> {
let mut crates: Vec<&CrateType> = crates.collect();
crates.sort_by_key(|x| &x.cargo_name);
crates.dedup_by_key(|x| &x.cargo_name);
crates
}
fn create_file_and_dir<P: AsRef<Path>>(file: P) -> io::Result<fs::File> {
let file = file.as_ref();
debug!("trying to create file: {}", file.display());
if let Some(parent) = file.parent() {
fs::create_dir_all(parent)?;
}
fs::File::create(file)
}
fn cargotoml_contents<'a, I: Iterator<Item = &'a CrateType>>(lib_name: &str, crates: I) -> String {
format!(
r#"[package]
name = "{lib_name}"
version = "0.1.0"
edition = "2018"
[lib]
name = "{lib_name}"
crate-type = [ "cdylib" ]
path = "src/lib.rs"
[dependencies]
kserd = {{ version = "0.3", default-features = false, features = [ "format" ] }}
{crates}
"#,
lib_name = lib_name,
crates = crates
.map(|c| format!(r#"{} = "*""#, c.cargo_name))
.collect::<Vec<_>>()
.join("\n")
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_file_and_dir_test() {
use std::path::Path;
let p = Path::new("foo.txt");
assert!(!p.exists());
create_file_and_dir(&"foo.txt").unwrap();
assert!(p.exists());
fs::remove_file(p).unwrap();
assert!(!p.exists());
let p = Path::new("target/testing/foo");
assert!(!p.exists());
create_file_and_dir(&p).unwrap();
assert!(p.exists());
fs::remove_file(p).unwrap();
assert!(!p.exists());
}
#[test]
fn test_dedup_crates() {
let crates = vec![
CrateType::parse_str("extern crate rand;").unwrap(),
CrateType::parse_str("extern crate rand as rnd;").unwrap(),
CrateType::parse_str("extern crate third;").unwrap(),
];
let crates = dedup_crates(crates.iter());
let v: Vec<_> = crates.iter().map(|x| &x.cargo_name).collect();
assert_eq!(&v, &["rand", "third"]);
}
}