|
28 | 28 | from typing_extensions import (TYPE_CHECKING, # pylint: disable=unused-import
|
29 | 29 | Text)
|
30 | 30 | from schema_salad import schema, validate
|
31 |
| -from schema_salad.ref_resolver import Loader, file_uri |
| 31 | +from schema_salad.ref_resolver import Loader, file_uri, uri_file_path |
32 | 32 | from schema_salad.sourceline import SourceLine, strip_dup_lineno
|
33 | 33 |
|
34 | 34 | from . import expression
|
|
39 | 39 | from .loghandler import _logger
|
40 | 40 | from .mutation import MutationManager # pylint: disable=unused-import
|
41 | 41 | from .pathmapper import (PathMapper, adjustDirObjs, ensure_writable,
|
42 |
| - get_listing, normalizeFilesDirs, visit_class) |
| 42 | + get_listing, normalizeFilesDirs, visit_class, |
| 43 | + MapperEnt) |
43 | 44 | from .secrets import SecretStore # pylint: disable=unused-import
|
44 | 45 | from .software_requirements import ( # pylint: disable=unused-import
|
45 | 46 | DependenciesConfiguration)
|
@@ -222,9 +223,30 @@ def stage_files(pathmapper, # type: PathMapper
|
222 | 223 | stage_func=None, # type: Optional[Callable[..., Any]]
|
223 | 224 | ignore_writable=False, # type: bool
|
224 | 225 | symlink=True, # type: bool
|
225 |
| - secret_store=None # type: Optional[SecretStore] |
| 226 | + secret_store=None, # type: Optional[SecretStore] |
| 227 | + fix_conflicts=False # type: bool |
226 | 228 | ): # type: (...) -> None
|
227 | 229 | """Link or copy files to their targets. Create them as needed."""
|
| 230 | + |
| 231 | + targets = {} # type: Dict[Text, MapperEnt] |
| 232 | + for key, entry in pathmapper.items(): |
| 233 | + if not 'File' in entry.type: |
| 234 | + continue |
| 235 | + if entry.target not in targets: |
| 236 | + targets[entry.target] = entry |
| 237 | + elif targets[entry.target].resolved != entry.resolved: |
| 238 | + if fix_conflicts: |
| 239 | + tgt = entry.target |
| 240 | + i = 2 |
| 241 | + tgt = "%s_%s" % (tgt, i) |
| 242 | + while tgt in targets: |
| 243 | + i += 1 |
| 244 | + tgt = "%s_%s" % (tgt, i) |
| 245 | + targets[tgt] = pathmapper.update(key, entry.resolved, tgt, entry.type, entry.staged) |
| 246 | + else: |
| 247 | + raise WorkflowException("File staging conflict, trying to stage both %s and %s to the same target %s" % ( |
| 248 | + targets[entry.target].resolved, entry.resolved, entry.target)) |
| 249 | + |
228 | 250 | for key, entry in pathmapper.items():
|
229 | 251 | if not entry.staged:
|
230 | 252 | continue
|
@@ -329,9 +351,16 @@ def _relocate(src, dst): # type: (Text, Text) -> None
|
329 | 351 | else:
|
330 | 352 | shutil.copy2(src, dst)
|
331 | 353 |
|
| 354 | + def _realpath(ob): # type: (Dict[Text, Any]) -> None |
| 355 | + if ob["location"].startswith("file:"): |
| 356 | + ob["location"] = file_uri(os.path.realpath(uri_file_path(ob["location"]))) |
| 357 | + if ob["location"].startswith("/"): |
| 358 | + ob["location"] = os.path.realpath(ob["location"]) |
| 359 | + |
332 | 360 | outfiles = list(_collectDirEntries(outputObj))
|
| 361 | + visit_class(outfiles, ("File", "Directory"), _realpath) |
333 | 362 | pm = path_mapper(outfiles, "", destination_path, separateDirs=False)
|
334 |
| - stage_files(pm, stage_func=_relocate, symlink=False) |
| 363 | + stage_files(pm, stage_func=_relocate, symlink=False, fix_conflicts=True) |
335 | 364 |
|
336 | 365 | def _check_adjust(a_file): # type: (Dict[Text, Text]) -> Dict[Text, Text]
|
337 | 366 | a_file["location"] = file_uri(pm.mapper(a_file["location"])[1])
|
|
0 commit comments