Skip to content

Commit e443800

Browse files
committed
feat(build): build_hash
Prevents constant rebuilding
1 parent 869e841 commit e443800

File tree

2 files changed

+96
-6
lines changed

2 files changed

+96
-6
lines changed

src/build/hash.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use anyhow::{Context, Result};
2+
use std::fs;
3+
use std::io::Write;
4+
use std::path::Path;
5+
6+
use super::BuildManifest;
7+
use crate::repo::{get_package, read_manifest};
8+
9+
/// Get the `build_hash` of a `build_manifest`
10+
/// Requires all dependencies to be built and in the Repository beforehand.
11+
///
12+
/// # Errors
13+
///
14+
/// - Scripts do not exist
15+
/// - Invalid build manifest
16+
pub fn calc_build_hash(build_manifest_path: &Path, repo_path: &Path) -> Result<String> {
17+
let build_manifest_path = build_manifest_path.canonicalize().with_context(
18+
|| "could not canoncicalize build manifest path. Does the build manifest exist?",
19+
)?;
20+
let build_manifest_raw = fs::read_to_string(build_manifest_path)?;
21+
let build_manifest: BuildManifest = serde_yaml::from_str(&build_manifest_raw)?;
22+
23+
let repo_manifest = read_manifest(repo_path)?;
24+
25+
let mut hash = blake3::Hasher::new();
26+
27+
hash.write_all(build_manifest_raw.as_bytes())?;
28+
29+
// Hash the `includes`
30+
if let Some(deps) = build_manifest.include {
31+
for dep in deps {
32+
let package = get_package(&repo_manifest, &dep)?;
33+
hash.write_all(package.build_hash.as_bytes())?;
34+
}
35+
}
36+
37+
// Hash the `sdks`
38+
if let Some(deps) = build_manifest.sdks {
39+
for dep in deps {
40+
let package = get_package(&repo_manifest, &dep)?;
41+
hash.write_all(package.build_hash.as_bytes())?;
42+
}
43+
}
44+
45+
// Hash the `build_script`
46+
if let Some(build_script) = build_manifest.build_script {
47+
let script = fs::read_to_string(build_script)?;
48+
hash.write_all(script.as_bytes())?;
49+
}
50+
51+
// Hash the `post_script`
52+
if let Some(post_script) = build_manifest.post_script {
53+
let script = fs::read_to_string(post_script)?;
54+
hash.write_all(script.as_bytes())?;
55+
}
56+
57+
Ok(hash.finalize().to_string())
58+
}

src/build/mod.rs

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
pub mod bundle;
2+
pub mod hash;
23
mod sources;
34

45
use anyhow::{Context, Result, bail};
@@ -11,10 +12,11 @@ use std::{
1112
use temp_dir::TempDir;
1213

1314
use crate::{
14-
build::sources::get_sources,
1515
chunks::{load_tree, save_tree},
1616
repo::{self, Metadata, PackageManifest, get_package, insert_package, read_manifest},
1717
};
18+
use hash::calc_build_hash;
19+
use sources::get_sources;
1820

1921
#[derive(serde::Deserialize, serde::Serialize, Clone, Hash)]
2022
struct BuildManifest {
@@ -71,6 +73,38 @@ pub async fn build(
7173
repo_path: &Path,
7274
config_path: Option<&Path>,
7375
chunk_store_path: &Path,
76+
) -> Result<PackageManifest> {
77+
let repo = read_manifest(repo_path)?;
78+
let build_manifest: BuildManifest =
79+
serde_yaml::from_str(&fs::read_to_string(build_manifest_path)?)?;
80+
81+
if let Ok(package) = get_package(&repo, &build_manifest.id) {
82+
let next_build_hash = calc_build_hash(build_manifest_path, repo_path)?;
83+
if package.build_hash == next_build_hash {
84+
return Ok(package);
85+
}
86+
}
87+
88+
force_build(
89+
build_manifest_path,
90+
repo_path,
91+
config_path,
92+
chunk_store_path,
93+
)
94+
.await
95+
}
96+
97+
/// Builds and inserts a package into a Repository from a `build_manifest`
98+
///
99+
/// # Errors
100+
///
101+
/// - Filesystem (Out of Space, Permissions)
102+
/// - Build Script Failure
103+
pub async fn force_build(
104+
build_manifest_path: &Path,
105+
repo_path: &Path,
106+
config_path: Option<&Path>,
107+
chunk_store_path: &Path,
74108
) -> Result<PackageManifest> {
75109
let build_dir = TempDir::new()?;
76110
let build_manifest_path = &build_manifest_path.canonicalize()?;
@@ -114,14 +148,13 @@ pub async fn build(
114148
}
115149

116150
if let Some(script) = build_manifest.build_script {
117-
run_script(build_dir.path(), build_manifest_path, &script)
118-
.with_context(|| "build_script")?;
151+
run_script(build_dir.path(), search_path, &script).with_context(|| "build_script")?;
119152
}
120153

121154
let out_dir = build_dir.path().join(&build_manifest.directory);
122155

123156
if let Some(script) = build_manifest.post_script {
124-
run_script(&out_dir, build_manifest_path, &script).with_context(|| "post_script")?;
157+
run_script(&out_dir, search_path, &script).with_context(|| "post_script")?;
125158
}
126159

127160
let mut included_chunks = Vec::new();
@@ -148,8 +181,7 @@ pub async fn build(
148181
metadata: build_manifest.metadata,
149182
chunks: included_chunks,
150183
env: None,
151-
// TODO!
152-
build_hash: "TODO".to_string(),
184+
build_hash: calc_build_hash(build_manifest_path, repo_path)?,
153185
};
154186

155187
if !envs.is_empty() {

0 commit comments

Comments
 (0)