@@ -10,91 +10,49 @@ pub fn ensure_repo(source: &str) -> Result<PathBuf> {
1010 }
1111
1212 if cache_dir. exists ( ) {
13- sync_repo ( source , & cache_dir) ?;
13+ sync_repo ( & cache_dir) ?;
1414 } else {
1515 clone_repo ( source, & cache_dir) ?;
1616 }
1717
1818 Ok ( cache_dir)
1919}
2020
21- fn is_remote ( source : & str ) -> bool {
22- source. starts_with ( "https://" )
23- || source. starts_with ( "git@" )
24- || source. starts_with ( "ssh://" )
25- || source. starts_with ( "git://" )
26- }
27-
2821fn clone_repo ( source : & str , dest : & Path ) -> Result < ( ) > {
29- if is_remote ( source) {
30- let dest_str = dest
31- . to_str ( )
32- . context ( "Destination path contains invalid UTF-8" ) ?;
33- let output = Command :: new ( "git" )
34- . args ( [ "clone" , source, dest_str] )
35- . output ( ) ?;
36-
37- if !output. status . success ( ) {
38- let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
39- anyhow:: bail!( "git clone failed: {}" , stderr) ;
40- }
41- } else {
42- // Local: rsync entire directory (including uncommitted changes)
43- rsync_local ( source, dest) ?;
44- }
45-
46- Ok ( ( ) )
47- }
22+ let dest_str = dest
23+ . to_str ( )
24+ . context ( "Destination path contains invalid UTF-8" ) ?;
25+ let output = Command :: new ( "git" )
26+ . args ( [ "clone" , source, dest_str] )
27+ . output ( ) ?;
4828
49- fn sync_repo ( source : & str , dest : & Path ) -> Result < ( ) > {
50- if is_remote ( source) {
51- // Remote: git pull
52- let has_upstream = Command :: new ( "git" )
53- . args ( [ "rev-parse" , "--abbrev-ref" , "@{upstream}" ] )
54- . current_dir ( dest)
55- . output ( )
56- . map ( |o| o. status . success ( ) )
57- . unwrap_or ( false ) ;
58-
59- if has_upstream {
60- let output = Command :: new ( "git" )
61- . args ( [ "pull" , "--ff-only" ] )
62- . current_dir ( dest)
63- . output ( ) ?;
64-
65- if !output. status . success ( ) {
66- let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
67- anyhow:: bail!( "git pull failed: {}" , stderr) ;
68- }
69- }
70- } else {
71- // Local: rsync (syncs uncommitted changes too)
72- rsync_local ( source, dest) ?;
29+ if !output. status . success ( ) {
30+ let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
31+ anyhow:: bail!( "git clone failed: {}" , stderr) ;
7332 }
7433
7534 Ok ( ( ) )
7635}
7736
78- fn rsync_local ( source : & str , dest : & Path ) -> Result < ( ) > {
79- std:: fs:: create_dir_all ( dest) ?;
37+ fn sync_repo ( dest : & Path ) -> Result < ( ) > {
38+ // git clone sets up tracking branches for both local and remote repos
39+ let has_upstream = Command :: new ( "git" )
40+ . args ( [ "rev-parse" , "--abbrev-ref" , "@{upstream}" ] )
41+ . current_dir ( dest)
42+ . output ( )
43+ . map ( |o| o. status . success ( ) )
44+ . unwrap_or ( false ) ;
8045
81- let dest_str = dest
82- . to_str ( )
83- . context ( "Destination path contains invalid UTF-8" ) ?;
84- let output = Command :: new ( "rsync" )
85- . args ( [
86- "-a" ,
87- "--delete" ,
88- "--exclude" ,
89- ".git" ,
90- & format ! ( "{}/" , source) ,
91- dest_str,
92- ] )
93- . output ( ) ?;
46+ if has_upstream {
47+ let output = Command :: new ( "git" )
48+ . args ( [ "pull" , "--ff-only" ] )
49+ . current_dir ( dest)
50+ . output ( ) ?;
9451
95- if !output. status . success ( ) {
96- let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
97- anyhow:: bail!( "rsync failed: {}" , stderr) ;
52+ if !output. status . success ( ) {
53+ let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
54+ anyhow:: bail!( "git pull failed: {}" , stderr) ;
55+ }
9856 }
9957
10058 Ok ( ( ) )
@@ -139,9 +97,6 @@ pub fn get_job_dir(sot_path: &Path, job_id: &str) -> PathBuf {
13997}
14098
14199pub fn sync_to_job_dir ( sot_path : & Path , job_dir : & Path ) -> Result < ( ) > {
142- let sot_str = sot_path
143- . to_str ( )
144- . context ( "Source path contains invalid UTF-8" ) ?;
145100 let job_dir_str = job_dir
146101 . to_str ( )
147102 . context ( "Job directory path contains invalid UTF-8" ) ?;
@@ -158,68 +113,46 @@ pub fn sync_to_job_dir(sot_path: &Path, job_dir: &Path) -> Result<()> {
158113 }
159114 std:: fs:: create_dir_all ( & temp_dir) ?;
160115
161- // Check if .git exists (remote repos have it, local rsync'd repos don't)
162- if sot_path. join ( ".git" ) . exists ( ) {
163- // Use git archive for git repos
164- let archive = Command :: new ( "git" )
165- . args ( [ "archive" , "HEAD" ] )
166- . current_dir ( sot_path)
167- . output ( ) ?;
168-
169- if !archive. status . success ( ) {
170- std:: fs:: remove_dir_all ( & temp_dir) ?;
171- let stderr = String :: from_utf8_lossy ( & archive. stderr ) ;
172- anyhow:: bail!( "git archive failed: {}" , stderr) ;
173- }
116+ // Use git archive for all repos (both local and remote use git clone now)
117+ let archive = Command :: new ( "git" )
118+ . args ( [ "archive" , "HEAD" ] )
119+ . current_dir ( sot_path)
120+ . output ( ) ?;
174121
175- // Extract with security flags to prevent path traversal
176- let mut extract = Command :: new ( "tar" )
177- . args ( [ "--no-absolute-file-names" , "-x" ] )
178- . current_dir ( & temp_dir)
179- . stdin ( std:: process:: Stdio :: piped ( ) )
180- . spawn ( ) ?;
181-
182- {
183- use std:: io:: Write ;
184- let stdin = extract
185- . stdin
186- . as_mut ( )
187- . context ( "Failed to open tar stdin" ) ?;
188- stdin. write_all ( & archive. stdout ) ?;
189- }
122+ if !archive. status . success ( ) {
123+ std:: fs:: remove_dir_all ( & temp_dir) ?;
124+ let stderr = String :: from_utf8_lossy ( & archive. stderr ) ;
125+ anyhow:: bail!( "git archive failed: {}" , stderr) ;
126+ }
190127
191- let status = extract . wait ( ) ? ;
192- if !status . success ( ) {
193- std :: fs :: remove_dir_all ( & temp_dir ) ? ;
194- anyhow :: bail! ( "tar extraction failed with exit code: {:?}" , status . code ( ) ) ;
195- }
196- } else {
197- // For non-git dirs (rsync'd local repos), use rsync
198- let output = Command :: new ( "rsync" )
199- . args ( [
200- "-a" ,
201- "--delete" ,
202- & format ! ( "{}/" , sot_str ) ,
203- temp_dir_str ,
204- ] )
205- . output ( ) ? ;
128+ // Extract with security flags to prevent path traversal
129+ let mut extract = Command :: new ( "tar" )
130+ . args ( [ "--no-absolute-file-names" , "-x" ] )
131+ . current_dir ( & temp_dir )
132+ . stdin ( std :: process :: Stdio :: piped ( ) )
133+ . spawn ( ) ? ;
134+
135+ {
136+ use std :: io :: Write ;
137+ let stdin = extract
138+ . stdin
139+ . as_mut ( )
140+ . context ( "Failed to open tar stdin" ) ? ;
141+ stdin . write_all ( & archive . stdout ) ? ;
142+ }
206143
207- if !output. status . success ( ) {
208- std:: fs:: remove_dir_all ( & temp_dir) ?;
209- let stderr = String :: from_utf8_lossy ( & output. stderr ) ;
210- anyhow:: bail!( "rsync failed: {}" , stderr) ;
211- }
144+ let status = extract. wait ( ) ?;
145+ if !status. success ( ) {
146+ std:: fs:: remove_dir_all ( & temp_dir) ?;
147+ anyhow:: bail!( "tar extraction failed with exit code: {:?}" , status. code( ) ) ;
212148 }
213149
214150 // Atomic swap: remove old, rename temp to target
215151 if job_dir. exists ( ) {
216152 std:: fs:: remove_dir_all ( job_dir) ?;
217153 }
218154 std:: fs:: rename ( & temp_dir, job_dir) . with_context ( || {
219- format ! (
220- "Failed to rename {} to {}" ,
221- temp_dir_str, job_dir_str
222- )
155+ format ! ( "Failed to rename {} to {}" , temp_dir_str, job_dir_str)
223156 } ) ?;
224157
225158 Ok ( ( ) )
@@ -229,14 +162,6 @@ pub fn sync_to_job_dir(sot_path: &Path, job_dir: &Path) -> Result<()> {
229162mod tests {
230163 use super :: * ;
231164
232- #[ test]
233- fn detect_remote_urls ( ) {
234- assert ! ( is_remote( "https://github.com/user/repo" ) ) ;
235- assert ! ( is_remote
( "[email protected] :user/repo.git" ) ) ; 236- assert ! ( !is_remote( "/home/user/repo" ) ) ;
237- assert ! ( !is_remote( "." ) ) ;
238- }
239-
240165 #[ test]
241166 fn cache_dir_from_url ( ) {
242167 let dir = get_cache_dir ( "https://github.com/user/myrepo.git" ) . unwrap ( ) ;
0 commit comments