-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Pull dependencies implicitly when running a report. (#47)
If a user runs a report with a `allow_remote=True` in their search options, specifying a dependency will look for packets in remote locations, and pull files from those locations as necessary. If `pull_metadata` is set as well, the metadata will be synchronized from all (enabled) locations. By default, only the requested files are copied, and not whole packets. However, if the `require_complete_tree` option is enabled on the root then the entire packet, and all of its transitive dependencies, are pulled as well.
- Loading branch information
Showing
20 changed files
with
600 additions
and
343 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
from dataclasses import dataclass | ||
from pathlib import Path | ||
from typing import Dict | ||
|
||
from outpack.location_pull import ( | ||
location_build_pull_plan, | ||
location_pull_files, | ||
) | ||
from outpack.metadata import PacketFile | ||
from outpack.root import OutpackRoot | ||
from outpack.search_options import SearchOptions | ||
|
||
|
||
@dataclass | ||
class Plan: | ||
id: str | ||
name: str | ||
files: Dict[str, PacketFile] | ||
|
||
|
||
def copy_files( | ||
id: str, | ||
files: Dict[str, str], | ||
dest: Path, | ||
options: SearchOptions, | ||
root: OutpackRoot, | ||
) -> Plan: | ||
plan = _plan_copy_files(root, id, files) | ||
|
||
try: | ||
for here, there in plan.files.items(): | ||
root.export_file(id, there.path, here, dest) | ||
|
||
except FileNotFoundError as e: | ||
if not options.allow_remote: | ||
msg = f"File `{e.filename}` from packet {id} is not available locally." | ||
raise Exception(msg) from e | ||
else: | ||
copy_files_from_remote(id, plan.files, dest, options, root) | ||
|
||
return plan | ||
|
||
|
||
def copy_files_from_remote( | ||
id: str, | ||
files: Dict[str, PacketFile], | ||
dest: Path, | ||
options: SearchOptions, | ||
root: OutpackRoot, | ||
): | ||
plan = location_build_pull_plan( | ||
[id], | ||
options.location, | ||
recursive=False, | ||
files={id: [f.hash for f in files.values()]}, | ||
root=root, | ||
) | ||
|
||
with location_pull_files(plan.files, root) as store: | ||
for here, there in files.items(): | ||
store.get(there.hash, dest / here, overwrite=True) | ||
|
||
|
||
def _validate_files(files): | ||
if isinstance(files, str): | ||
files = {files: files} | ||
if isinstance(files, list): | ||
files = {x: x for x in files} | ||
return files | ||
|
||
|
||
def _plan_copy_files(root, id, files): | ||
meta = root.index.metadata(id) | ||
files = _validate_files(files) | ||
known = {f.path: f for f in meta.files} | ||
|
||
plan = {} | ||
for here, there in files.items(): | ||
# TODO: check absolute paths | ||
if here.endswith("/") or there.endswith("/"): | ||
msg = "Directories not yet supported for export" | ||
raise Exception(msg) | ||
|
||
f = known.get(there, None) | ||
if f is None: | ||
msg = f"Packet '{id}' does not contain the requested path '{there}'" | ||
raise Exception(msg) | ||
plan[here] = f | ||
return Plan(id, meta.name, plan) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.