Skip to content

Commit ef5ed21

Browse files
Use argument array persistence even for single arg filters
1 parent 1e2b15b commit ef5ed21

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
&Op::Lookup(_) | &Op::Lookup2(_) => todo!(),
339332
}
@@ -402,12 +395,28 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult<Op> {
402395
Ok(Op::Export)
403396
}
404397
"link" => {
405-
let blob = repo.find_blob(entry.id())?;
406-
Ok(Op::Link(std::str::from_utf8(blob.content())?.to_string()))
398+
let inner = repo.find_tree(entry.id())?;
399+
let mode_blob = repo.find_blob(
400+
inner
401+
.get_name("0")
402+
.ok_or_else(|| josh_error("link: missing mode"))?
403+
.id(),
404+
)?;
405+
Ok(Op::Link(
406+
std::str::from_utf8(mode_blob.content())?.to_string(),
407+
))
407408
}
408409
"adapt" => {
409-
let blob = repo.find_blob(entry.id())?;
410-
Ok(Op::Adapt(std::str::from_utf8(blob.content())?.to_string()))
410+
let inner = repo.find_tree(entry.id())?;
411+
let mode_blob = repo.find_blob(
412+
inner
413+
.get_name("0")
414+
.ok_or_else(|| josh_error("adapt: missing mode"))?
415+
.id(),
416+
)?;
417+
Ok(Op::Adapt(
418+
std::str::from_utf8(mode_blob.content())?.to_string(),
419+
))
411420
}
412421
"unlink" => {
413422
let _ = repo.find_blob(entry.id())?;
@@ -443,8 +452,14 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult<Op> {
443452
}
444453
}
445454
"hook" => {
446-
let blob = repo.find_blob(entry.id())?;
447-
let hook_name = std::str::from_utf8(blob.content())?.to_string();
455+
let inner = repo.find_tree(entry.id())?;
456+
let hook_blob = repo.find_blob(
457+
inner
458+
.get_name("0")
459+
.ok_or_else(|| josh_error("hook: missing hook name"))?
460+
.id(),
461+
)?;
462+
let hook_name = std::str::from_utf8(hook_blob.content())?.to_string();
448463
Ok(Op::Hook(hook_name))
449464
}
450465
"author" => {
@@ -504,66 +519,90 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult<Op> {
504519
Ok(Op::Message(fmt, regex))
505520
}
506521
"subdir" => {
507-
let blob = repo.find_blob(entry.id())?;
508-
let path = std::str::from_utf8(blob.content())?;
522+
let inner = repo.find_tree(entry.id())?;
523+
let path_blob = repo.find_blob(
524+
inner
525+
.get_name("0")
526+
.ok_or_else(|| josh_error("subdir: missing path"))?
527+
.id(),
528+
)?;
529+
let path = std::str::from_utf8(path_blob.content())?;
509530
Ok(Op::Subdir(std::path::PathBuf::from(path)))
510531
}
511532
"prefix" => {
512-
let blob = repo.find_blob(entry.id())?;
513-
let path = std::str::from_utf8(blob.content())?;
533+
let inner = repo.find_tree(entry.id())?;
534+
let path_blob = repo.find_blob(
535+
inner
536+
.get_name("0")
537+
.ok_or_else(|| josh_error("prefix: missing path"))?
538+
.id(),
539+
)?;
540+
let path = std::str::from_utf8(path_blob.content())?;
514541
Ok(Op::Prefix(std::path::PathBuf::from(path)))
515542
}
516543
"file" => {
517-
// Try to read as tree (new format with destination path)
518-
if let Ok(inner) = repo.find_tree(entry.id()) {
519-
let dest_blob = repo.find_blob(
520-
inner
521-
.get_name("0")
522-
.ok_or_else(|| josh_error("file: missing destination path"))?
523-
.id(),
524-
)?;
525-
let dest_path_str = std::str::from_utf8(dest_blob.content())?.to_string();
526-
let source_path = inner
544+
let inner = repo.find_tree(entry.id())?;
545+
let dest_blob = repo.find_blob(
546+
inner
547+
.get_name("0")
548+
.ok_or_else(|| josh_error("file: missing destination path"))?
549+
.id(),
550+
)?;
551+
let source_blob = repo.find_blob(
552+
inner
527553
.get_name("1")
528-
.and_then(|entry| repo.find_blob(entry.id()).ok())
529-
.and_then(|blob| {
530-
std::str::from_utf8(blob.content())
531-
.ok()
532-
.map(|s| s.to_string())
533-
})
534-
.map(|s| std::path::PathBuf::from(s))
535-
.unwrap_or_else(|| std::path::PathBuf::from(&dest_path_str));
536-
Ok(Op::File(
537-
std::path::PathBuf::from(dest_path_str),
538-
source_path,
539-
))
540-
} else {
541-
// Fall back to blob format (old format, backward compatibility)
542-
let blob = repo.find_blob(entry.id())?;
543-
let path_str = std::str::from_utf8(blob.content())?.to_string();
544-
let path_buf = std::path::PathBuf::from(&path_str);
545-
// When reading from blob format, destination is the same as source
546-
Ok(Op::File(path_buf.clone(), path_buf))
547-
}
554+
.ok_or_else(|| josh_error("file: missing source path"))?
555+
.id(),
556+
)?;
557+
let dest_path_str = std::str::from_utf8(dest_blob.content())?.to_string();
558+
let source_path_str = std::str::from_utf8(source_blob.content())?.to_string();
559+
Ok(Op::File(
560+
std::path::PathBuf::from(dest_path_str),
561+
std::path::PathBuf::from(source_path_str),
562+
))
548563
}
549564
"embed" => {
550-
let blob = repo.find_blob(entry.id())?;
551-
let path = std::str::from_utf8(blob.content())?;
565+
let inner = repo.find_tree(entry.id())?;
566+
let path_blob = repo.find_blob(
567+
inner
568+
.get_name("0")
569+
.ok_or_else(|| josh_error("embed: missing path"))?
570+
.id(),
571+
)?;
572+
let path = std::str::from_utf8(path_blob.content())?;
552573
Ok(Op::Embed(std::path::PathBuf::from(path)))
553574
}
554575
"pattern" => {
555-
let blob = repo.find_blob(entry.id())?;
556-
let pattern = std::str::from_utf8(blob.content())?.to_string();
576+
let inner = repo.find_tree(entry.id())?;
577+
let pattern_blob = repo.find_blob(
578+
inner
579+
.get_name("0")
580+
.ok_or_else(|| josh_error("pattern: missing pattern"))?
581+
.id(),
582+
)?;
583+
let pattern = std::str::from_utf8(pattern_blob.content())?.to_string();
557584
Ok(Op::Pattern(pattern))
558585
}
559586
"workspace" => {
560-
let blob = repo.find_blob(entry.id())?;
561-
let path = std::str::from_utf8(blob.content())?;
587+
let inner = repo.find_tree(entry.id())?;
588+
let path_blob = repo.find_blob(
589+
inner
590+
.get_name("0")
591+
.ok_or_else(|| josh_error("workspace: missing path"))?
592+
.id(),
593+
)?;
594+
let path = std::str::from_utf8(path_blob.content())?;
562595
Ok(Op::Workspace(std::path::PathBuf::from(path)))
563596
}
564597
"stored" => {
565-
let blob = repo.find_blob(entry.id())?;
566-
let path = std::str::from_utf8(blob.content())?;
598+
let inner = repo.find_tree(entry.id())?;
599+
let path_blob = repo.find_blob(
600+
inner
601+
.get_name("0")
602+
.ok_or_else(|| josh_error("stored: missing path"))?
603+
.id(),
604+
)?;
605+
let path = std::str::from_utf8(path_blob.content())?;
567606
Ok(Op::Stored(std::path::PathBuf::from(path)))
568607
}
569608
"compose" => {
@@ -625,13 +664,33 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult<Op> {
625664
}
626665
"exclude" => {
627666
let exclude_tree = repo.find_tree(entry.id())?;
628-
let filter = from_tree2(repo, exclude_tree.id())?;
629-
Ok(Op::Exclude(to_filter(filter)))
667+
if exclude_tree.len() == 1 {
668+
let filter_tree = repo.find_tree(
669+
exclude_tree
670+
.get_name("0")
671+
.ok_or_else(|| josh_error("exclude: missing 0"))?
672+
.id(),
673+
)?;
674+
let filter = from_tree2(repo, filter_tree.id())?;
675+
Ok(Op::Exclude(to_filter(filter)))
676+
} else {
677+
Err(josh_error("exclude: expected 1 entry"))
678+
}
630679
}
631680
"pin" => {
632681
let pin_tree = repo.find_tree(entry.id())?;
633-
let filter = from_tree2(repo, pin_tree.id())?;
634-
Ok(Op::Pin(to_filter(filter)))
682+
if pin_tree.len() == 1 {
683+
let filter_tree = repo.find_tree(
684+
pin_tree
685+
.get_name("0")
686+
.ok_or_else(|| josh_error("pin: missing 0"))?
687+
.id(),
688+
)?;
689+
let filter = from_tree2(repo, filter_tree.id())?;
690+
Ok(Op::Pin(to_filter(filter)))
691+
} else {
692+
Err(josh_error("pin: expected 1 entry"))
693+
}
635694
}
636695
"rev" => {
637696
let rev_tree = repo.find_tree(entry.id())?;

0 commit comments

Comments
 (0)