2929from uuid import UUID
3030
3131import httpx
32- import requests
3332from rich .console import Console
3433from tqdm import tqdm
3534
4544from kleinkram .errors import InvalidFileQuery
4645from kleinkram .errors import MissionNotFound
4746from kleinkram .errors import TemplateNotFound
47+ from kleinkram .models import ArtifactState
4848from kleinkram .models import FileState
4949from kleinkram .models import FileVerificationStatus
5050from kleinkram .printing import files_to_table
@@ -65,7 +65,8 @@ def download_artifact(
6565 * ,
6666 client : AuthenticatedClient ,
6767 execution_id : UUID ,
68- output : Optional [str ] = None ,
68+ output_dir : Optional [str ] = None ,
69+ filename : Optional [str ] = None ,
6970 extract : bool = False ,
7071 verbose : bool = False ,
7172) -> str :
@@ -74,7 +75,8 @@ def download_artifact(
7475
7576 Args:
7677 execution_id: The ID of the execution to download artifacts for.
77- output: Path or filename to save the artifacts to.
78+ output_dir: Directory to save the artifacts to (optional).
79+ filename: Custom filename for the downloaded artifact (optional, must end with .tar.gz).
7880 extract: Automatically extract the archive after downloading.
7981 verbose: Print progress and extraction info.
8082
@@ -85,52 +87,41 @@ def download_artifact(
8587 # Fetch Execution Details
8688 execution = kleinkram .api .routes .get_execution (client , execution_id = execution_id )
8789
90+ if execution .artifact_state == ArtifactState .EXPIRED :
91+ raise ValueError (f"Artifacts for execution { execution_id } have expired and therefore been deleted." )
92+
8893 if not execution .artifact_url :
94+ raise ValueError (f"No artifacts found for execution { execution_id } . The execution might not be finished yet." )
95+
96+ if not execution .artifact_size :
8997 raise ValueError (
90- f"No artifacts found for execution { execution_id } . The execution might not be finished or artifacts expired ."
98+ f"Artifact size is missing, empty, or corrupted for execution { execution_id } , cannot proceed with download ."
9199 )
92100
93101 if verbose :
94102 print (f"Downloading artifacts for execution { execution_id } ..." )
95103
96- # Grab the headers to determine filename and size
97- try :
98- with requests .get (execution .artifact_url , stream = True ) as r :
99- r .raise_for_status ()
100- headers = r .headers .copy ()
101- except requests .exceptions .RequestException as e :
102- raise ValueError (f"Error fetching artifact headers: { e } " )
103-
104- # Determine Filename
105- filename = output
106- if not filename :
107- filename = kleinkram .api .file_transfer ._get_filename_from_cd (headers .get ("content-disposition" ))
104+ if filename :
105+ if not filename .endswith (".tar.gz" ):
106+ raise ValueError (f"Filename must end with .tar.gz, got: { filename } " )
108107
109108 if not filename :
110- filename = f"{ execution_id } .tar.gz"
109+ filename = f"{ execution . template_name } - { execution_id } .tar.gz"
111110
112- # If output is a directory, join with filename
113- if output and os .path .isdir (output ):
114- filename = os .path .join (
115- output ,
116- kleinkram .api .file_transfer ._get_filename_from_cd (headers .get ("content-disposition" )) or f"{ execution_id } .tar.gz" ,
117- )
111+ if output_dir and not os .path .isdir (output_dir ):
112+ raise ValueError (f"Output directory { output_dir } does not exist or is not a directory." )
118113
119- total_length_raw = headers .get ("content-length" )
120- if total_length_raw is None :
121- raise ValueError (
122- f"Cannot determine artifact size for execution { execution_id } : "
123- "the server did not return a content-length header."
124- )
125- total_length = int (total_length_raw )
114+ filepath = Path (os .path .join (output_dir , filename ) if output_dir else filename )
126115
127- filepath = Path (filename )
116+ if verbose :
117+ print (f"Artifact size: { execution .artifact_size } bytes" )
118+ print (f"Saving artifact to: { filepath } ..." )
128119
129120 # Download the file using _url_download
130121 kleinkram .api .file_transfer ._url_download (
131122 url = execution .artifact_url ,
132123 path = filepath ,
133- size = total_length ,
124+ size = execution . artifact_size ,
134125 overwrite = True , # overwrite if we run the CLI command directly
135126 verbose = verbose ,
136127 )
0 commit comments