-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathbuild.rs
136 lines (125 loc) · 4.45 KB
/
build.rs
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
129
130
131
132
133
134
135
136
// Copyright 2019-2022 Manta Network.
// This file is part of manta-sdk.
//
// manta-sdk is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// manta-sdk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with manta-sdk. If not, see <http://www.gnu.org/licenses/>.
//! Manta SDK Build Script
use anyhow::{anyhow, bail, ensure, Result};
use hex::FromHex;
use std::{
collections::HashMap,
env,
fs::{self, OpenOptions},
io::{BufRead, BufReader},
path::{Path, PathBuf},
};
/// Returns the parent of `path` which should exist relative to `OUT_DIR`.
#[inline]
fn parent(path: &Path) -> Result<&Path> {
path.parent()
.ok_or_else(|| anyhow!("The parent should be in the subtree of the `OUT_DIR` directory."))
}
/// Checksum
type Checksum = [u8; 32];
/// Checksum Map
type ChecksumMap = HashMap<PathBuf, Checksum>;
/// Parses the checkfile at `path` producing a [`ChecksumMap`] for all the files in the data
/// directory.
#[inline]
fn parse_checkfile<P>(path: P) -> Result<ChecksumMap>
where
P: AsRef<Path>,
{
let file = OpenOptions::new().read(true).open(path)?;
let mut checksums = ChecksumMap::new();
for line in BufReader::new(file).lines() {
let line = line?;
let mut iter = line.split(" ");
match (iter.next(), iter.next(), iter.next()) {
(Some(checksum), Some(path), None) => {
checksums.insert(path.into(), Checksum::from_hex(checksum)?);
}
_ => bail!("Invalid checkfile line: {:?}", line),
}
}
Ok(checksums)
}
/// Gets the checksum from the `checksums` map for `path` returning an error if it was not found.
#[inline]
fn get_checksum<P>(checksums: &ChecksumMap, path: P) -> Result<Checksum>
where
P: AsRef<Path>,
{
let path = path.as_ref();
checksums
.get(path)
.ok_or_else(|| anyhow!("Unable to get checksum for path: {:?}", path))
.map(move |c| *c)
}
/// Writes the `checksum` to `path` returning an error if the write failed.
#[inline]
fn write_checksum<P>(path: P, checksum: Checksum) -> Result<()>
where
P: AsRef<Path>,
{
let path = path.as_ref();
fs::create_dir_all(parent(path)?)?;
Ok(fs::write(path.with_extension("checksum"), checksum)?)
}
/// Compiles a raw binary file by checking its BLAKE3 checksum with the `checksums` map and copying
/// the data and checksum to the `out_dir`.
#[inline]
fn compile_dat(source: &Path, out_dir: &Path, checksums: &ChecksumMap) -> Result<()> {
let checksum = get_checksum(checksums, source)?;
let data = fs::read(source)?;
let found_checksum = blake3::hash(&data);
ensure!(
found_checksum == checksum,
"Checksum did not match for {:?}. Expected: {:?}, Found: {:?}. Data: {:?}",
source,
hex::encode(checksum),
found_checksum,
data,
);
let target = out_dir.join(source);
write_checksum(&target, checksum)?;
fs::copy(source, target)?;
Ok(())
}
/// Compiles a Git LFS file by writing its checksum to the `out_dir`.
#[inline]
fn compile_lfs(source: &Path, out_dir: &Path, checksums: &ChecksumMap) -> Result<()> {
write_checksum(out_dir.join(source), get_checksum(checksums, source)?)
}
/// Loads all the files from `data` into the `OUT_DIR` directory for inclusion into the library.
#[inline]
fn main() -> Result<()> {
println!("cargo:rerun-if-changed=data");
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
let checksums = parse_checkfile("data.checkfile")?;
for file in walkdir::WalkDir::new("data") {
let file = file?;
let path = file.path();
if !path.is_dir() {
match path.extension() {
Some(extension) => match extension.to_str() {
Some("dat") => compile_dat(path, &out_dir, &checksums)?,
Some("lfs") => compile_lfs(path, &out_dir, &checksums)?,
_ => bail!("Unsupported data file extension."),
},
_ => bail!("All data files must have an extension."),
}
}
}
Ok(())
}