Skip to content

Commit 28e5f7d

Browse files
authored
Merge pull request #19154 from kysrpex/file_sources_assign_paths
Let file sources choose a path for uploaded files
2 parents 42bf463 + 3b1516c commit 28e5f7d

File tree

10 files changed

+170
-130
lines changed

10 files changed

+170
-130
lines changed

client/src/api/schema/schema.ts

+2
Original file line numberDiff line numberDiff line change
@@ -8935,6 +8935,8 @@ export interface components {
89358935
error?: string | null;
89368936
/** Success */
89378937
success: boolean;
8938+
/** Uri */
8939+
uri?: string | null;
89388940
};
89398941
/**
89408942
* ExportObjectType

client/src/components/Common/models/exportRecordModel.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { formatDistanceToNow, parseISO } from "date-fns";
22

33
import {
44
type ExportObjectRequestMetadata,
5+
type ExportObjectResultMetadata,
56
type ModelStoreFormat,
67
type ObjectExportTaskResponse,
78
type StoreExportPayload,
@@ -85,12 +86,14 @@ export class ExportRecordModel implements ExportRecord {
8586
private _data: ObjectExportTaskResponse;
8687
private _expirationDate?: Date;
8788
private _requestMetadata?: ExportObjectRequestMetadata;
89+
private _resultMetadata?: ExportObjectResultMetadata | null;
8890
private _exportParameters?: ExportParamsModel;
8991

9092
constructor(data: ObjectExportTaskResponse) {
9193
this._data = data;
9294
this._expirationDate = undefined;
9395
this._requestMetadata = data.export_metadata?.request_data;
96+
this._resultMetadata = data.export_metadata?.result_data;
9497
this._exportParameters = this._requestMetadata?.payload
9598
? new ExportParamsModel(this._requestMetadata?.payload)
9699
: undefined;
@@ -130,7 +133,9 @@ export class ExportRecordModel implements ExportRecord {
130133

131134
get importUri() {
132135
const payload = this._requestMetadata?.payload;
133-
return payload && "target_uri" in payload ? payload.target_uri : undefined;
136+
const requestUri = payload && "target_uri" in payload ? payload.target_uri : undefined;
137+
const resultUri = this._resultMetadata?.uri;
138+
return resultUri || requestUri;
134139
}
135140

136141
get canReimport() {

lib/galaxy/files/sources/__init__.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ def write_from(
220220
native_path: str,
221221
user_context: "OptionalUserContext" = None,
222222
opts: Optional[FilesSourceOptions] = None,
223-
):
223+
) -> str:
224224
"""Write file at native path to target_path (relative to uri root).
225225
226226
:param target_path: url of the target file to write to within the filesource. e.g. `gxfiles://myftp1/myfile.txt`
@@ -231,6 +231,9 @@ def write_from(
231231
:type user_context: _type_, optional
232232
:param opts: A set of options to exercise additional control over the write_from method. Filesource specific, defaults to None
233233
:type opts: Optional[FilesSourceOptions], optional
234+
:return: Actual url of the written file, fixed by the service backing the FileSource. May differ from the target
235+
path.
236+
:rtype: str
234237
"""
235238

236239
@abc.abstractmethod
@@ -511,10 +514,10 @@ def write_from(
511514
native_path: str,
512515
user_context: "OptionalUserContext" = None,
513516
opts: Optional[FilesSourceOptions] = None,
514-
):
517+
) -> str:
515518
self._ensure_writeable()
516519
self._check_user_access(user_context)
517-
self._write_from(target_path, native_path, user_context=user_context, opts=opts)
520+
return self._write_from(target_path, native_path, user_context=user_context, opts=opts) or target_path
518521

519522
@abc.abstractmethod
520523
def _write_from(
@@ -523,7 +526,7 @@ def _write_from(
523526
native_path: str,
524527
user_context: "OptionalUserContext" = None,
525528
opts: Optional[FilesSourceOptions] = None,
526-
):
529+
) -> Optional[str]:
527530
pass
528531

529532
def realize_to(

lib/galaxy/managers/model_stores.py

+42-18
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ def prepare_history_download(self, request: GenerateHistoryDownload):
114114
include_hidden = request.include_hidden
115115
include_deleted = request.include_deleted
116116
export_metadata = self.set_history_export_request_metadata(request)
117+
118+
exception_exporting_history: Optional[Exception] = None
117119
try:
118120
with storage_context(
119121
request.short_term_storage_request_id, self._short_term_storage_monitor
@@ -122,12 +124,16 @@ def prepare_history_download(self, request: GenerateHistoryDownload):
122124
short_term_storage_target.path
123125
) as export_store:
124126
export_store.export_history(history, include_hidden=include_hidden, include_deleted=include_deleted)
125-
self.set_history_export_result_metadata(request.export_association_id, export_metadata, success=True)
126-
except Exception as e:
127+
except Exception as exception:
128+
exception_exporting_history = exception
129+
raise
130+
finally:
127131
self.set_history_export_result_metadata(
128-
request.export_association_id, export_metadata, success=False, error=str(e)
132+
request.export_association_id,
133+
export_metadata,
134+
success=not bool(exception_exporting_history),
135+
error=str(exception_exporting_history) if exception_exporting_history else None,
129136
)
130-
raise
131137

132138
def prepare_history_content_download(self, request: GenerateHistoryContentDownload):
133139
model_store_format = request.model_store_format
@@ -140,11 +146,13 @@ def prepare_history_content_download(self, request: GenerateHistoryContentDownlo
140146
) as export_store:
141147
if request.content_type == HistoryContentType.dataset:
142148
hda = self._sa_session.get(model.HistoryDatasetAssociation, request.content_id)
143-
export_store.add_dataset(hda)
149+
export_store.add_dataset(hda) # type: ignore[arg-type]
144150
else:
145151
hdca = self._sa_session.get(model.HistoryDatasetCollectionAssociation, request.content_id)
146152
export_store.export_collection(
147-
hdca, include_hidden=request.include_hidden, include_deleted=request.include_deleted
153+
hdca, # type: ignore[arg-type]
154+
include_hidden=request.include_hidden,
155+
include_deleted=request.include_deleted,
148156
)
149157

150158
def prepare_invocation_download(self, request: GenerateInvocationDownload):
@@ -161,7 +169,9 @@ def prepare_invocation_download(self, request: GenerateInvocationDownload):
161169
)(short_term_storage_target.path) as export_store:
162170
invocation = self._sa_session.get(model.WorkflowInvocation, request.invocation_id)
163171
export_store.export_workflow_invocation(
164-
invocation, include_hidden=request.include_hidden, include_deleted=request.include_deleted
172+
invocation, # type: ignore[arg-type]
173+
include_hidden=request.include_hidden,
174+
include_deleted=request.include_deleted,
165175
)
166176

167177
def write_invocation_to(self, request: WriteInvocationTo):
@@ -178,7 +188,9 @@ def write_invocation_to(self, request: WriteInvocationTo):
178188
)(target_uri) as export_store:
179189
invocation = self._sa_session.get(model.WorkflowInvocation, request.invocation_id)
180190
export_store.export_workflow_invocation(
181-
invocation, include_hidden=request.include_hidden, include_deleted=request.include_deleted
191+
invocation, # type: ignore[arg-type]
192+
include_hidden=request.include_hidden,
193+
include_deleted=request.include_deleted,
182194
)
183195

184196
def _bco_export_options(self, request: BcoGenerationTaskParametersMixin):
@@ -202,33 +214,44 @@ def write_history_content_to(self, request: WriteHistoryContentTo):
202214
)(target_uri) as export_store:
203215
if request.content_type == HistoryContentType.dataset:
204216
hda = self._sa_session.get(model.HistoryDatasetAssociation, request.content_id)
205-
export_store.add_dataset(hda)
217+
export_store.add_dataset(hda) # type: ignore[arg-type]
206218
else:
207219
hdca = self._sa_session.get(model.HistoryDatasetCollectionAssociation, request.content_id)
208220
export_store.export_collection(
209-
hdca, include_hidden=request.include_hidden, include_deleted=request.include_deleted
221+
hdca, # type: ignore[arg-type]
222+
include_hidden=request.include_hidden,
223+
include_deleted=request.include_deleted,
210224
)
211225

212226
def write_history_to(self, request: WriteHistoryTo):
213227
model_store_format = request.model_store_format
214228
export_files = "symlink" if request.include_files else None
215-
target_uri = request.target_uri
216229
user_context = self._build_user_context(request.user.user_id)
217230
export_metadata = self.set_history_export_request_metadata(request)
231+
232+
exception_exporting_history: Optional[Exception] = None
233+
uri: Optional[str] = None
218234
try:
219-
with model.store.get_export_store_factory(
235+
export_store = model.store.get_export_store_factory(
220236
self._app, model_store_format, export_files=export_files, user_context=user_context
221-
)(target_uri) as export_store:
237+
)(request.target_uri)
238+
with export_store:
222239
history = self._history_manager.by_id(request.history_id)
223240
export_store.export_history(
224241
history, include_hidden=request.include_hidden, include_deleted=request.include_deleted
225242
)
226-
self.set_history_export_result_metadata(request.export_association_id, export_metadata, success=True)
227-
except Exception as e:
243+
uri = str(export_store.file_source_uri) if export_store.file_source_uri else request.target_uri
244+
except Exception as exception:
245+
exception_exporting_history = exception
246+
raise
247+
finally:
228248
self.set_history_export_result_metadata(
229-
request.export_association_id, export_metadata, success=False, error=str(e)
249+
request.export_association_id,
250+
export_metadata,
251+
success=not bool(exception_exporting_history),
252+
uri=uri,
253+
error=str(exception_exporting_history) if exception_exporting_history else None,
230254
)
231-
raise
232255

233256
def set_history_export_request_metadata(
234257
self, request: Union[WriteHistoryTo, GenerateHistoryDownload]
@@ -257,10 +280,11 @@ def set_history_export_result_metadata(
257280
export_association_id: Optional[int],
258281
export_metadata: Optional[ExportObjectMetadata],
259282
success: bool,
283+
uri: Optional[str] = None,
260284
error: Optional[str] = None,
261285
):
262286
if export_association_id is not None and export_metadata is not None:
263-
export_metadata.result_data = ExportObjectResultMetadata(success=success, error=error)
287+
export_metadata.result_data = ExportObjectResultMetadata(success=success, uri=uri, error=error)
264288
self._export_tracker.set_export_association_metadata(export_association_id, export_metadata)
265289

266290
def import_model_store(self, request: ImportModelStoreTaskRequest):

0 commit comments

Comments
 (0)