Skip to content

Commit 9cf5cc5

Browse files
Use argument array persistence even for single arg filters
1 parent 2d149cb commit 9cf5cc5

File tree

2 files changed

+227
-142
lines changed

2 files changed

+227
-142
lines changed

josh-core/src/filter/persist.rs

Lines changed: 146 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -190,51 +190,44 @@ impl InMemoryBuilder {
190190
push_tree_entries(&mut entries, [("chain", params_tree)]);
191191
}
192192
Op::Exclude(b) => {
193-
let child = self.build_filter(*b)?;
194-
push_tree_entries(&mut entries, [("exclude", child)]);
193+
let params_tree = self.build_filter_params(&[*b])?;
194+
push_tree_entries(&mut entries, [("exclude", params_tree)]);
195195
}
196196
Op::Pin(b) => {
197-
let child = self.build_filter(*b)?;
198-
push_tree_entries(&mut entries, [("pin", child)]);
197+
let params_tree = self.build_filter_params(&[*b])?;
198+
push_tree_entries(&mut entries, [("pin", params_tree)]);
199199
}
200200
Op::Subdir(path) => {
201-
let blob = self.write_blob(path.to_string_lossy().as_bytes());
202-
push_blob_entries(&mut entries, [("subdir", blob)]);
201+
let params_tree = self.build_str_params(&[path.to_string_lossy().as_ref()]);
202+
push_tree_entries(&mut entries, [("subdir", params_tree)]);
203203
}
204204
Op::Prefix(path) => {
205-
let blob = self.write_blob(path.to_string_lossy().as_bytes());
206-
push_blob_entries(&mut entries, [("prefix", blob)]);
205+
let params_tree = self.build_str_params(&[path.to_string_lossy().as_ref()]);
206+
push_tree_entries(&mut entries, [("prefix", params_tree)]);
207207
}
208208
Op::File(dest_path, source_path) => {
209-
if source_path == dest_path {
210-
// Backward compatibility: use blob format when source and dest are the same
211-
let blob = self.write_blob(dest_path.to_string_lossy().as_bytes());
212-
push_blob_entries(&mut entries, [("file", blob)]);
213-
} else {
214-
// New format: use tree format when source and dest differ
215-
// Store as (dest_path, source_path) to match enum order
216-
let params_tree = self.build_str_params(&[
217-
dest_path.to_string_lossy().as_ref(),
218-
source_path.to_string_lossy().as_ref(),
219-
]);
220-
push_tree_entries(&mut entries, [("file", params_tree)]);
221-
}
209+
// Store as (dest_path, source_path) to match enum order
210+
let params_tree = self.build_str_params(&[
211+
dest_path.to_string_lossy().as_ref(),
212+
source_path.to_string_lossy().as_ref(),
213+
]);
214+
push_tree_entries(&mut entries, [("file", params_tree)]);
222215
}
223216
Op::Embed(path) => {
224-
let blob = self.write_blob(path.to_string_lossy().as_bytes());
225-
push_blob_entries(&mut entries, [("embed", blob)]);
217+
let params_tree = self.build_str_params(&[path.to_string_lossy().as_ref()]);
218+
push_tree_entries(&mut entries, [("embed", params_tree)]);
226219
}
227220
Op::Pattern(pattern) => {
228-
let blob = self.write_blob(pattern.as_bytes());
229-
push_blob_entries(&mut entries, [("pattern", blob)]);
221+
let params_tree = self.build_str_params(&[pattern.as_ref()]);
222+
push_tree_entries(&mut entries, [("pattern", params_tree)]);
230223
}
231224
Op::Workspace(path) => {
232-
let blob = self.write_blob(path.to_string_lossy().as_bytes());
233-
push_blob_entries(&mut entries, [("workspace", blob)]);
225+
let params_tree = self.build_str_params(&[path.to_string_lossy().as_ref()]);
226+
push_tree_entries(&mut entries, [("workspace", params_tree)]);
234227
}
235228
Op::Stored(path) => {
236-
let blob = self.write_blob(path.to_string_lossy().as_bytes());
237-
push_blob_entries(&mut entries, [("stored", blob)]);
229+
let params_tree = self.build_str_params(&[path.to_string_lossy().as_ref()]);
230+
push_tree_entries(&mut entries, [("stored", params_tree)]);
238231
}
239232
Op::Nop => {
240233
let blob = self.write_blob(b"");
@@ -253,12 +246,12 @@ impl InMemoryBuilder {
253246
push_blob_entries(&mut entries, [("paths", blob)]);
254247
}
255248
Op::Link(mode) => {
256-
let blob = self.write_blob(mode.as_bytes());
257-
push_blob_entries(&mut entries, [("link", blob)]);
249+
let params_tree = self.build_str_params(&[mode.as_ref()]);
250+
push_tree_entries(&mut entries, [("link", params_tree)]);
258251
}
259252
Op::Adapt(mode) => {
260-
let blob = self.write_blob(mode.as_bytes());
261-
push_blob_entries(&mut entries, [("adapt", blob)]);
253+
let params_tree = self.build_str_params(&[mode.as_ref()]);
254+
push_tree_entries(&mut entries, [("adapt", params_tree)]);
262255
}
263256
Op::Unlink => {
264257
let blob = self.write_blob(b"");
@@ -332,8 +325,8 @@ impl InMemoryBuilder {
332325
push_tree_entries(&mut entries, [("regex_replace", params_tree)]);
333326
}
334327
Op::Hook(hook) => {
335-
let blob = self.write_blob(hook.as_bytes());
336-
push_blob_entries(&mut entries, [("hook", blob)]);
328+
let params_tree = self.build_str_params(&[hook.as_ref()]);
329+
push_tree_entries(&mut entries, [("hook", params_tree)]);
337330
}
338331
}
339332

@@ -401,12 +394,28 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult<Op> {
401394
Ok(Op::Export)
402395
}
403396
"link" => {
404-
let blob = repo.find_blob(entry.id())?;
405-
Ok(Op::Link(std::str::from_utf8(blob.content())?.to_string()))
397+
let inner = repo.find_tree(entry.id())?;
398+
let mode_blob = repo.find_blob(
399+
inner
400+
.get_name("0")
401+
.ok_or_else(|| josh_error("link: missing mode"))?
402+
.id(),
403+
)?;
404+
Ok(Op::Link(
405+
std::str::from_utf8(mode_blob.content())?.to_string(),
406+
))
406407
}
407408
"adapt" => {
408-
let blob = repo.find_blob(entry.id())?;
409-
Ok(Op::Adapt(std::str::from_utf8(blob.content())?.to_string()))
409+
let inner = repo.find_tree(entry.id())?;
410+
let mode_blob = repo.find_blob(
411+
inner
412+
.get_name("0")
413+
.ok_or_else(|| josh_error("adapt: missing mode"))?
414+
.id(),
415+
)?;
416+
Ok(Op::Adapt(
417+
std::str::from_utf8(mode_blob.content())?.to_string(),
418+
))
410419
}
411420
"unlink" => {
412421
let _ = repo.find_blob(entry.id())?;
@@ -442,8 +451,14 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult<Op> {
442451
}
443452
}
444453
"hook" => {
445-
let blob = repo.find_blob(entry.id())?;
446-
let hook_name = std::str::from_utf8(blob.content())?.to_string();
454+
let inner = repo.find_tree(entry.id())?;
455+
let hook_blob = repo.find_blob(
456+
inner
457+
.get_name("0")
458+
.ok_or_else(|| josh_error("hook: missing hook name"))?
459+
.id(),
460+
)?;
461+
let hook_name = std::str::from_utf8(hook_blob.content())?.to_string();
447462
Ok(Op::Hook(hook_name))
448463
}
449464
"author" => {
@@ -503,66 +518,90 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult<Op> {
503518
Ok(Op::Message(fmt, regex))
504519
}
505520
"subdir" => {
506-
let blob = repo.find_blob(entry.id())?;
507-
let path = std::str::from_utf8(blob.content())?;
521+
let inner = repo.find_tree(entry.id())?;
522+
let path_blob = repo.find_blob(
523+
inner
524+
.get_name("0")
525+
.ok_or_else(|| josh_error("subdir: missing path"))?
526+
.id(),
527+
)?;
528+
let path = std::str::from_utf8(path_blob.content())?;
508529
Ok(Op::Subdir(std::path::PathBuf::from(path)))
509530
}
510531
"prefix" => {
511-
let blob = repo.find_blob(entry.id())?;
512-
let path = std::str::from_utf8(blob.content())?;
532+
let inner = repo.find_tree(entry.id())?;
533+
let path_blob = repo.find_blob(
534+
inner
535+
.get_name("0")
536+
.ok_or_else(|| josh_error("prefix: missing path"))?
537+
.id(),
538+
)?;
539+
let path = std::str::from_utf8(path_blob.content())?;
513540
Ok(Op::Prefix(std::path::PathBuf::from(path)))
514541
}
515542
"file" => {
516-
// Try to read as tree (new format with destination path)
517-
if let Ok(inner) = repo.find_tree(entry.id()) {
518-
let dest_blob = repo.find_blob(
519-
inner
520-
.get_name("0")
521-
.ok_or_else(|| josh_error("file: missing destination path"))?
522-
.id(),
523-
)?;
524-
let dest_path_str = std::str::from_utf8(dest_blob.content())?.to_string();
525-
let source_path = inner
543+
let inner = repo.find_tree(entry.id())?;
544+
let dest_blob = repo.find_blob(
545+
inner
546+
.get_name("0")
547+
.ok_or_else(|| josh_error("file: missing destination path"))?
548+
.id(),
549+
)?;
550+
let source_blob = repo.find_blob(
551+
inner
526552
.get_name("1")
527-
.and_then(|entry| repo.find_blob(entry.id()).ok())
528-
.and_then(|blob| {
529-
std::str::from_utf8(blob.content())
530-
.ok()
531-
.map(|s| s.to_string())
532-
})
533-
.map(|s| std::path::PathBuf::from(s))
534-
.unwrap_or_else(|| std::path::PathBuf::from(&dest_path_str));
535-
Ok(Op::File(
536-
std::path::PathBuf::from(dest_path_str),
537-
source_path,
538-
))
539-
} else {
540-
// Fall back to blob format (old format, backward compatibility)
541-
let blob = repo.find_blob(entry.id())?;
542-
let path_str = std::str::from_utf8(blob.content())?.to_string();
543-
let path_buf = std::path::PathBuf::from(&path_str);
544-
// When reading from blob format, destination is the same as source
545-
Ok(Op::File(path_buf.clone(), path_buf))
546-
}
553+
.ok_or_else(|| josh_error("file: missing source path"))?
554+
.id(),
555+
)?;
556+
let dest_path_str = std::str::from_utf8(dest_blob.content())?.to_string();
557+
let source_path_str = std::str::from_utf8(source_blob.content())?.to_string();
558+
Ok(Op::File(
559+
std::path::PathBuf::from(dest_path_str),
560+
std::path::PathBuf::from(source_path_str),
561+
))
547562
}
548563
"embed" => {
549-
let blob = repo.find_blob(entry.id())?;
550-
let path = std::str::from_utf8(blob.content())?;
564+
let inner = repo.find_tree(entry.id())?;
565+
let path_blob = repo.find_blob(
566+
inner
567+
.get_name("0")
568+
.ok_or_else(|| josh_error("embed: missing path"))?
569+
.id(),
570+
)?;
571+
let path = std::str::from_utf8(path_blob.content())?;
551572
Ok(Op::Embed(std::path::PathBuf::from(path)))
552573
}
553574
"pattern" => {
554-
let blob = repo.find_blob(entry.id())?;
555-
let pattern = std::str::from_utf8(blob.content())?.to_string();
575+
let inner = repo.find_tree(entry.id())?;
576+
let pattern_blob = repo.find_blob(
577+
inner
578+
.get_name("0")
579+
.ok_or_else(|| josh_error("pattern: missing pattern"))?
580+
.id(),
581+
)?;
582+
let pattern = std::str::from_utf8(pattern_blob.content())?.to_string();
556583
Ok(Op::Pattern(pattern))
557584
}
558585
"workspace" => {
559-
let blob = repo.find_blob(entry.id())?;
560-
let path = std::str::from_utf8(blob.content())?;
586+
let inner = repo.find_tree(entry.id())?;
587+
let path_blob = repo.find_blob(
588+
inner
589+
.get_name("0")
590+
.ok_or_else(|| josh_error("workspace: missing path"))?
591+
.id(),
592+
)?;
593+
let path = std::str::from_utf8(path_blob.content())?;
561594
Ok(Op::Workspace(std::path::PathBuf::from(path)))
562595
}
563596
"stored" => {
564-
let blob = repo.find_blob(entry.id())?;
565-
let path = std::str::from_utf8(blob.content())?;
597+
let inner = repo.find_tree(entry.id())?;
598+
let path_blob = repo.find_blob(
599+
inner
600+
.get_name("0")
601+
.ok_or_else(|| josh_error("stored: missing path"))?
602+
.id(),
603+
)?;
604+
let path = std::str::from_utf8(path_blob.content())?;
566605
Ok(Op::Stored(std::path::PathBuf::from(path)))
567606
}
568607
"compose" => {
@@ -624,13 +663,33 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult<Op> {
624663
}
625664
"exclude" => {
626665
let exclude_tree = repo.find_tree(entry.id())?;
627-
let filter = from_tree2(repo, exclude_tree.id())?;
628-
Ok(Op::Exclude(to_filter(filter)))
666+
if exclude_tree.len() == 1 {
667+
let filter_tree = repo.find_tree(
668+
exclude_tree
669+
.get_name("0")
670+
.ok_or_else(|| josh_error("exclude: missing 0"))?
671+
.id(),
672+
)?;
673+
let filter = from_tree2(repo, filter_tree.id())?;
674+
Ok(Op::Exclude(to_filter(filter)))
675+
} else {
676+
Err(josh_error("exclude: expected 1 entry"))
677+
}
629678
}
630679
"pin" => {
631680
let pin_tree = repo.find_tree(entry.id())?;
632-
let filter = from_tree2(repo, pin_tree.id())?;
633-
Ok(Op::Pin(to_filter(filter)))
681+
if pin_tree.len() == 1 {
682+
let filter_tree = repo.find_tree(
683+
pin_tree
684+
.get_name("0")
685+
.ok_or_else(|| josh_error("pin: missing 0"))?
686+
.id(),
687+
)?;
688+
let filter = from_tree2(repo, filter_tree.id())?;
689+
Ok(Op::Pin(to_filter(filter)))
690+
} else {
691+
Err(josh_error("pin: expected 1 entry"))
692+
}
634693
}
635694
"rev" => {
636695
let rev_tree = repo.find_tree(entry.id())?;

0 commit comments

Comments
 (0)