@@ -19,7 +19,7 @@ pub mod pipeline {
1919     pub  mod  options { 
2020        use  crate :: { bstr:: BString ,  config} ; 
2121
22-         /// The error returned by [Pipeline::options()][ crate::filter::Pipeline::options()] . 
22+         /// The error returned by [Pipeline::options()]( crate::filter::Pipeline::options()) . 
2323         #[ derive( Debug ,  thiserror:: Error ) ]  
2424        #[ allow( missing_docs) ]  
2525        pub  enum  Error  { 
@@ -39,7 +39,7 @@ pub mod pipeline {
3939
4040    /// 
4141     pub  mod  convert_to_git { 
42-         /// The error returned by [Pipeline::convert_to_git()][ crate::filter::Pipeline::convert_to_git()] . 
42+         /// The error returned by [Pipeline::convert_to_git()]( crate::filter::Pipeline::convert_to_git()) . 
4343         #[ derive( Debug ,  thiserror:: Error ) ]  
4444        #[ allow( missing_docs) ]  
4545        pub  enum  Error  { 
@@ -52,7 +52,7 @@ pub mod pipeline {
5252
5353    /// 
5454     pub  mod  convert_to_worktree { 
55-         /// The error returned by [Pipeline::convert_to_worktree()][ crate::filter::Pipeline::convert_to_worktree()] . 
55+         /// The error returned by [Pipeline::convert_to_worktree()]( crate::filter::Pipeline::convert_to_worktree()) . 
5656         #[ derive( Debug ,  thiserror:: Error ) ]  
5757        #[ allow( missing_docs) ]  
5858        pub  enum  Error  { 
@@ -62,6 +62,25 @@ pub mod pipeline {
6262            Convert ( #[ from]   gix_filter:: pipeline:: convert:: to_worktree:: Error ) , 
6363        } 
6464    } 
65+ 
66+     /// 
67+      pub  mod  worktree_file_to_object { 
68+         use  std:: path:: PathBuf ; 
69+ 
70+         /// The error returned by [Pipeline::worktree_file_to_object()](crate::filter::Pipeline::worktree_file_to_object()). 
71+          #[ derive( Debug ,  thiserror:: Error ) ]  
72+         #[ allow( missing_docs) ]  
73+         pub  enum  Error  { 
74+             #[ error( "Cannot add worktree files in bare repositories" ) ]  
75+             MissingWorktree , 
76+             #[ error( "Failed to perform IO for object creation for '{}'" ,  path. display( ) ) ]  
77+             IO  {  source :  std:: io:: Error ,  path :  PathBuf  } , 
78+             #[ error( transparent) ]  
79+             WriteBlob ( #[ from]   crate :: object:: write:: Error ) , 
80+             #[ error( transparent) ]  
81+             ConvertToGit ( #[ from]   crate :: filter:: pipeline:: convert_to_git:: Error ) , 
82+         } 
83+     } 
6584} 
6685
6786/// A git pipeline for transforming data *to-git* and *to-worktree*, based 
@@ -133,7 +152,7 @@ impl Pipeline<'_> {
133152    /// Convert a `src` stream (to be found at `rela_path`, a repo-relative path) to a representation suitable for storage in `git` 
134153     /// by using all attributes at `rela_path` and configuration of the repository to know exactly which filters apply. 
135154     /// `index` is used in particularly rare cases where the CRLF filter in auto-mode tries to determine whether to apply itself, 
136-      /// and it should match the state used when [instantiating this instance][ Self::new()] . 
155+      /// and it should match the state used when [instantiating this instance]( Self::new()) . 
137156     /// Note that the return-type implements [`std::io::Read`]. 
138157     pub  fn  convert_to_git < R > ( 
139158        & mut  self , 
@@ -187,6 +206,63 @@ impl Pipeline<'_> {
187206        ) ?) 
188207    } 
189208
209+     /// Add the worktree file at `rela_path` to the object database and return its `(id, entry)` for use in a tree or in the index, for instance. 
210+      /// 
211+      /// `index` is used in particularly rare cases where the CRLF filter in auto-mode tries to determine whether to apply itself, 
212+      /// and it should match the state used when [instantiating this instance](Self::new()). 
213+      /// 
214+      /// Return `Ok(None)` the file didn't exist in the worktree, or if it was of an untrackable type. 
215+      pub  fn  worktree_file_to_object ( 
216+         & mut  self , 
217+         rela_path :  & BStr , 
218+         index :  & gix_index:: State , 
219+     )  -> Result < Option < ( gix_hash:: ObjectId ,  gix_object:: tree:: EntryKind ) > ,  pipeline:: worktree_file_to_object:: Error > 
220+     { 
221+         use  pipeline:: worktree_file_to_object:: Error ; 
222+ 
223+         let  rela_path_as_path = gix_path:: from_bstr ( rela_path) ; 
224+         let  repo = self . repo ; 
225+         let  worktree_dir = repo. work_dir ( ) . ok_or ( Error :: MissingWorktree ) ?; 
226+         let  path = worktree_dir. join ( & rela_path_as_path) ; 
227+         let  md = match  std:: fs:: symlink_metadata ( & path)  { 
228+             Ok ( md)  => md, 
229+             Err ( err)  => { 
230+                 if  gix_fs:: io_err:: is_not_found ( err. kind ( ) ,  err. raw_os_error ( ) )  { 
231+                     return  Ok ( None ) ; 
232+                 }  else  { 
233+                     return  Err ( Error :: IO  {  source :  err,  path } ) ; 
234+                 } 
235+             } 
236+         } ; 
237+         let  ( id,  kind)  = if  md. is_symlink ( )  { 
238+             let  target = std:: fs:: read_link ( & path) . map_err ( |source| Error :: IO  {  source,  path } ) ?; 
239+             let  id = repo. write_blob ( gix_path:: into_bstr ( target) . as_ref ( ) ) ?; 
240+             ( id,  gix_object:: tree:: EntryKind :: Link ) 
241+         }  else  if  md. is_file ( )  { 
242+             use  gix_filter:: pipeline:: convert:: ToGitOutcome ; 
243+ 
244+             let  file = std:: fs:: File :: open ( & path) . map_err ( |source| Error :: IO  {  source,  path } ) ?; 
245+             let  file_for_git = self . convert_to_git ( file,  rela_path_as_path. as_ref ( ) ,  index) ?; 
246+             let  id = match  file_for_git { 
247+                 ToGitOutcome :: Unchanged ( mut  file)  => repo. write_blob_stream ( & mut  file) ?, 
248+                 ToGitOutcome :: Buffer ( buf)  => repo. write_blob ( buf) ?, 
249+                 ToGitOutcome :: Process ( mut  read)  => repo. write_blob_stream ( & mut  read) ?, 
250+             } ; 
251+ 
252+             let  kind = if  gix_fs:: is_executable ( & md)  { 
253+                 gix_object:: tree:: EntryKind :: BlobExecutable 
254+             }  else  { 
255+                 gix_object:: tree:: EntryKind :: Blob 
256+             } ; 
257+             ( id,  kind) 
258+         }  else  { 
259+             // This is probably a type-change to something we can't track. 
260+             return  Ok ( None ) ; 
261+         } ; 
262+ 
263+         Ok ( Some ( ( id. detach ( ) ,  kind) ) ) 
264+     } 
265+ 
190266    /// Retrieve the static context that is made available to the process filters. 
191267     /// 
192268     /// The context set here is relevant for the [`convert_to_git()`][Self::convert_to_git()] and 
0 commit comments