Skip to content

Commit a4f8089

Browse files
Use argument array persistence even for single arg filters
1 parent b4f811f commit a4f8089

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"");
@@ -323,8 +316,8 @@ impl InMemoryBuilder {
323316
push_tree_entries(&mut entries, [("regex_replace", params_tree)]);
324317
}
325318
Op::Hook(hook) => {
326-
let blob = self.write_blob(hook.as_bytes());
327-
push_blob_entries(&mut entries, [("hook", blob)]);
319+
let params_tree = self.build_str_params(&[hook.as_ref()]);
320+
push_tree_entries(&mut entries, [("hook", params_tree)]);
328321
}
329322
}
330323

@@ -392,12 +385,28 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult<Op> {
392385
Ok(Op::Export)
393386
}
394387
"link" => {
395-
let blob = repo.find_blob(entry.id())?;
396-
Ok(Op::Link(std::str::from_utf8(blob.content())?.to_string()))
388+
let inner = repo.find_tree(entry.id())?;
389+
let mode_blob = repo.find_blob(
390+
inner
391+
.get_name("0")
392+
.ok_or_else(|| josh_error("link: missing mode"))?
393+
.id(),
394+
)?;
395+
Ok(Op::Link(
396+
std::str::from_utf8(mode_blob.content())?.to_string(),
397+
))
397398
}
398399
"adapt" => {
399-
let blob = repo.find_blob(entry.id())?;
400-
Ok(Op::Adapt(std::str::from_utf8(blob.content())?.to_string()))
400+
let inner = repo.find_tree(entry.id())?;
401+
let mode_blob = repo.find_blob(
402+
inner
403+
.get_name("0")
404+
.ok_or_else(|| josh_error("adapt: missing mode"))?
405+
.id(),
406+
)?;
407+
Ok(Op::Adapt(
408+
std::str::from_utf8(mode_blob.content())?.to_string(),
409+
))
401410
}
402411
"unlink" => {
403412
let _ = repo.find_blob(entry.id())?;
@@ -433,8 +442,14 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult<Op> {
433442
}
434443
}
435444
"hook" => {
436-
let blob = repo.find_blob(entry.id())?;
437-
let hook_name = std::str::from_utf8(blob.content())?.to_string();
445+
let inner = repo.find_tree(entry.id())?;
446+
let hook_blob = repo.find_blob(
447+
inner
448+
.get_name("0")
449+
.ok_or_else(|| josh_error("hook: missing hook name"))?
450+
.id(),
451+
)?;
452+
let hook_name = std::str::from_utf8(hook_blob.content())?.to_string();
438453
Ok(Op::Hook(hook_name))
439454
}
440455
"author" => {
@@ -494,66 +509,90 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult<Op> {
494509
Ok(Op::Message(fmt, regex))
495510
}
496511
"subdir" => {
497-
let blob = repo.find_blob(entry.id())?;
498-
let path = std::str::from_utf8(blob.content())?;
512+
let inner = repo.find_tree(entry.id())?;
513+
let path_blob = repo.find_blob(
514+
inner
515+
.get_name("0")
516+
.ok_or_else(|| josh_error("subdir: missing path"))?
517+
.id(),
518+
)?;
519+
let path = std::str::from_utf8(path_blob.content())?;
499520
Ok(Op::Subdir(std::path::PathBuf::from(path)))
500521
}
501522
"prefix" => {
502-
let blob = repo.find_blob(entry.id())?;
503-
let path = std::str::from_utf8(blob.content())?;
523+
let inner = repo.find_tree(entry.id())?;
524+
let path_blob = repo.find_blob(
525+
inner
526+
.get_name("0")
527+
.ok_or_else(|| josh_error("prefix: missing path"))?
528+
.id(),
529+
)?;
530+
let path = std::str::from_utf8(path_blob.content())?;
504531
Ok(Op::Prefix(std::path::PathBuf::from(path)))
505532
}
506533
"file" => {
507-
// Try to read as tree (new format with destination path)
508-
if let Ok(inner) = repo.find_tree(entry.id()) {
509-
let dest_blob = repo.find_blob(
510-
inner
511-
.get_name("0")
512-
.ok_or_else(|| josh_error("file: missing destination path"))?
513-
.id(),
514-
)?;
515-
let dest_path_str = std::str::from_utf8(dest_blob.content())?.to_string();
516-
let source_path = inner
534+
let inner = repo.find_tree(entry.id())?;
535+
let dest_blob = repo.find_blob(
536+
inner
537+
.get_name("0")
538+
.ok_or_else(|| josh_error("file: missing destination path"))?
539+
.id(),
540+
)?;
541+
let source_blob = repo.find_blob(
542+
inner
517543
.get_name("1")
518-
.and_then(|entry| repo.find_blob(entry.id()).ok())
519-
.and_then(|blob| {
520-
std::str::from_utf8(blob.content())
521-
.ok()
522-
.map(|s| s.to_string())
523-
})
524-
.map(|s| std::path::PathBuf::from(s))
525-
.unwrap_or_else(|| std::path::PathBuf::from(&dest_path_str));
526-
Ok(Op::File(
527-
std::path::PathBuf::from(dest_path_str),
528-
source_path,
529-
))
530-
} else {
531-
// Fall back to blob format (old format, backward compatibility)
532-
let blob = repo.find_blob(entry.id())?;
533-
let path_str = std::str::from_utf8(blob.content())?.to_string();
534-
let path_buf = std::path::PathBuf::from(&path_str);
535-
// When reading from blob format, destination is the same as source
536-
Ok(Op::File(path_buf.clone(), path_buf))
537-
}
544+
.ok_or_else(|| josh_error("file: missing source path"))?
545+
.id(),
546+
)?;
547+
let dest_path_str = std::str::from_utf8(dest_blob.content())?.to_string();
548+
let source_path_str = std::str::from_utf8(source_blob.content())?.to_string();
549+
Ok(Op::File(
550+
std::path::PathBuf::from(dest_path_str),
551+
std::path::PathBuf::from(source_path_str),
552+
))
538553
}
539554
"embed" => {
540-
let blob = repo.find_blob(entry.id())?;
541-
let path = std::str::from_utf8(blob.content())?;
555+
let inner = repo.find_tree(entry.id())?;
556+
let path_blob = repo.find_blob(
557+
inner
558+
.get_name("0")
559+
.ok_or_else(|| josh_error("embed: missing path"))?
560+
.id(),
561+
)?;
562+
let path = std::str::from_utf8(path_blob.content())?;
542563
Ok(Op::Embed(std::path::PathBuf::from(path)))
543564
}
544565
"pattern" => {
545-
let blob = repo.find_blob(entry.id())?;
546-
let pattern = std::str::from_utf8(blob.content())?.to_string();
566+
let inner = repo.find_tree(entry.id())?;
567+
let pattern_blob = repo.find_blob(
568+
inner
569+
.get_name("0")
570+
.ok_or_else(|| josh_error("pattern: missing pattern"))?
571+
.id(),
572+
)?;
573+
let pattern = std::str::from_utf8(pattern_blob.content())?.to_string();
547574
Ok(Op::Pattern(pattern))
548575
}
549576
"workspace" => {
550-
let blob = repo.find_blob(entry.id())?;
551-
let path = std::str::from_utf8(blob.content())?;
577+
let inner = repo.find_tree(entry.id())?;
578+
let path_blob = repo.find_blob(
579+
inner
580+
.get_name("0")
581+
.ok_or_else(|| josh_error("workspace: missing path"))?
582+
.id(),
583+
)?;
584+
let path = std::str::from_utf8(path_blob.content())?;
552585
Ok(Op::Workspace(std::path::PathBuf::from(path)))
553586
}
554587
"stored" => {
555-
let blob = repo.find_blob(entry.id())?;
556-
let path = std::str::from_utf8(blob.content())?;
588+
let inner = repo.find_tree(entry.id())?;
589+
let path_blob = repo.find_blob(
590+
inner
591+
.get_name("0")
592+
.ok_or_else(|| josh_error("stored: missing path"))?
593+
.id(),
594+
)?;
595+
let path = std::str::from_utf8(path_blob.content())?;
557596
Ok(Op::Stored(std::path::PathBuf::from(path)))
558597
}
559598
"compose" => {
@@ -615,13 +654,33 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult<Op> {
615654
}
616655
"exclude" => {
617656
let exclude_tree = repo.find_tree(entry.id())?;
618-
let filter = from_tree2(repo, exclude_tree.id())?;
619-
Ok(Op::Exclude(to_filter(filter)))
657+
if exclude_tree.len() == 1 {
658+
let filter_tree = repo.find_tree(
659+
exclude_tree
660+
.get_name("0")
661+
.ok_or_else(|| josh_error("exclude: missing 0"))?
662+
.id(),
663+
)?;
664+
let filter = from_tree2(repo, filter_tree.id())?;
665+
Ok(Op::Exclude(to_filter(filter)))
666+
} else {
667+
Err(josh_error("exclude: expected 1 entry"))
668+
}
620669
}
621670
"pin" => {
622671
let pin_tree = repo.find_tree(entry.id())?;
623-
let filter = from_tree2(repo, pin_tree.id())?;
624-
Ok(Op::Pin(to_filter(filter)))
672+
if pin_tree.len() == 1 {
673+
let filter_tree = repo.find_tree(
674+
pin_tree
675+
.get_name("0")
676+
.ok_or_else(|| josh_error("pin: missing 0"))?
677+
.id(),
678+
)?;
679+
let filter = from_tree2(repo, filter_tree.id())?;
680+
Ok(Op::Pin(to_filter(filter)))
681+
} else {
682+
Err(josh_error("pin: expected 1 entry"))
683+
}
625684
}
626685
"rev" => {
627686
let rev_tree = repo.find_tree(entry.id())?;

0 commit comments

Comments
 (0)