11use crate :: { remote:: refs:: JsonRef , OutputFormat , Protocol } ;
22use git_features:: progress:: Progress ;
3- use git_object:: owned;
3+ use git_object:: { bstr :: ByteSlice , owned} ;
44use git_odb:: pack;
55use git_protocol:: fetch:: { Action , Arguments , Ref , Response } ;
6- use std:: { io, io:: BufRead , path:: PathBuf } ;
6+ use std:: {
7+ io:: { self , BufRead } ,
8+ path:: PathBuf ,
9+ } ;
710
811pub const PROGRESS_RANGE : std:: ops:: RangeInclusive < u8 > = 1 ..=3 ;
912
@@ -16,6 +19,7 @@ pub struct Context<W: io::Write> {
1619struct CloneDelegate < W : io:: Write > {
1720 ctx : Context < W > ,
1821 directory : Option < PathBuf > ,
22+ write_refs : bool ,
1923}
2024
2125impl < W : io:: Write > git_protocol:: fetch:: Delegate for CloneDelegate < W > {
@@ -43,8 +47,30 @@ impl<W: io::Write> git_protocol::fetch::Delegate for CloneDelegate<W> {
4347 index_kind : pack:: index:: Kind :: V2 ,
4448 iteration_mode : pack:: data:: iter:: Mode :: Verify ,
4549 } ;
46- let outcome = pack:: bundle:: Bundle :: write_stream_to_directory ( input, self . directory . take ( ) , progress, options)
50+ let outcome = pack:: bundle:: Bundle :: write_stream_to_directory ( input, self . directory . clone ( ) , progress, options)
4751 . map_err ( |err| io:: Error :: new ( io:: ErrorKind :: Other , err) ) ?;
52+
53+ if let Some ( directory) = self . directory . take ( ) {
54+ let assure_dir = |path : & git_object:: bstr:: BString | {
55+ assert ! ( !path. starts_with_str( "/" ) , "no ref start with a /, they are relative" ) ;
56+ let path = directory. join ( path. to_path_lossy ( ) ) ;
57+ std:: fs:: create_dir_all ( path. parent ( ) . expect ( "multi-component path" ) ) . map ( |_| path)
58+ } ;
59+ if self . write_refs {
60+ for r in refs {
61+ match r {
62+ Ref :: Symbolic { path, target, .. } => {
63+ assure_dir ( path) . map ( |path| ( path, format ! ( "ref: {}" , target) ) )
64+ }
65+ Ref :: Peeled { path, tag : object, .. } | Ref :: Direct { path, object } => {
66+ assure_dir ( path) . map ( |path| ( path, object. to_string ( ) ) )
67+ }
68+ }
69+ . and_then ( |( path, content) | std:: fs:: write ( path, content. as_bytes ( ) ) ) ?;
70+ }
71+ }
72+ }
73+
4874 match self . ctx . format {
4975 OutputFormat :: Human => drop ( print ( & mut self . ctx . out , outcome, refs) ) ,
5076 #[ cfg( feature = "serde1" ) ]
@@ -118,6 +144,7 @@ pub fn receive<P, W: io::Write>(
118144 protocol : Option < Protocol > ,
119145 url : & str ,
120146 directory : Option < PathBuf > ,
147+ write_refs : bool ,
121148 progress : P ,
122149 ctx : Context < W > ,
123150) -> anyhow:: Result < ( ) >
@@ -127,7 +154,11 @@ where
127154 <<P as Progress >:: SubProgress as Progress >:: SubProgress : Send ,
128155{
129156 let transport = git_protocol:: git_transport:: client:: connect ( url. as_bytes ( ) , protocol. unwrap_or_default ( ) . into ( ) ) ?;
130- let mut delegate = CloneDelegate { ctx, directory } ;
157+ let mut delegate = CloneDelegate {
158+ ctx,
159+ directory,
160+ write_refs,
161+ } ;
131162 git_protocol:: fetch ( transport, & mut delegate, git_protocol:: credentials:: helper, progress) ?;
132163 Ok ( ( ) )
133164}
0 commit comments