@@ -555,7 +555,7 @@ def Restore(
555555 )
556556 return
557557
558- with _YieldTempDirectory ("staging content" ) as staging_directory :
558+ with _YieldTempDirectory (working_dir / "staging" , "staging content" ) as staging_directory :
559559 # ----------------------------------------------------------------------
560560 @dataclass (frozen = True )
561561 class Instruction :
@@ -709,26 +709,38 @@ def PrepareTask(
709709 def ExecuteTask (
710710 status : ExecuteTasks .Status ,
711711 ) -> Path :
712- destination_dir = working_dir / directory
713-
714- if destination_dir .is_dir ():
712+ # This function will create the following directory structure:
713+ #
714+ # <working_dir>
715+ # └── <directory>
716+ # └── transferred (temporary)
717+ # └── decompressed (temporary)
718+ # └── final
719+
720+ assert working_dir is not None
721+ this_working_dir = working_dir / directory
722+ final_dir = this_working_dir / "final"
723+
724+ if final_dir .is_dir ():
715725 # The destination already exists, no need to process it further
716- return destination_dir
726+ return final_dir
717727
718- with _YieldRestoredArchive (
728+ with _YieldTransferredArchive (
719729 data_store , # type: ignore
720730 directory ,
731+ this_working_dir / "transferred" ,
721732 lambda bytes_transferred : cast (
722733 None ,
723734 status .OnProgress (
724735 ProcessDirectoryState .Transferring .value + 1 ,
725736 bytes_transferred ,
726737 ),
727738 ),
728- ) as (archive_directory , archive_directory_is_temporary ):
729- with _YieldRestoredFiles (
739+ ) as (transferred_dir , transferred_dir_is_temporary ):
740+ with _YieldDecompressedFiles (
741+ transferred_dir ,
742+ this_working_dir / "decompressed" ,
730743 directory ,
731- archive_directory ,
732744 encryption_password ,
733745 lambda message : cast (
734746 None ,
@@ -737,11 +749,11 @@ def ExecuteTask(
737749 message ,
738750 ),
739751 ),
740- ) as (contents_dir , contents_dir_is_temporary ):
752+ ) as (decompressed_dir , decompressed_dir_is_temporary ):
741753 # Validate the contents
742- _VerifyRestoredFiles (
754+ _VerifyFiles (
743755 directory ,
744- contents_dir ,
756+ decompressed_dir ,
745757 lambda message : cast (
746758 None ,
747759 status .OnProgress (
@@ -755,7 +767,7 @@ def ExecuteTask(
755767 # directory structure and doesn't do anything to account for
756768 # nested dirs. This assumption matches the current archive
757769 # format.
758- if archive_directory_is_temporary or contents_dir_is_temporary :
770+ if transferred_dir_is_temporary or decompressed_dir_is_temporary :
759771 func = cast (Callable [[Path , Path ], None ], shutil .move )
760772 else :
761773 # ----------------------------------------------------------------------
@@ -770,14 +782,14 @@ def CreateSymLink(
770782
771783 func = CreateSymLink
772784
773- temp_dest_dir = destination_dir .parent / (destination_dir .name + "__temp__" )
785+ temp_dest_dir = final_dir .parent / (final_dir .name + "__temp__" )
774786
775787 shutil .rmtree (temp_dest_dir , ignore_errors = True )
776788 temp_dest_dir .mkdir (parents = True )
777789
778790 items = [
779791 item
780- for item in contents_dir .iterdir ()
792+ for item in decompressed_dir .iterdir ()
781793 if item .name != INDEX_HASH_FILENAME
782794 ]
783795
@@ -789,9 +801,9 @@ def CreateSymLink(
789801
790802 func (item , temp_dest_dir )
791803
792- shutil .move (temp_dest_dir , destination_dir )
804+ shutil .move (temp_dest_dir , final_dir )
793805
794- return destination_dir
806+ return final_dir
795807
796808 # ----------------------------------------------------------------------
797809
@@ -960,7 +972,8 @@ def PathToFilename(
960972 with dm .Nested ("\n Processing instructions..." ) as all_instructions_dm :
961973 all_instructions_dm .WriteLine ("" )
962974
963- temp_directory = PathEx .CreateTempDirectory ()
975+ temp_directory = working_dir / "instructions"
976+ temp_directory .mkdir (parents = True , exist_ok = True )
964977
965978 with ExitStack (lambda : shutil .rmtree (temp_directory )):
966979 commit_actions : list [Callable [[], None ]] = []
@@ -1287,9 +1300,9 @@ def CommitContext(
12871300# ----------------------------------------------------------------------
12881301@contextmanager
12891302def _YieldTempDirectory (
1303+ temp_directory : Path ,
12901304 desc : str ,
12911305) -> Iterator [Path ]:
1292- temp_directory = PathEx .CreateTempDirectory ()
12931306 should_delete = True
12941307
12951308 try :
@@ -1299,7 +1312,8 @@ def _YieldTempDirectory(
12991312 raise
13001313 finally :
13011314 if should_delete :
1302- shutil .rmtree (temp_directory )
1315+ if temp_directory .is_dir ():
1316+ shutil .rmtree (temp_directory )
13031317 else :
13041318 sys .stderr .write (
13051319 f"**** The temporary directory '{ temp_directory } ' was preserved due to errors while { desc } .\n " ,
@@ -1308,16 +1322,19 @@ def _YieldTempDirectory(
13081322
13091323# ----------------------------------------------------------------------
13101324@contextmanager
1311- def _YieldRestoredArchive (
1325+ def _YieldTransferredArchive (
13121326 data_store : FileBasedDataStore ,
13131327 directory : str ,
1328+ working_dir : Path ,
13141329 status_func : Callable [[str ], None ],
13151330) -> Iterator [
13161331 tuple [
13171332 Path ,
13181333 bool , # is temporary directory
13191334 ],
13201335]:
1336+ """Transfer content from the data store to the local filesystem."""
1337+
13211338 if data_store .is_local_filesystem :
13221339 working_dir = data_store .GetWorkingDir () / directory
13231340 assert working_dir .is_dir (), working_dir
@@ -1327,7 +1344,7 @@ def _YieldRestoredArchive(
13271344
13281345 status_func ("Calculating files to transfer..." )
13291346
1330- with _YieldTempDirectory ("transferring archive files" ) as temp_directory :
1347+ with _YieldTempDirectory (working_dir , "transferring archive files" ) as working_dir :
13311348 # Map the remote filenames to local filenames
13321349 filename_map : dict [Path , Path ] = {}
13331350
@@ -1339,7 +1356,7 @@ def _YieldRestoredArchive(
13391356 relative_root = root .relative_to (data_store_dir )
13401357
13411358 for filename in filenames :
1342- filename_map [root / filename ] = temp_directory / relative_root / filename
1359+ filename_map [root / filename ] = working_dir / relative_root / filename
13431360
13441361 if not filename_map :
13451362 raise Exception (f"The directory '{ directory } ' does not contain any files." )
@@ -1359,14 +1376,15 @@ def _YieldRestoredArchive(
13591376 ),
13601377 )
13611378
1362- yield temp_directory , True
1379+ yield working_dir , True
13631380
13641381
13651382# ----------------------------------------------------------------------
13661383@contextmanager
1367- def _YieldRestoredFiles (
1384+ def _YieldDecompressedFiles (
1385+ transferred_dir : Path ,
1386+ decompressed_dir : Path ,
13681387 directory_name : str ,
1369- archive_dir : Path ,
13701388 encryption_password : str | None ,
13711389 status_func : Callable [[str ], None ],
13721390) -> Iterator [
@@ -1375,8 +1393,10 @@ def _YieldRestoredFiles(
13751393 bool , # is temporary directory
13761394 ],
13771395]:
1378- if (archive_dir / INDEX_FILENAME ).is_file ():
1379- yield archive_dir , False
1396+ """Decompress the archive if necessary"""
1397+
1398+ if (transferred_dir / INDEX_FILENAME ).is_file ():
1399+ yield transferred_dir , False
13801400 return
13811401
13821402 # By default, 7zip will prompt for a password with archives that were created
@@ -1394,7 +1414,7 @@ def _YieldRestoredFiles(
13941414 # Validate
13951415 status_func ("Validating archive..." )
13961416
1397- archive_filename = archive_dir / (ARCHIVE_FILENAME + ".001" )
1417+ archive_filename = transferred_dir / (ARCHIVE_FILENAME + ".001" )
13981418
13991419 if not archive_filename .is_file ():
14001420 raise Exception (f"The archive file '{ archive_filename .name } ' was not found." )
@@ -1424,10 +1444,12 @@ def _YieldRestoredFiles(
14241444 # Extract
14251445 status_func ("Extracting archive..." )
14261446
1427- with _YieldTempDirectory ("extracting the archive" ) as temp_directory :
1447+ with _YieldTempDirectory (decompressed_dir , "extracting the archive" ) as decompressed_dir :
1448+ decompressed_dir .mkdir (parents = True , exist_ok = True )
1449+
14281450 result = SubprocessEx .Run (
14291451 f'{ _GetZipBinary ()} x "{ archive_filename } " "-p{ password } "' ,
1430- cwd = temp_directory ,
1452+ cwd = decompressed_dir ,
14311453 )
14321454
14331455 if result .returncode != 0 :
@@ -1450,11 +1472,11 @@ def _YieldRestoredFiles(
14501472 ),
14511473 )
14521474
1453- yield temp_directory , True
1475+ yield decompressed_dir , True
14541476
14551477
14561478# ----------------------------------------------------------------------
1457- def _VerifyRestoredFiles (
1479+ def _VerifyFiles (
14581480 directory_name : str ,
14591481 contents_dir : Path ,
14601482 status_func : Callable [[str ], None ],
0 commit comments