@@ -12,6 +12,7 @@ use std::{
1212
1313use anyhow:: { Context , Error , Result , anyhow} ;
1414use chrono:: TimeZone ;
15+ use futures_util:: TryStreamExt ;
1516use itertools:: Itertools ;
1617use jj_cli:: {
1718 cli_util:: { default_ignored_remote_name, short_operation_hash} ,
@@ -38,7 +39,7 @@ use jj_lib::{
3839 repo_path:: { RepoPath , RepoPathUiConverter } ,
3940 revset:: {
4041 self , Revset , RevsetAliasesMap , RevsetDiagnostics , RevsetEvaluationError , RevsetExpression ,
41- RevsetExtensions , RevsetIteratorExt , RevsetParseContext , RevsetResolutionError ,
42+ RevsetExtensions , RevsetParseContext , RevsetResolutionError , RevsetStreamExt ,
4243 RevsetWorkspaceContext , SymbolResolverExtension , UserRevsetExpression ,
4344 } ,
4445 rewrite,
@@ -49,6 +50,7 @@ use jj_lib::{
4950 workspace:: { self , DefaultWorkspaceLoaderFactory , Workspace , WorkspaceLoaderFactory } ,
5051 workspace_store:: { SimpleWorkspaceStore , WorkspaceStore as _} ,
5152} ;
53+ use pollster:: FutureExt as _;
5254use thiserror:: Error ;
5355
5456use super :: { WorkerSession , git_util:: get_git_remote_names} ;
@@ -276,7 +278,7 @@ impl WorkspaceSession<'_> {
276278 let repo_path = self . workspace . repo_path ( ) . to_owned ( ) ;
277279 let is_colocated = self . is_colocated ;
278280
279- let mut locked_ws = self . workspace . start_working_copy_mutation ( ) ?;
281+ let mut locked_ws = self . workspace . start_working_copy_mutation ( ) . await ?;
280282
281283 locked_ws. locked_wc ( ) . rename_workspace ( new_name. clone ( ) ) ;
282284 tx. repo_mut ( )
@@ -299,7 +301,9 @@ impl WorkspaceSession<'_> {
299301 ) )
300302 . await ?,
301303 ) ;
302- locked_ws. finish ( self . operation . repo . op_id ( ) . clone ( ) ) ?;
304+ locked_ws
305+ . finish ( self . operation . repo . op_id ( ) . clone ( ) )
306+ . await ?;
303307
304308 Ok ( Some ( self . format_status ( ) ) )
305309 }
@@ -407,13 +411,12 @@ impl WorkspaceSession<'_> {
407411 & ' op self ,
408412 revset : T ,
409413 ) -> Result < Option < Commit > , RevsetError > {
410- let mut iter = revset
411- . as_ref ( )
412- . iter ( )
413- . commits ( self . operation . repo . store ( ) )
414- . fuse ( ) ;
415- match ( iter. next ( ) , iter. next ( ) ) {
416- ( Some ( commit) , None ) => Ok ( Some ( commit?) ) ,
414+ let store = self . operation . repo . store ( ) ;
415+ let mut stream = revset. as_ref ( ) . stream ( ) . commits ( store) ;
416+ let first = stream. try_next ( ) . block_on ( ) ?;
417+ let second = stream. try_next ( ) . block_on ( ) ?;
418+ match ( first, second) {
419+ ( Some ( commit) , None ) => Ok ( Some ( commit) ) ,
417420 ( None , _) => Ok ( None ) ,
418421 ( Some ( _) , Some ( _) ) => Err ( RevsetError :: Other ( anyhow ! (
419422 r#"Revset "{:?}" resolved to more than one revision"# ,
@@ -452,23 +455,18 @@ impl WorkspaceSession<'_> {
452455 Err ( err) => return Err ( err) ,
453456 } ;
454457
455- let mut change_iter = change_revset
456- . as_ref ( )
457- . iter ( )
458- . commits ( self . operation . repo . store ( ) )
459- . fuse ( ) ;
460- match ( change_iter. next ( ) , change_iter. next ( ) ) {
461- ( Some ( commit) , None ) => Ok ( Some ( commit?) ) ,
458+ let store = self . operation . repo . store ( ) ;
459+ let mut change_stream = change_revset. as_ref ( ) . stream ( ) . commits ( store) ;
460+ let first = change_stream. try_next ( ) . block_on ( ) ?;
461+ let second = change_stream. try_next ( ) . block_on ( ) ?;
462+ match ( first, second) {
463+ ( Some ( commit) , None ) => Ok ( Some ( commit) ) ,
462464 ( None , _) => Ok ( None ) ,
463465 ( Some ( _) , Some ( _) ) => {
464466 let commit_revset = self . evaluate_revset_commits ( slice:: from_ref ( & id. commit ) ) ?;
465- let mut commit_iter = commit_revset
466- . as_ref ( )
467- . iter ( )
468- . commits ( self . operation . repo . store ( ) )
469- . fuse ( ) ;
470- match commit_iter. next ( ) {
471- Some ( commit) => Ok ( Some ( commit?) ) ,
467+ let mut commit_stream = commit_revset. as_ref ( ) . stream ( ) . commits ( store) ;
468+ match commit_stream. try_next ( ) . block_on ( ) ? {
469+ Some ( commit) => Ok ( Some ( commit) ) ,
472470 None => Ok ( None ) ,
473471 }
474472 }
@@ -507,13 +505,12 @@ impl WorkspaceSession<'_> {
507505 pub ( crate ) fn resolve_change_id ( & self , id : & RevId ) -> Result < Commit , RevsetError > {
508506 let id_str = Self :: format_id_str ( id) ;
509507 let revset = self . evaluate_revset_str ( & id_str) ?;
510- let mut iter = revset
511- . as_ref ( )
512- . iter ( )
513- . commits ( self . operation . repo . store ( ) )
514- . fuse ( ) ;
515- let optional_change = match ( iter. next ( ) , iter. next ( ) ) {
516- ( Some ( commit) , None ) => Some ( commit?) ,
508+ let store = self . operation . repo . store ( ) ;
509+ let mut stream = revset. as_ref ( ) . stream ( ) . commits ( store) ;
510+ let first = stream. try_next ( ) . block_on ( ) ?;
511+ let second = stream. try_next ( ) . block_on ( ) ?;
512+ let optional_change = match ( first, second) {
513+ ( Some ( commit) , None ) => Some ( commit) ,
517514 ( None , _) => None ,
518515 ( Some ( _) , Some ( _) ) => Some ( self . resolve_commit_id ( & id. commit ) ?) ,
519516 } ;
@@ -578,11 +575,14 @@ impl WorkspaceSession<'_> {
578575 & ' op self ,
579576 revset : T ,
580577 ) -> Result < Vec < Commit > , RevsetError > {
581- let commits = revset
578+ let store = self . operation . repo . store ( ) ;
579+ let commits: Vec < Commit > = revset
582580 . as_ref ( )
583- . iter ( )
584- . commits ( self . operation . repo . store ( ) )
585- . collect :: < Result < Vec < Commit > , RevsetEvaluationError > > ( ) ?;
581+ . stream ( )
582+ . commits ( store)
583+ . try_collect ( )
584+ . block_on ( )
585+ . map_err ( RevsetError :: from) ?;
586586 Ok ( commits)
587587 }
588588
@@ -850,9 +850,7 @@ impl WorkspaceSession<'_> {
850850 let intersection_revset = check_revset. intersection ( & immutable_revset) ;
851851
852852 let immutable_revs = self . evaluate_revset_expr ( repo, intersection_revset) ?;
853- let first = immutable_revs. iter ( ) . next ( ) ;
854-
855- Ok ( first. is_some ( ) )
853+ Ok ( !immutable_revs. is_empty ( ) )
856854 }
857855
858856 /// checks if any commit in an iterator is immutable
@@ -866,8 +864,9 @@ impl WorkspaceSession<'_> {
866864 pub ( crate ) fn check_immutable_revset ( & self , revset : & dyn Revset ) -> Result < bool > {
867865 let immutable_revset = self . evaluate_immutable ( ) ?;
868866 let contains = immutable_revset. containing_fn ( ) ;
869- for id in revset. iter ( ) {
870- if contains ( & id?) ? {
867+ let mut stream = revset. stream ( ) ;
868+ while let Some ( id) = stream. try_next ( ) . block_on ( ) ? {
869+ if contains ( & id) ? {
871870 return Ok ( true ) ;
872871 }
873872 }
@@ -946,7 +945,7 @@ impl WorkspaceSession<'_> {
946945 . transpose ( ) ?;
947946 if self . is_colocated {
948947 if let Some ( wc_commit) = & maybe_new_wc_commit {
949- git:: reset_head ( tx. repo_mut ( ) , wc_commit) ?;
948+ git:: reset_head ( tx. repo_mut ( ) , wc_commit) . await ?;
950949 }
951950 git:: export_refs ( tx. repo_mut ( ) ) ?;
952951 }
@@ -1008,13 +1007,15 @@ impl WorkspaceSession<'_> {
10081007 . base_ignores ( self . workspace . workspace_root ( ) ) ?;
10091008
10101009 // Compare working-copy tree and operation with repo's, and reload as needed.
1011- let mut locked_ws = self . workspace . start_working_copy_mutation ( ) ?;
1010+ let mut locked_ws = self . workspace . start_working_copy_mutation ( ) . await ?;
10121011 let old_op_id = locked_ws. locked_wc ( ) . old_operation_id ( ) . clone ( ) ;
10131012 let ( repo, wc_commit) = match WorkingCopyFreshness :: check_stale (
10141013 locked_ws. locked_wc ( ) ,
10151014 & wc_commit,
10161015 & repo,
1017- ) ? {
1016+ )
1017+ . await ?
1018+ {
10181019 WorkingCopyFreshness :: Fresh => ( repo, wc_commit) ,
10191020 WorkingCopyFreshness :: Updated ( wc_operation) => {
10201021 let repo = repo. reload_at ( & wc_operation) . await ?;
@@ -1053,7 +1054,7 @@ impl WorkspaceSession<'_> {
10531054 self . workspace
10541055 . check_out ( repo. op_id ( ) . clone ( ) , old_tree. as_ref ( ) , & new_wc_commit)
10551056 . await ?;
1056- locked_ws = self . workspace . start_working_copy_mutation ( ) ?;
1057+ locked_ws = self . workspace . start_working_copy_mutation ( ) . await ?;
10571058
10581059 ( repo, new_wc_commit)
10591060 }
@@ -1110,7 +1111,9 @@ impl WorkspaceSession<'_> {
11101111 ) ;
11111112 }
11121113
1113- locked_ws. finish ( self . operation . repo . op_id ( ) . clone ( ) ) ?;
1114+ locked_ws
1115+ . finish ( self . operation . repo . op_id ( ) . clone ( ) )
1116+ . await ?;
11141117
11151118 Ok ( did_anything)
11161119 }
@@ -1134,16 +1137,18 @@ impl WorkspaceSession<'_> {
11341137 . await ?,
11351138 )
11361139 } else {
1137- let locked_ws = self . workspace . start_working_copy_mutation ( ) ?;
1138- locked_ws. finish ( self . operation . repo . op_id ( ) . clone ( ) ) ?;
1140+ let locked_ws = self . workspace . start_working_copy_mutation ( ) . await ?;
1141+ locked_ws
1142+ . finish ( self . operation . repo . op_id ( ) . clone ( ) )
1143+ . await ?;
11391144 None
11401145 } ,
11411146 )
11421147 }
11431148
11441149 async fn import_git_head ( & mut self ) -> Result < ( ) > {
11451150 let mut tx = self . operation . repo . start_transaction ( ) ;
1146- git:: import_head ( tx. repo_mut ( ) ) ?;
1151+ git:: import_head ( tx. repo_mut ( ) ) . await ?;
11471152 if !tx. repo ( ) . has_changes ( ) {
11481153 return Ok ( ( ) ) ;
11491154 }
@@ -1164,7 +1169,7 @@ impl WorkspaceSession<'_> {
11641169 . check_out ( workspace_name. clone ( ) , & new_git_head_commit)
11651170 . await ?;
11661171
1167- let mut locked_ws = self . workspace . start_working_copy_mutation ( ) ?;
1172+ let mut locked_ws = self . workspace . start_working_copy_mutation ( ) . await ?;
11681173
11691174 locked_ws. locked_wc ( ) . reset ( & new_git_head_commit) . await ?;
11701175 tx. repo_mut ( ) . rebase_descendants ( ) . await ?;
@@ -1175,7 +1180,9 @@ impl WorkspaceSession<'_> {
11751180 tx. commit ( "import git head" ) . await ?,
11761181 ) ;
11771182
1178- locked_ws. finish ( self . operation . repo . op_id ( ) . clone ( ) ) ?;
1183+ locked_ws
1184+ . finish ( self . operation . repo . op_id ( ) . clone ( ) )
1185+ . await ?;
11791186 } else {
11801187 self . finish_transaction ( tx, "import git head" ) . await ?;
11811188 }
@@ -1189,6 +1196,7 @@ impl WorkspaceSession<'_> {
11891196 . map_err ( |e| Error :: new ( e. error ) ) ?;
11901197 let mut tx = self . operation . repo . start_transaction ( ) ;
11911198 let stats = git:: import_refs ( tx. repo_mut ( ) , & import_options)
1199+ . await
11921200 . context ( "automated import failed despite reserved remote name" ) ?;
11931201 if !tx. repo ( ) . has_changes ( ) {
11941202 return Ok ( ( ) ) ;
@@ -1319,14 +1327,16 @@ impl OperationData {
13191327 if let Some ( excludes_file_path) =
13201328 get_excludes_file_path ( git_repo. config_snapshot ( ) . plumbing ( ) )
13211329 {
1322- git_ignores = git_ignores. chain_with_file ( "" , excludes_file_path) ?;
1330+ git_ignores = git_ignores. chain_with_file ( RepoPath :: root ( ) , excludes_file_path) ?;
13231331 }
1324- git_ignores = git_ignores
1325- . chain_with_file ( "" , git_backend. git_repo_path ( ) . join ( "info" ) . join ( "exclude" ) ) ?;
1332+ git_ignores = git_ignores. chain_with_file (
1333+ RepoPath :: root ( ) ,
1334+ git_backend. git_repo_path ( ) . join ( "info" ) . join ( "exclude" ) ,
1335+ ) ?;
13261336 } else if let Ok ( git_config) = gix:: config:: File :: from_globals ( )
13271337 && let Some ( excludes_file_path) = get_excludes_file_path ( & git_config)
13281338 {
1329- git_ignores = git_ignores. chain_with_file ( "" , excludes_file_path) ?;
1339+ git_ignores = git_ignores. chain_with_file ( RepoPath :: root ( ) , excludes_file_path) ?;
13301340 }
13311341 Ok ( git_ignores)
13321342 }
0 commit comments