@@ -48,7 +48,6 @@ use async_trait::async_trait;
4848use bellatrix:: Bellatrix ;
4949use bytes:: Bytes ;
5050use callisto:: {
51- entity_ext:: generate_link,
5251 mega_cl, mega_refs, mega_tag, mega_tree,
5352 sea_orm_active_enums:: { ConvTypeEnum , MergeStatusEnum , QueueFailureTypeEnum , QueueStatusEnum } ,
5453} ;
@@ -91,14 +90,14 @@ use crate::{
9190 ApiHandler , buck_tree_builder:: BuckCommitBuilder , cache:: GitObjectCache ,
9291 state:: ProtocolApiState , tree_ops,
9392 } ,
94- build_trigger :: BuildTriggerService ,
93+ code_edit :: { on_edit :: OneditCodeEdit , utils as edit_utils } ,
9594 model:: {
9695 buck:: {
9796 CompletePayload , CompleteResponse , DEFAULT_MODE , FileChange ,
9897 FileToUpload as ApiFileToUpload , ManifestPayload , ManifestResponse ,
9998 } ,
10099 change_list:: { ClDiffFile , UpdateBranchStatusRes } ,
101- git:: { CreateEntryInfo , EditCLMode , EditFilePayload , EditFileResult } ,
100+ git:: { CreateEntryInfo , EditFilePayload , EditFileResult } ,
102101 tag:: TagInfo ,
103102 third_party:: { ThirdPartyClient , ThirdPartyRepoTrait } ,
104103 } ,
@@ -376,6 +375,8 @@ impl ApiHandler for MonoApiService {
376375
377376 /// Save file edit in monorepo with optimistic concurrency check
378377 async fn save_file_edit ( & self , payload : EditFilePayload ) -> Result < EditFileResult , GitError > {
378+ let repo_path = "/" ;
379+ let src_commit = edit_utils:: get_repo_latest_commit ( & self . storage , repo_path) . await ?;
379380 let file_path = PathBuf :: from ( & payload. path ) ;
380381 let parent_path = file_path
381382 . parent ( )
@@ -414,12 +415,13 @@ impl ApiHandler for MonoApiService {
414415 . clone ( )
415416 . unwrap_or ( "Anonymous" . to_string ( ) ) ;
416417
417- let cl = self
418+ let editor = OneditCodeEdit :: from ( repo_path, & src_commit. id . to_string ( ) , & self ) ;
419+ let cl = editor
418420 . find_or_create_cl_for_edit (
421+ & self . storage ,
422+ & editor,
419423 payload. mode ,
420424 & new_commit_id,
421- & payload. commit_message ,
422- & payload. path ,
423425 & username,
424426 )
425427 . await ?;
@@ -429,13 +431,13 @@ impl ApiHandler for MonoApiService {
429431 . await ?;
430432
431433 if !payload. skip_build {
432- self . trigger_build_for_cl ( & cl . link ) . await ?;
434+ self . trigger_build_for_cl ( & editor , & cl , & username ) . await ?;
433435 }
434436
435437 Ok ( EditFileResult {
436438 commit_id : new_commit_id,
437439 new_oid : new_blob. id . to_string ( ) ,
438- path : payload . path ,
440+ path : repo_path . to_string ( ) ,
439441 cl_link : Some ( cl. link ) ,
440442 } )
441443 }
@@ -1057,127 +1059,24 @@ impl MonoApiService {
10571059 }
10581060 }
10591061
1060- async fn create_new_cl (
1062+ async fn trigger_build_for_cl (
10611063 & self ,
1062- repo_path : & str ,
1063- commit_message : & str ,
1064- to_hash : & str ,
1065- username : & str ,
1066- ) -> Result < mega_cl:: Model , GitError > {
1067- let cl_link = generate_link ( ) ;
1068-
1069- let from_hash = self
1070- . storage
1071- . mono_storage ( )
1072- . get_main_ref ( repo_path)
1073- . await ?
1074- . ok_or_else ( || MegaError :: Other ( "Main ref not found" . to_string ( ) ) ) ?
1075- . ref_commit_hash ;
1076-
1077- // Create and return a new CL model
1078- let cl = self
1079- . storage
1080- . cl_storage ( )
1081- . new_cl_model (
1082- repo_path,
1083- & cl_link,
1084- commit_message,
1085- & from_hash,
1086- to_hash,
1087- username,
1088- )
1089- . await
1090- . map_err ( |e| GitError :: CustomError ( format ! ( "Failed to create CL: {}" , e) ) ) ?;
1091-
1092- Ok ( cl)
1093- }
1094-
1095- /// Finds or creates a Change List (CL) for file edits.
1096- /// This method determines whether to create a new CL or reuse an existing one based on the
1097- /// [`EditCLMode`] passed in `mode`. For example, `EditCLMode::ForceCreate` will always create
1098- /// a new CL, while `EditCLMode::TryReuse` will attempt to find an open CL for the given user
1099- /// and path and only create a new one if none exists.
1100- ///
1101- /// # Arguments
1102- /// * `mode` - Controls whether to force creation of a new CL (`ForceCreate`) or try to reuse an
1103- /// existing open CL for the user and path when possible (`TryReuse`).
1104- /// * `to_hash` - The commit hash representing the new state after the edit.
1105- /// * `commit_message` - The message describing the changes made in the CL.
1106- /// * `file_path` - The path of the file being edited.
1107- /// * `username` - The username of the user performing the edit.
1108- ///
1109- /// # Returns
1110- /// A `Result` containing the `mega_cl::Model` representing the found or created CL on success,
1111- /// or a `GitError` on failure.
1112- async fn find_or_create_cl_for_edit (
1113- & self ,
1114- mode : EditCLMode ,
1115- to_hash : & str ,
1116- commit_message : & str ,
1117- file_path : & str ,
1064+ editor : & OneditCodeEdit ,
1065+ cl : & mega_cl:: Model ,
11181066 username : & str ,
1119- ) -> Result < mega_cl:: Model , GitError > {
1120- let path = PathBuf :: from ( file_path) ;
1121- let repo_path = path
1122- . parent ( )
1123- . map ( |p| p. to_string_lossy ( ) . to_string ( ) )
1124- . unwrap_or_else ( || "/" . to_string ( ) ) ;
1125-
1126- let storage = self . storage . cl_storage ( ) ;
1127- match mode {
1128- EditCLMode :: ForceCreate => {
1129- self . create_new_cl ( & repo_path, commit_message, to_hash, username)
1130- . await
1131- }
1132- EditCLMode :: TryReuse ( None ) => {
1133- if let Some ( existing_cl) =
1134- storage
1135- . get_open_cl_by_path ( & repo_path, username)
1136- . await
1137- . map_err ( |e| GitError :: CustomError ( format ! ( "Failed to fetch CL: {}" , e) ) ) ?
1138- {
1139- storage
1140- . update_cl_to_hash ( existing_cl. clone ( ) , to_hash)
1141- . await ?;
1142- Ok ( existing_cl)
1143- } else {
1144- self . create_new_cl ( & repo_path, commit_message, to_hash, username)
1145- . await
1146- }
1147- }
1148- EditCLMode :: TryReuse ( Some ( link) ) => {
1149- match self . storage . cl_storage ( ) . get_cl ( & link) . await {
1150- Ok ( Some ( model) ) => {
1151- storage. update_cl_to_hash ( model. clone ( ) , to_hash) . await ?;
1152- Ok ( model)
1153- }
1154- _ => {
1155- self . create_new_cl ( & repo_path, commit_message, to_hash, username)
1156- . await
1157- }
1158- }
1159- }
1160- }
1161- }
1162-
1163- /// Triggers a build for the specified CL in a background task.
1164- ///
1165- /// This is a best-effort operation: the build runs asynchronously to keep the API responsive,
1166- /// and any failures are logged but do not propagate to the caller.
1167- async fn trigger_build_for_cl ( & self , cl_link : & str ) -> Result < ( ) , GitError > {
1067+ ) -> Result < ( ) , GitError > {
11681068 let config = self . storage . config ( ) ;
1169- let bellatrix = Arc :: new ( Bellatrix :: new ( config. build . clone ( ) ) ) ;
1170- let storage = self . storage . clone ( ) ;
1069+ let bellatrix = Bellatrix :: new ( config. build . clone ( ) ) ;
11711070 let git_cache = self . git_object_cache . clone ( ) ;
1172- let cl_link = cl_link . to_string ( ) ;
1173-
1174- // Spawn a background task to handle the build process
1175- tokio :: spawn ( async move {
1176- let service = BuildTriggerService :: new ( storage , git_cache , bellatrix) ;
1177- if let Err ( e ) = service . trigger_for_cl ( & cl_link ) . await {
1178- tracing :: warn! ( "Build trigger failed for CL {}: {}" , cl_link , e ) ;
1179- }
1180- } ) ;
1071+ editor
1072+ . trigger_build_and_check (
1073+ self . storage . clone ( ) ,
1074+ git_cache ,
1075+ Arc :: new ( bellatrix) ,
1076+ cl ,
1077+ username ,
1078+ )
1079+ . await ? ;
11811080
11821081 Ok ( ( ) )
11831082 }
@@ -2064,8 +1963,7 @@ impl MonoApiService {
20641963 . map_err ( |e| GitError :: CustomError ( format ! ( "Failed to get new commit blobs: {e}" ) ) ) ?;
20651964
20661965 // calculate pages
2067- let sorted_changed_files = self
2068- . cl_files_list ( old_blobs. clone ( ) , new_blobs. clone ( ) )
1966+ let sorted_changed_files = edit_utils:: cl_files_list ( old_blobs. clone ( ) , new_blobs. clone ( ) )
20691967 . await
20701968 . map_err ( |e| GitError :: CustomError ( e. to_string ( ) ) ) ?;
20711969
@@ -2171,9 +2069,8 @@ impl MonoApiService {
21712069 let new_files = self . get_commit_blobs ( & cl. to_hash . clone ( ) ) . await ?;
21722070
21732071 // calculate pages
2174- let sorted_changed_files = self
2175- . cl_files_list ( old_files. clone ( ) , new_files. clone ( ) )
2176- . await ?;
2072+ let sorted_changed_files =
2073+ edit_utils:: cl_files_list ( old_files. clone ( ) , new_files. clone ( ) ) . await ?;
21772074 let file_paths: Vec < String > = sorted_changed_files
21782075 . iter ( )
21792076 . map ( |f| f. path ( ) . to_string_lossy ( ) . to_string ( ) )
@@ -2277,8 +2174,7 @@ impl MonoApiService {
22772174 . get_commit_blobs ( & cl. to_hash )
22782175 . await
22792176 . map_err ( |e| GitError :: CustomError ( e. to_string ( ) ) ) ?;
2280- let cl_changed = self
2281- . cl_files_list ( old_blobs. clone ( ) , new_blobs. clone ( ) )
2177+ let cl_changed = edit_utils:: cl_files_list ( old_blobs. clone ( ) , new_blobs. clone ( ) )
22822178 . await
22832179 . map_err ( |e| GitError :: CustomError ( e. to_string ( ) ) ) ?;
22842180
@@ -2370,17 +2266,15 @@ impl MonoApiService {
23702266 . get_commit_blobs ( & cl. to_hash )
23712267 . await
23722268 . map_err ( |e| GitError :: CustomError ( e. to_string ( ) ) ) ?;
2373- let cl_changed = self
2374- . cl_files_list ( old_blobs. clone ( ) , new_blobs. clone ( ) )
2269+ let cl_changed = edit_utils:: cl_files_list ( old_blobs. clone ( ) , new_blobs. clone ( ) )
23752270 . await
23762271 . map_err ( |e| GitError :: CustomError ( e. to_string ( ) ) ) ?;
23772272
23782273 let target_blobs = self
23792274 . get_commit_blobs ( target_head)
23802275 . await
23812276 . map_err ( |e| GitError :: CustomError ( e. to_string ( ) ) ) ?;
2382- let base_vs_target = self
2383- . cl_files_list ( old_blobs. clone ( ) , target_blobs. clone ( ) )
2277+ let base_vs_target = edit_utils:: cl_files_list ( old_blobs. clone ( ) , target_blobs. clone ( ) )
23842278 . await
23852279 . map_err ( |e| GitError :: CustomError ( e. to_string ( ) ) ) ?;
23862280
@@ -2401,34 +2295,7 @@ impl MonoApiService {
24012295 old_files : Vec < ( PathBuf , ObjectHash ) > ,
24022296 new_files : Vec < ( PathBuf , ObjectHash ) > ,
24032297 ) -> Result < Vec < ClDiffFile > , MegaError > {
2404- let old_files: HashMap < PathBuf , ObjectHash > = old_files. into_iter ( ) . collect ( ) ;
2405- let new_files: HashMap < PathBuf , ObjectHash > = new_files. into_iter ( ) . collect ( ) ;
2406- let unions: HashSet < PathBuf > = old_files. keys ( ) . chain ( new_files. keys ( ) ) . cloned ( ) . collect ( ) ;
2407- let mut res = vec ! [ ] ;
2408- for path in unions {
2409- let old_hash = old_files. get ( & path) ;
2410- let new_hash = new_files. get ( & path) ;
2411- match ( old_hash, new_hash) {
2412- ( None , None ) => { }
2413- ( None , Some ( new) ) => res. push ( ClDiffFile :: New ( path, * new) ) ,
2414- ( Some ( old) , None ) => res. push ( ClDiffFile :: Deleted ( path, * old) ) ,
2415- ( Some ( old) , Some ( new) ) => {
2416- if old == new {
2417- continue ;
2418- } else {
2419- res. push ( ClDiffFile :: Modified ( path, * old, * new) ) ;
2420- }
2421- }
2422- }
2423- }
2424-
2425- // Sort the results
2426- res. sort_by ( |a, b| {
2427- a. path ( )
2428- . cmp ( b. path ( ) )
2429- . then_with ( || a. kind_weight ( ) . cmp ( & b. kind_weight ( ) ) )
2430- } ) ;
2431- Ok ( res)
2298+ edit_utils:: cl_files_list ( old_files, new_files) . await
24322299 }
24332300
24342301 pub async fn get_commit_blobs (
0 commit comments