@@ -304,6 +304,7 @@ enum Op {
304304 Chain ( Filter , Filter ) ,
305305 Subtract ( Filter , Filter ) ,
306306 Exclude ( Filter ) ,
307+ Pin ( Filter ) ,
307308}
308309
309310/// Pretty print the filter on multiple lines with initial indentation level.
@@ -349,6 +350,10 @@ fn pretty2(op: &Op, indent: usize, compose: bool) -> String {
349350 Op :: Compose ( filters) => ff ( & filters, "exclude" , indent) ,
350351 b => format ! ( ":exclude[{}]" , pretty2( & b, indent, false ) ) ,
351352 } ,
353+ Op :: Pin ( filter) => match to_op ( * filter) {
354+ Op :: Compose ( filters) => ff ( & filters, "pin" , indent) ,
355+ b => format ! ( ":pin[{}]" , pretty2( & b, indent, false ) ) ,
356+ } ,
352357 Op :: Chain ( a, b) => match ( to_op ( * a) , to_op ( * b) ) {
353358 ( Op :: Subdir ( p1) , Op :: Prefix ( p2) ) if p1 == p2 => {
354359 format ! ( "::{}/" , parse:: quote_if( & p1. to_string_lossy( ) ) )
@@ -407,7 +412,7 @@ fn lazy_refs2(op: &Op) -> Vec<String> {
407412 acc
408413 } )
409414 }
410- Op :: Exclude ( filter) => lazy_refs ( * filter) ,
415+ Op :: Exclude ( filter) | Op :: Pin ( filter ) => lazy_refs ( * filter) ,
411416 Op :: Chain ( a, b) => {
412417 let mut av = lazy_refs ( * a) ;
413418 av. append ( & mut lazy_refs ( * b) ) ;
@@ -458,6 +463,7 @@ fn resolve_refs2(refs: &std::collections::HashMap<String, git2::Oid>, op: &Op) -
458463 Op :: Compose ( filters. iter ( ) . map ( |f| resolve_refs ( refs, * f) ) . collect ( ) )
459464 }
460465 Op :: Exclude ( filter) => Op :: Exclude ( resolve_refs ( refs, * filter) ) ,
466+ Op :: Pin ( filter) => Op :: Pin ( resolve_refs ( refs, * filter) ) ,
461467 Op :: Chain ( a, b) => Op :: Chain ( resolve_refs ( refs, * a) , resolve_refs ( refs, * b) ) ,
462468 Op :: Subtract ( a, b) => Op :: Subtract ( resolve_refs ( refs, * a) , resolve_refs ( refs, * b) ) ,
463469 Op :: Rev ( filters) => {
@@ -545,6 +551,9 @@ fn spec2(op: &Op) -> String {
545551 Op :: Exclude ( b) => {
546552 format ! ( ":exclude[{}]" , spec( * b) )
547553 }
554+ Op :: Pin ( filter) => {
555+ format ! ( ":pin[{}]" , spec( * filter) )
556+ }
548557 Op :: Rev ( filters) => {
549558 let mut v = filters
550559 . iter ( )
@@ -688,6 +697,9 @@ fn as_tree2(repo: &git2::Repository, op: &Op) -> JoshResult<git2::Oid> {
688697 Op :: Exclude ( b) => {
689698 builder. insert ( "exclude" , as_tree ( repo, * b) ?, git2:: FileMode :: Tree . into ( ) ) ?;
690699 }
700+ Op :: Pin ( b) => {
701+ builder. insert ( "pin" , as_tree ( repo, * b) ?, git2:: FileMode :: Tree . into ( ) ) ?;
702+ }
691703 Op :: Subdir ( path) => {
692704 builder. insert (
693705 "subdir" ,
@@ -1064,6 +1076,11 @@ fn from_tree2(repo: &git2::Repository, tree_oid: git2::Oid) -> JoshResult<Op> {
10641076 let filter = from_tree2 ( repo, exclude_tree. id ( ) ) ?;
10651077 Ok ( Op :: Exclude ( to_filter ( filter) ) )
10661078 }
1079+ "pin" => {
1080+ let pin_tree = repo. find_tree ( entry. id ( ) ) ?;
1081+ let filter = from_tree2 ( repo, pin_tree. id ( ) ) ?;
1082+ Ok ( Op :: Pin ( to_filter ( filter) ) )
1083+ }
10671084 "rev" => {
10681085 let rev_tree = repo. find_tree ( entry. id ( ) ) ?;
10691086 let mut filters = std:: collections:: BTreeMap :: new ( ) ;
@@ -1828,6 +1845,25 @@ fn apply2<'a>(transaction: &'a cache::Transaction, op: &Op, x: Apply<'a>) -> Jos
18281845 return apply ( transaction, * b, apply ( transaction, * a, x. clone ( ) ) ?) ;
18291846 }
18301847 Op :: Hook ( _) => Err ( josh_error ( "not applicable to tree" ) ) ,
1848+
1849+ Op :: Pin ( pin_filter) => {
1850+ let filtered_parent = if let Some ( parent) = x. parents . as_ref ( ) . and_then ( |p| p. first ( ) ) {
1851+ let parent = repo. find_commit ( * parent) ?;
1852+ let filtered = apply ( transaction, * pin_filter, Apply :: from_commit ( & parent) ?) ?;
1853+ filtered. tree . id ( )
1854+ } else {
1855+ tree:: empty_id ( )
1856+ } ;
1857+
1858+ // Mask out all the "pinned" files from current tree
1859+ let exclude = to_filter ( Op :: Exclude ( * pin_filter) ) ;
1860+ let with_mask = apply ( transaction, exclude, x. clone ( ) ) ?;
1861+
1862+ // Overlay filtered parent tree on current one to override versions
1863+ let with_overlay = tree:: overlay ( transaction, with_mask. tree . id ( ) , filtered_parent) ?;
1864+
1865+ Ok ( x. with_tree ( repo. find_tree ( with_overlay) ?) )
1866+ }
18311867 }
18321868}
18331869
0 commit comments