Skip to content

Commit 02dfee2

Browse files
committed
Filter stdlib, update manifests
1 parent 41c16a2 commit 02dfee2

File tree

8 files changed

+140
-14
lines changed

8 files changed

+140
-14
lines changed

crates/pcb-layout/tests/resources/multi_pads/pcb.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ members = [
88
"boards/*",
99
"graphics/*",
1010
]
11+
12+
[dependencies]
13+
"gitlab.com/kicad/libraries/kicad-footprints" = "9.0.3"

crates/pcb-layout/tests/resources/netclass_assignment/pcb.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ members = [
88
"boards/*",
99
"graphics/*",
1010
]
11+
12+
[dependencies]
13+
"gitlab.com/kicad/libraries/kicad-footprints" = "9.0.3"

crates/pcb-layout/tests/resources/not_connected_single_pin_multi_pad/pcb.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ members = [
88
"boards/*",
99
"graphics/*",
1010
]
11+
12+
[dependencies]
13+
"gitlab.com/kicad/libraries/kicad-footprints" = "9.0.3"

crates/pcb-zen-core/src/embedded_stdlib.rs

Lines changed: 123 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,44 @@
11
use anyhow::{Context, Result};
2+
use globset::{Glob, GlobSet, GlobSetBuilder};
23
use include_dir::{Dir, include_dir};
4+
use once_cell::sync::Lazy;
35
use std::fs;
4-
use std::path::Path;
6+
use std::path::{Path, PathBuf};
57

68
#[cfg(feature = "native")]
79
use once_cell::sync::OnceCell;
10+
#[cfg(feature = "native")]
11+
use walkdir::WalkDir;
812

913
/// Embedded stdlib tree sourced directly from repository stdlib/.
1014
static EMBEDDED_STDLIB: Dir = include_dir!("$CARGO_MANIFEST_DIR/../../stdlib");
15+
static EXCLUDED_STDLIB_PATHS: Lazy<GlobSet> = Lazy::new(|| {
16+
let mut builder = GlobSetBuilder::new();
17+
for pattern in [
18+
".gitignore",
19+
"**/.gitignore",
20+
"**/*.log",
21+
"**/*layout.json",
22+
"**/test",
23+
"**/test/**",
24+
] {
25+
builder.add(Glob::new(pattern).expect("valid stdlib exclude glob"));
26+
}
27+
builder
28+
.build()
29+
.expect("valid stdlib exclude globset configuration")
30+
});
1131

1232
pub fn embedded_stdlib_dir() -> &'static Dir<'static> {
1333
&EMBEDDED_STDLIB
1434
}
1535

36+
/// Filter out tool-generated files and local ignore metadata so embedded and
37+
/// materialized stdlib hashing stays stable across workspaces.
38+
fn include_stdlib_path(path: &Path) -> bool {
39+
!EXCLUDED_STDLIB_PATHS.is_match(path)
40+
}
41+
1642
#[cfg(feature = "native")]
1743
pub fn embedded_stdlib_hash() -> &'static str {
1844
static EMBEDDED_STDLIB_HASH: OnceCell<String> = OnceCell::new();
@@ -26,6 +52,17 @@ pub fn embedded_stdlib_hash() -> &'static str {
2652
.as_str()
2753
}
2854

55+
#[cfg(feature = "native")]
56+
pub fn compute_stdlib_dir_hash(root: &Path) -> Result<String> {
57+
let mut files: Vec<(PathBuf, Vec<u8>)> = Vec::new();
58+
collect_stdlib_disk_files(root, &mut files)?;
59+
let refs: Vec<(&Path, &[u8])> = files
60+
.iter()
61+
.map(|(path, contents)| (path.as_path(), contents.as_slice()))
62+
.collect();
63+
pcb_canonical::compute_content_hash_from_memory_files(refs)
64+
}
65+
2966
/// Extract the embedded stdlib tree into `target_dir`.
3067
pub fn extract_embedded_stdlib(target_dir: &Path) -> Result<()> {
3168
fs::create_dir_all(target_dir).with_context(|| {
@@ -39,19 +76,74 @@ pub fn extract_embedded_stdlib(target_dir: &Path) -> Result<()> {
3976
"Failed to extract embedded stdlib into {}",
4077
target_dir.display()
4178
)
42-
})
79+
})?;
80+
#[cfg(feature = "native")]
81+
prune_excluded_paths(target_dir)?;
82+
Ok(())
4383
}
4484

4585
#[cfg(feature = "native")]
4686
fn collect_embedded_files(dir: &Dir<'static>, out: &mut Vec<(&'static Path, &'static [u8])>) {
47-
out.extend(dir.files().map(|file| (file.path(), file.contents())));
87+
out.extend(
88+
dir.files()
89+
.filter(|file| include_stdlib_path(file.path()))
90+
.map(|file| (file.path(), file.contents())),
91+
);
4892
for subdir in dir.dirs() {
4993
collect_embedded_files(subdir, out);
5094
}
5195
}
5296

97+
#[cfg(feature = "native")]
98+
fn collect_stdlib_disk_files(root: &Path, out: &mut Vec<(PathBuf, Vec<u8>)>) -> Result<()> {
99+
for entry in WalkDir::new(root).follow_links(false) {
100+
let entry = entry.with_context(|| format!("Failed to walk {}", root.display()))?;
101+
if !entry.file_type().is_file() {
102+
continue;
103+
}
104+
105+
let path = entry.path();
106+
let rel = path
107+
.strip_prefix(root)
108+
.with_context(|| format!("{} is not under {}", path.display(), root.display()))?;
109+
if !include_stdlib_path(rel) {
110+
continue;
111+
}
112+
113+
let contents =
114+
fs::read(path).with_context(|| format!("Failed to read {}", path.display()))?;
115+
out.push((rel.to_path_buf(), contents));
116+
}
117+
Ok(())
118+
}
119+
120+
#[cfg(feature = "native")]
121+
fn prune_excluded_paths(root: &Path) -> Result<()> {
122+
for entry in WalkDir::new(root).contents_first(true).min_depth(1) {
123+
let entry = entry.with_context(|| format!("Failed to walk {}", root.display()))?;
124+
let path = entry.path();
125+
let rel = path
126+
.strip_prefix(root)
127+
.with_context(|| format!("{} is not under {}", path.display(), root.display()))?;
128+
if include_stdlib_path(rel) {
129+
continue;
130+
}
131+
132+
if entry.file_type().is_dir() {
133+
fs::remove_dir_all(path)
134+
.with_context(|| format!("Failed to remove directory {}", path.display()))?;
135+
} else {
136+
fs::remove_file(path)
137+
.with_context(|| format!("Failed to remove file {}", path.display()))?;
138+
}
139+
}
140+
Ok(())
141+
}
142+
53143
#[cfg(test)]
54144
mod tests {
145+
use std::path::Path;
146+
55147
#[test]
56148
fn embeds_expected_stdlib_files() {
57149
let stdlib = &super::EMBEDDED_STDLIB;
@@ -61,4 +153,32 @@ mod tests {
61153
assert!(stdlib.get_file("docs/spec.md").is_some());
62154
assert!(stdlib.get_dir(".pcb").is_none());
63155
}
156+
157+
#[test]
158+
fn stdlib_filter_excludes_hidden_and_generated_noise() {
159+
assert!(super::include_stdlib_path(Path::new("interfaces.zen")));
160+
assert!(!super::include_stdlib_path(Path::new(
161+
"test/test_checks.zen"
162+
)));
163+
assert!(!super::include_stdlib_path(Path::new(".gitignore")));
164+
assert!(!super::include_stdlib_path(Path::new(
165+
"test/layout/layout.log"
166+
)));
167+
assert!(!super::include_stdlib_path(Path::new(
168+
"test/layout/snapshot.layout.json",
169+
)));
170+
}
171+
172+
#[cfg(feature = "native")]
173+
#[test]
174+
fn filtered_embedded_hash_matches_filtered_extracted_hash() {
175+
let temp = tempfile::tempdir().expect("create temp dir");
176+
super::extract_embedded_stdlib(temp.path()).expect("extract stdlib");
177+
assert!(!temp.path().join("test").exists());
178+
assert!(!temp.path().join(".gitignore").exists());
179+
180+
let expected = super::embedded_stdlib_hash().to_string();
181+
let actual = super::compute_stdlib_dir_hash(temp.path()).expect("hash extracted stdlib");
182+
assert_eq!(expected, actual);
183+
}
64184
}

crates/pcb-zen/src/cache_index.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use anyhow::{Context, Result};
44
use pcb_zen_core::FileProvider;
55
use pcb_zen_core::config::split_repo_and_subpath;
6+
use pcb_zen_core::embedded_stdlib::compute_stdlib_dir_hash;
67
use r2d2::{Pool, PooledConnection};
78
use r2d2_sqlite::SqliteConnectionManager;
89
use rusqlite::{OptionalExtension, params};
@@ -12,7 +13,6 @@ use std::path::PathBuf;
1213

1314
use crate::git;
1415
use crate::tags;
15-
use pcb_canonical::compute_content_hash_from_dir;
1616

1717
/// Bump this when changing table schemas. Encoded in the filename so a new
1818
/// version just creates a fresh file — no migration logic needed.
@@ -271,7 +271,7 @@ pub fn ensure_stdlib_materialized(workspace_root: &std::path::Path) -> Result<Pa
271271

272272
let expected_hash = pcb_zen_core::embedded_stdlib::embedded_stdlib_hash();
273273
let current_hash = if target.exists() {
274-
compute_content_hash_from_dir(&target).ok()
274+
compute_stdlib_dir_hash(&target).ok()
275275
} else {
276276
None
277277
};
@@ -292,7 +292,7 @@ pub fn ensure_stdlib_materialized(workspace_root: &std::path::Path) -> Result<Pa
292292
}
293293
pcb_zen_core::embedded_stdlib::extract_embedded_stdlib(&target)?;
294294

295-
let refreshed_hash = compute_content_hash_from_dir(&target)
295+
let refreshed_hash = compute_stdlib_dir_hash(&target)
296296
.with_context(|| format!("Failed to hash materialized stdlib at {}", target.display()))?;
297297
if refreshed_hash != expected_hash {
298298
anyhow::bail!(

pcb.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
[workspace]
2-
name = "examples"
2+
name = "pcb"
33
pcb-version = "0.3"
44
members = [
5-
"components/*",
6-
"reference/*",
7-
"modules/*",
8-
"boards/*",
9-
"graphics/*",
5+
"stdlib/*",
6+
"examples/*",
107
]
118

129
[dependencies]
1310
"gitlab.com/kicad/libraries/kicad-symbols" = "9.0.3"
11+
"gitlab.com/kicad/libraries/kicad-footprints" = "9.0.3"
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
11
github.com/diodeinc/kicad 0.1.5 h1:47V6qFMRuQmMmTw4E2vZa+7JC3QDv4liaNIYyWMJtP0=
22
github.com/diodeinc/kicad 0.1.5/pcb.toml h1:WJbNNnWmT1GE55n6WQytu/QDikSIOnHSheQaQLikv+c=
3-
github.com/diodeinc/stdlib 0.5.9 h1:zBVG9TVPSSgCEzg/wLzYI4cUFPdZ8FahMKcjgobphbU=
4-
github.com/diodeinc/stdlib 0.5.9/pcb.toml h1:p7AGSnxAhTOByyaQk5BJRGFTv4TSojhTFzSHcWHX4sM=

0 commit comments

Comments
 (0)