hpcflow 0.1.15__py3-none-any.whl → 0.2.0a271__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hpcflow/__init__.py +2 -11
- hpcflow/__pyinstaller/__init__.py +5 -0
- hpcflow/__pyinstaller/hook-hpcflow.py +40 -0
- hpcflow/_version.py +1 -1
- hpcflow/app.py +43 -0
- hpcflow/cli.py +2 -461
- hpcflow/data/demo_data_manifest/__init__.py +3 -0
- hpcflow/data/demo_data_manifest/demo_data_manifest.json +6 -0
- hpcflow/data/jinja_templates/test/test_template.txt +8 -0
- hpcflow/data/programs/hello_world/README.md +1 -0
- hpcflow/data/programs/hello_world/hello_world.c +87 -0
- hpcflow/data/programs/hello_world/linux/hello_world +0 -0
- hpcflow/data/programs/hello_world/macos/hello_world +0 -0
- hpcflow/data/programs/hello_world/win/hello_world.exe +0 -0
- hpcflow/data/scripts/__init__.py +1 -0
- hpcflow/data/scripts/bad_script.py +2 -0
- hpcflow/data/scripts/demo_task_1_generate_t1_infile_1.py +8 -0
- hpcflow/data/scripts/demo_task_1_generate_t1_infile_2.py +8 -0
- hpcflow/data/scripts/demo_task_1_parse_p3.py +7 -0
- hpcflow/data/scripts/do_nothing.py +2 -0
- hpcflow/data/scripts/env_specifier_test/input_file_generator_pass_env_spec.py +4 -0
- hpcflow/data/scripts/env_specifier_test/main_script_test_pass_env_spec.py +8 -0
- hpcflow/data/scripts/env_specifier_test/output_file_parser_pass_env_spec.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v1/input_file_generator_basic.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v1/main_script_test_direct_in_direct_out.py +7 -0
- hpcflow/data/scripts/env_specifier_test/v1/output_file_parser_basic.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v2/main_script_test_direct_in_direct_out.py +7 -0
- hpcflow/data/scripts/generate_t1_file_01.py +7 -0
- hpcflow/data/scripts/import_future_script.py +7 -0
- hpcflow/data/scripts/input_file_generator_basic.py +3 -0
- hpcflow/data/scripts/input_file_generator_basic_FAIL.py +3 -0
- hpcflow/data/scripts/input_file_generator_test_stdout_stderr.py +8 -0
- hpcflow/data/scripts/main_script_test_direct_in.py +3 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed_group.py +7 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_all_iters_test.py +15 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_env_spec.py +7 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_labels.py +8 -0
- hpcflow/data/scripts/main_script_test_direct_in_group_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_group_one_fail_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_sub_param_in_direct_out.py +6 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj.py +12 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +12 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj_group.py +12 -0
- hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +11 -0
- hpcflow/data/scripts/main_script_test_json_and_direct_in_json_out.py +14 -0
- hpcflow/data/scripts/main_script_test_json_in_json_and_direct_out.py +17 -0
- hpcflow/data/scripts/main_script_test_json_in_json_out.py +14 -0
- hpcflow/data/scripts/main_script_test_json_in_json_out_labels.py +16 -0
- hpcflow/data/scripts/main_script_test_json_in_obj.py +12 -0
- hpcflow/data/scripts/main_script_test_json_out_FAIL.py +3 -0
- hpcflow/data/scripts/main_script_test_json_out_obj.py +10 -0
- hpcflow/data/scripts/main_script_test_json_sub_param_in_json_out_labels.py +16 -0
- hpcflow/data/scripts/main_script_test_shell_env_vars.py +12 -0
- hpcflow/data/scripts/main_script_test_std_out_std_err.py +6 -0
- hpcflow/data/scripts/output_file_parser_basic.py +3 -0
- hpcflow/data/scripts/output_file_parser_basic_FAIL.py +7 -0
- hpcflow/data/scripts/output_file_parser_test_stdout_stderr.py +8 -0
- hpcflow/data/scripts/parse_t1_file_01.py +4 -0
- hpcflow/data/scripts/script_exit_test.py +5 -0
- hpcflow/data/template_components/__init__.py +1 -0
- hpcflow/data/template_components/command_files.yaml +26 -0
- hpcflow/data/template_components/environments.yaml +13 -0
- hpcflow/data/template_components/parameters.yaml +14 -0
- hpcflow/data/template_components/task_schemas.yaml +139 -0
- hpcflow/data/workflows/workflow_1.yaml +5 -0
- hpcflow/examples.ipynb +1037 -0
- hpcflow/sdk/__init__.py +149 -0
- hpcflow/sdk/app.py +4266 -0
- hpcflow/sdk/cli.py +1479 -0
- hpcflow/sdk/cli_common.py +385 -0
- hpcflow/sdk/config/__init__.py +5 -0
- hpcflow/sdk/config/callbacks.py +246 -0
- hpcflow/sdk/config/cli.py +388 -0
- hpcflow/sdk/config/config.py +1410 -0
- hpcflow/sdk/config/config_file.py +501 -0
- hpcflow/sdk/config/errors.py +272 -0
- hpcflow/sdk/config/types.py +150 -0
- hpcflow/sdk/core/__init__.py +38 -0
- hpcflow/sdk/core/actions.py +3857 -0
- hpcflow/sdk/core/app_aware.py +25 -0
- hpcflow/sdk/core/cache.py +224 -0
- hpcflow/sdk/core/command_files.py +814 -0
- hpcflow/sdk/core/commands.py +424 -0
- hpcflow/sdk/core/element.py +2071 -0
- hpcflow/sdk/core/enums.py +221 -0
- hpcflow/sdk/core/environment.py +256 -0
- hpcflow/sdk/core/errors.py +1043 -0
- hpcflow/sdk/core/execute.py +207 -0
- hpcflow/sdk/core/json_like.py +809 -0
- hpcflow/sdk/core/loop.py +1320 -0
- hpcflow/sdk/core/loop_cache.py +282 -0
- hpcflow/sdk/core/object_list.py +933 -0
- hpcflow/sdk/core/parameters.py +3371 -0
- hpcflow/sdk/core/rule.py +196 -0
- hpcflow/sdk/core/run_dir_files.py +57 -0
- hpcflow/sdk/core/skip_reason.py +7 -0
- hpcflow/sdk/core/task.py +3792 -0
- hpcflow/sdk/core/task_schema.py +993 -0
- hpcflow/sdk/core/test_utils.py +538 -0
- hpcflow/sdk/core/types.py +447 -0
- hpcflow/sdk/core/utils.py +1207 -0
- hpcflow/sdk/core/validation.py +87 -0
- hpcflow/sdk/core/values.py +477 -0
- hpcflow/sdk/core/workflow.py +4820 -0
- hpcflow/sdk/core/zarr_io.py +206 -0
- hpcflow/sdk/data/__init__.py +13 -0
- hpcflow/sdk/data/config_file_schema.yaml +34 -0
- hpcflow/sdk/data/config_schema.yaml +260 -0
- hpcflow/sdk/data/environments_spec_schema.yaml +21 -0
- hpcflow/sdk/data/files_spec_schema.yaml +5 -0
- hpcflow/sdk/data/parameters_spec_schema.yaml +7 -0
- hpcflow/sdk/data/task_schema_spec_schema.yaml +3 -0
- hpcflow/sdk/data/workflow_spec_schema.yaml +22 -0
- hpcflow/sdk/demo/__init__.py +3 -0
- hpcflow/sdk/demo/cli.py +242 -0
- hpcflow/sdk/helper/__init__.py +3 -0
- hpcflow/sdk/helper/cli.py +137 -0
- hpcflow/sdk/helper/helper.py +300 -0
- hpcflow/sdk/helper/watcher.py +192 -0
- hpcflow/sdk/log.py +288 -0
- hpcflow/sdk/persistence/__init__.py +18 -0
- hpcflow/sdk/persistence/base.py +2817 -0
- hpcflow/sdk/persistence/defaults.py +6 -0
- hpcflow/sdk/persistence/discovery.py +39 -0
- hpcflow/sdk/persistence/json.py +954 -0
- hpcflow/sdk/persistence/pending.py +948 -0
- hpcflow/sdk/persistence/store_resource.py +203 -0
- hpcflow/sdk/persistence/types.py +309 -0
- hpcflow/sdk/persistence/utils.py +73 -0
- hpcflow/sdk/persistence/zarr.py +2388 -0
- hpcflow/sdk/runtime.py +320 -0
- hpcflow/sdk/submission/__init__.py +3 -0
- hpcflow/sdk/submission/enums.py +70 -0
- hpcflow/sdk/submission/jobscript.py +2379 -0
- hpcflow/sdk/submission/schedulers/__init__.py +281 -0
- hpcflow/sdk/submission/schedulers/direct.py +233 -0
- hpcflow/sdk/submission/schedulers/sge.py +376 -0
- hpcflow/sdk/submission/schedulers/slurm.py +598 -0
- hpcflow/sdk/submission/schedulers/utils.py +25 -0
- hpcflow/sdk/submission/shells/__init__.py +52 -0
- hpcflow/sdk/submission/shells/base.py +229 -0
- hpcflow/sdk/submission/shells/bash.py +504 -0
- hpcflow/sdk/submission/shells/os_version.py +115 -0
- hpcflow/sdk/submission/shells/powershell.py +352 -0
- hpcflow/sdk/submission/submission.py +1402 -0
- hpcflow/sdk/submission/types.py +140 -0
- hpcflow/sdk/typing.py +194 -0
- hpcflow/sdk/utils/arrays.py +69 -0
- hpcflow/sdk/utils/deferred_file.py +55 -0
- hpcflow/sdk/utils/hashing.py +16 -0
- hpcflow/sdk/utils/patches.py +31 -0
- hpcflow/sdk/utils/strings.py +69 -0
- hpcflow/tests/api/test_api.py +32 -0
- hpcflow/tests/conftest.py +123 -0
- hpcflow/tests/data/__init__.py +0 -0
- hpcflow/tests/data/benchmark_N_elements.yaml +6 -0
- hpcflow/tests/data/benchmark_script_runner.yaml +26 -0
- hpcflow/tests/data/multi_path_sequences.yaml +29 -0
- hpcflow/tests/data/workflow_1.json +10 -0
- hpcflow/tests/data/workflow_1.yaml +5 -0
- hpcflow/tests/data/workflow_1_slurm.yaml +8 -0
- hpcflow/tests/data/workflow_1_wsl.yaml +8 -0
- hpcflow/tests/data/workflow_test_run_abort.yaml +42 -0
- hpcflow/tests/jinja_templates/test_jinja_templates.py +161 -0
- hpcflow/tests/programs/test_programs.py +180 -0
- hpcflow/tests/schedulers/direct_linux/test_direct_linux_submission.py +12 -0
- hpcflow/tests/schedulers/sge/test_sge_submission.py +36 -0
- hpcflow/tests/schedulers/slurm/test_slurm_submission.py +14 -0
- hpcflow/tests/scripts/test_input_file_generators.py +282 -0
- hpcflow/tests/scripts/test_main_scripts.py +1361 -0
- hpcflow/tests/scripts/test_non_snippet_script.py +46 -0
- hpcflow/tests/scripts/test_ouput_file_parsers.py +353 -0
- hpcflow/tests/shells/wsl/test_wsl_submission.py +14 -0
- hpcflow/tests/unit/test_action.py +1066 -0
- hpcflow/tests/unit/test_action_rule.py +24 -0
- hpcflow/tests/unit/test_app.py +132 -0
- hpcflow/tests/unit/test_cache.py +46 -0
- hpcflow/tests/unit/test_cli.py +172 -0
- hpcflow/tests/unit/test_command.py +377 -0
- hpcflow/tests/unit/test_config.py +195 -0
- hpcflow/tests/unit/test_config_file.py +162 -0
- hpcflow/tests/unit/test_element.py +666 -0
- hpcflow/tests/unit/test_element_iteration.py +88 -0
- hpcflow/tests/unit/test_element_set.py +158 -0
- hpcflow/tests/unit/test_group.py +115 -0
- hpcflow/tests/unit/test_input_source.py +1479 -0
- hpcflow/tests/unit/test_input_value.py +398 -0
- hpcflow/tests/unit/test_jobscript_unit.py +757 -0
- hpcflow/tests/unit/test_json_like.py +1247 -0
- hpcflow/tests/unit/test_loop.py +2674 -0
- hpcflow/tests/unit/test_meta_task.py +325 -0
- hpcflow/tests/unit/test_multi_path_sequences.py +259 -0
- hpcflow/tests/unit/test_object_list.py +116 -0
- hpcflow/tests/unit/test_parameter.py +243 -0
- hpcflow/tests/unit/test_persistence.py +664 -0
- hpcflow/tests/unit/test_resources.py +243 -0
- hpcflow/tests/unit/test_run.py +286 -0
- hpcflow/tests/unit/test_run_directories.py +29 -0
- hpcflow/tests/unit/test_runtime.py +9 -0
- hpcflow/tests/unit/test_schema_input.py +372 -0
- hpcflow/tests/unit/test_shell.py +129 -0
- hpcflow/tests/unit/test_slurm.py +39 -0
- hpcflow/tests/unit/test_submission.py +502 -0
- hpcflow/tests/unit/test_task.py +2560 -0
- hpcflow/tests/unit/test_task_schema.py +182 -0
- hpcflow/tests/unit/test_utils.py +616 -0
- hpcflow/tests/unit/test_value_sequence.py +549 -0
- hpcflow/tests/unit/test_values.py +91 -0
- hpcflow/tests/unit/test_workflow.py +827 -0
- hpcflow/tests/unit/test_workflow_template.py +186 -0
- hpcflow/tests/unit/utils/test_arrays.py +40 -0
- hpcflow/tests/unit/utils/test_deferred_file_writer.py +34 -0
- hpcflow/tests/unit/utils/test_hashing.py +65 -0
- hpcflow/tests/unit/utils/test_patches.py +5 -0
- hpcflow/tests/unit/utils/test_redirect_std.py +50 -0
- hpcflow/tests/unit/utils/test_strings.py +97 -0
- hpcflow/tests/workflows/__init__.py +0 -0
- hpcflow/tests/workflows/test_directory_structure.py +31 -0
- hpcflow/tests/workflows/test_jobscript.py +355 -0
- hpcflow/tests/workflows/test_run_status.py +198 -0
- hpcflow/tests/workflows/test_skip_downstream.py +696 -0
- hpcflow/tests/workflows/test_submission.py +140 -0
- hpcflow/tests/workflows/test_workflows.py +564 -0
- hpcflow/tests/workflows/test_zip.py +18 -0
- hpcflow/viz_demo.ipynb +6794 -0
- hpcflow-0.2.0a271.dist-info/LICENSE +375 -0
- hpcflow-0.2.0a271.dist-info/METADATA +65 -0
- hpcflow-0.2.0a271.dist-info/RECORD +237 -0
- {hpcflow-0.1.15.dist-info → hpcflow-0.2.0a271.dist-info}/WHEEL +4 -5
- hpcflow-0.2.0a271.dist-info/entry_points.txt +6 -0
- hpcflow/api.py +0 -490
- hpcflow/archive/archive.py +0 -307
- hpcflow/archive/cloud/cloud.py +0 -45
- hpcflow/archive/cloud/errors.py +0 -9
- hpcflow/archive/cloud/providers/dropbox.py +0 -427
- hpcflow/archive/errors.py +0 -5
- hpcflow/base_db.py +0 -4
- hpcflow/config.py +0 -233
- hpcflow/copytree.py +0 -66
- hpcflow/data/examples/_config.yml +0 -14
- hpcflow/data/examples/damask/demo/1.run.yml +0 -4
- hpcflow/data/examples/damask/demo/2.process.yml +0 -29
- hpcflow/data/examples/damask/demo/geom.geom +0 -2052
- hpcflow/data/examples/damask/demo/load.load +0 -1
- hpcflow/data/examples/damask/demo/material.config +0 -185
- hpcflow/data/examples/damask/inputs/geom.geom +0 -2052
- hpcflow/data/examples/damask/inputs/load.load +0 -1
- hpcflow/data/examples/damask/inputs/material.config +0 -185
- hpcflow/data/examples/damask/profiles/_variable_lookup.yml +0 -21
- hpcflow/data/examples/damask/profiles/damask.yml +0 -4
- hpcflow/data/examples/damask/profiles/damask_process.yml +0 -8
- hpcflow/data/examples/damask/profiles/damask_run.yml +0 -5
- hpcflow/data/examples/damask/profiles/default.yml +0 -6
- hpcflow/data/examples/thinking.yml +0 -177
- hpcflow/errors.py +0 -2
- hpcflow/init_db.py +0 -37
- hpcflow/models.py +0 -2595
- hpcflow/nesting.py +0 -9
- hpcflow/profiles.py +0 -455
- hpcflow/project.py +0 -81
- hpcflow/scheduler.py +0 -322
- hpcflow/utils.py +0 -103
- hpcflow/validation.py +0 -166
- hpcflow/variables.py +0 -543
- hpcflow-0.1.15.dist-info/METADATA +0 -168
- hpcflow-0.1.15.dist-info/RECORD +0 -45
- hpcflow-0.1.15.dist-info/entry_points.txt +0 -8
- hpcflow-0.1.15.dist-info/top_level.txt +0 -1
- /hpcflow/{archive → data/jinja_templates}/__init__.py +0 -0
- /hpcflow/{archive/cloud → data/programs}/__init__.py +0 -0
- /hpcflow/{archive/cloud/providers → data/workflows}/__init__.py +0 -0
hpcflow/archive/archive.py
DELETED
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
"""`hpcflow.archive.archive.py`
|
|
2
|
-
|
|
3
|
-
This module contains a database model class for the archiving capabilities.
|
|
4
|
-
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import shutil
|
|
8
|
-
import enum
|
|
9
|
-
import time
|
|
10
|
-
from datetime import datetime
|
|
11
|
-
from pathlib import Path
|
|
12
|
-
from shutil import ignore_patterns
|
|
13
|
-
from time import sleep
|
|
14
|
-
|
|
15
|
-
from sqlalchemy import (Table, Column, Integer, ForeignKey, String,
|
|
16
|
-
UniqueConstraint, Enum, Boolean)
|
|
17
|
-
from sqlalchemy.orm import relationship, Session
|
|
18
|
-
from sqlalchemy.exc import IntegrityError, OperationalError
|
|
19
|
-
|
|
20
|
-
from hpcflow.config import Config as CONFIG
|
|
21
|
-
from hpcflow.archive.cloud.cloud import CloudProvider
|
|
22
|
-
from hpcflow.archive.cloud.errors import CloudProviderError, CloudCredentialsError
|
|
23
|
-
from hpcflow.archive.errors import ArchiveError
|
|
24
|
-
from hpcflow.base_db import Base
|
|
25
|
-
from hpcflow.copytree import copytree_multi
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
archive_is_active = Table(
|
|
29
|
-
'archive_is_active',
|
|
30
|
-
Base.metadata,
|
|
31
|
-
Column(
|
|
32
|
-
'archive_id',
|
|
33
|
-
Integer,
|
|
34
|
-
ForeignKey('archive.id'),
|
|
35
|
-
primary_key=True
|
|
36
|
-
),
|
|
37
|
-
Column(
|
|
38
|
-
'directory_value_id',
|
|
39
|
-
Integer,
|
|
40
|
-
ForeignKey('var_value.id'),
|
|
41
|
-
primary_key=True
|
|
42
|
-
),
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class RootDirectoryName(enum.Enum):
|
|
47
|
-
|
|
48
|
-
parent = 'parent'
|
|
49
|
-
datetime = 'datetime'
|
|
50
|
-
null = ''
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
class TaskArchiveStatus(enum.Enum):
|
|
54
|
-
|
|
55
|
-
pending = 'pending'
|
|
56
|
-
active = 'active'
|
|
57
|
-
complete = 'complete'
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
class Archive(Base):
|
|
61
|
-
"""Class to represent an archive location."""
|
|
62
|
-
|
|
63
|
-
__tablename__ = 'archive'
|
|
64
|
-
__table_args__ = (
|
|
65
|
-
UniqueConstraint('path', 'host', 'cloud_provider',
|
|
66
|
-
name='archive_location'),
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
id_ = Column('id', Integer, primary_key=True)
|
|
70
|
-
name = Column(String(255))
|
|
71
|
-
_path = Column('path', String(255))
|
|
72
|
-
host = Column(String(255))
|
|
73
|
-
cloud_provider = Column(Enum(CloudProvider))
|
|
74
|
-
root_directory_name = Column(Enum(RootDirectoryName))
|
|
75
|
-
root_directory_increment = Column(Boolean)
|
|
76
|
-
|
|
77
|
-
command_groups = relationship('CommandGroup', back_populates='archive')
|
|
78
|
-
directories_archiving = relationship('VarValue', secondary=archive_is_active)
|
|
79
|
-
workflow = relationship('Workflow', back_populates='root_archive', uselist=False)
|
|
80
|
-
|
|
81
|
-
def __init__(self, name, path, host='', cloud_provider='', root_directory_name='',
|
|
82
|
-
root_directory_increment=True):
|
|
83
|
-
|
|
84
|
-
self.name = name
|
|
85
|
-
self._path = path
|
|
86
|
-
self.host = host
|
|
87
|
-
self.cloud_provider = CloudProvider(cloud_provider)
|
|
88
|
-
self.root_directory_name = RootDirectoryName(root_directory_name)
|
|
89
|
-
self.root_directory_increment = root_directory_increment
|
|
90
|
-
|
|
91
|
-
if not self.check_exists(self.path):
|
|
92
|
-
raise ValueError('Archive path "{}" does not exist.'.format(self.path))
|
|
93
|
-
|
|
94
|
-
@property
|
|
95
|
-
def path(self):
|
|
96
|
-
return Path(self._path)
|
|
97
|
-
|
|
98
|
-
def get_directories(self):
|
|
99
|
-
"""Get sub directories currently on the archive path.
|
|
100
|
-
|
|
101
|
-
Returns
|
|
102
|
-
-------
|
|
103
|
-
list of str
|
|
104
|
-
Sub-directory names.
|
|
105
|
-
|
|
106
|
-
"""
|
|
107
|
-
|
|
108
|
-
if not self.host:
|
|
109
|
-
if self.cloud_provider != CloudProvider.null:
|
|
110
|
-
directories = self.cloud_provider.get_directories(self.path)
|
|
111
|
-
else:
|
|
112
|
-
directories = [i.name for i in self.path.glob('*') if i.is_dir()]
|
|
113
|
-
else:
|
|
114
|
-
raise NotImplementedError()
|
|
115
|
-
|
|
116
|
-
return directories
|
|
117
|
-
|
|
118
|
-
def check_exists(self, directory):
|
|
119
|
-
"""Check if a given directory exists on the Archive."""
|
|
120
|
-
|
|
121
|
-
if not self.host:
|
|
122
|
-
if self.cloud_provider != CloudProvider.null:
|
|
123
|
-
exists = self.cloud_provider.check_exists(directory)
|
|
124
|
-
else:
|
|
125
|
-
exists = directory.is_dir()
|
|
126
|
-
else:
|
|
127
|
-
raise NotImplementedError()
|
|
128
|
-
|
|
129
|
-
return exists
|
|
130
|
-
|
|
131
|
-
def get_archive_dir(self, workflow):
|
|
132
|
-
"""This should be called once per unique workflow Archive."""
|
|
133
|
-
|
|
134
|
-
if self.root_directory_name != RootDirectoryName.null:
|
|
135
|
-
|
|
136
|
-
if self.root_directory_name == RootDirectoryName.parent:
|
|
137
|
-
archive_dir = workflow.directory.stem
|
|
138
|
-
elif self.root_directory_name == RootDirectoryName.datetime:
|
|
139
|
-
archive_dir = time.strftime('%Y-%m-%d-%H%M')
|
|
140
|
-
|
|
141
|
-
sub_dirs = self.get_directories()
|
|
142
|
-
if archive_dir in sub_dirs:
|
|
143
|
-
if self.root_directory_increment:
|
|
144
|
-
count = 0
|
|
145
|
-
max_count = 10
|
|
146
|
-
while archive_dir in sub_dirs:
|
|
147
|
-
count += 1
|
|
148
|
-
if count > max_count:
|
|
149
|
-
msg = ('Maximum iteration reached ({}) in searching for '
|
|
150
|
-
'available archive directory.'.format(max_count))
|
|
151
|
-
raise RuntimeError(msg)
|
|
152
|
-
archive_dir = archive_dir + '_1'
|
|
153
|
-
else:
|
|
154
|
-
msg = ('Archive directory "{}" already exists.')
|
|
155
|
-
raise ValueError(msg.format(archive_dir))
|
|
156
|
-
|
|
157
|
-
else:
|
|
158
|
-
archive_dir = ''
|
|
159
|
-
|
|
160
|
-
return archive_dir
|
|
161
|
-
|
|
162
|
-
def execute(self, exclude, archive_dir):
|
|
163
|
-
"""Execute the archive process with no lock. Used for root archive.
|
|
164
|
-
|
|
165
|
-
Parameters
|
|
166
|
-
----------
|
|
167
|
-
exclude : list of str
|
|
168
|
-
|
|
169
|
-
"""
|
|
170
|
-
|
|
171
|
-
self._copy(self.workflow.directory, self.path.joinpath(archive_dir), exclude)
|
|
172
|
-
|
|
173
|
-
def execute_with_lock(self, task):
|
|
174
|
-
"""Execute the archive process of a given working directory.
|
|
175
|
-
|
|
176
|
-
Parameters
|
|
177
|
-
----------
|
|
178
|
-
directory_value : VarValue
|
|
179
|
-
exclude : list of str
|
|
180
|
-
|
|
181
|
-
"""
|
|
182
|
-
|
|
183
|
-
print('Archive.execute_with_lock: task.is_archive_required: {}'.format(
|
|
184
|
-
task.is_archive_required()))
|
|
185
|
-
|
|
186
|
-
session = Session.object_session(self)
|
|
187
|
-
|
|
188
|
-
cg_sub = task.command_group_submission_iteration.command_group_submission
|
|
189
|
-
directory_value = task.get_working_directory()
|
|
190
|
-
exclude = cg_sub.command_group.archive_excludes
|
|
191
|
-
archive_dir = cg_sub.command_group.archive_directory
|
|
192
|
-
|
|
193
|
-
root_dir = self.command_groups[0].workflow.directory
|
|
194
|
-
src_dir = root_dir.joinpath(directory_value.value)
|
|
195
|
-
dst_dir = self.path.joinpath(archive_dir, directory_value.value)
|
|
196
|
-
|
|
197
|
-
sleep_time = 5
|
|
198
|
-
context = 'Archive.execute_with_lock'
|
|
199
|
-
block_msg = ('{{}} {}: Archiving blocked. Sleeping for {} '
|
|
200
|
-
'seconds'.format(context, sleep_time))
|
|
201
|
-
unblock_msg = ('{{}} {}: Archiving available. Archiving from source directory: '
|
|
202
|
-
'"{}" to destination directory: "{}".'.format(
|
|
203
|
-
context, src_dir, dst_dir))
|
|
204
|
-
apply_block_msg = ('{{}} {}: Applying archive lock to directory: {}.'.format(
|
|
205
|
-
context, directory_value))
|
|
206
|
-
remove_block_msg = ('{{}} {}: Removing archive lock from directory: {}'.format(
|
|
207
|
-
context, directory_value))
|
|
208
|
-
arch_done_msg = ('{{}} {}: Archive of the working directory {} performed by '
|
|
209
|
-
'another task.'.format(context, directory_value))
|
|
210
|
-
|
|
211
|
-
if task.is_archive_required():
|
|
212
|
-
|
|
213
|
-
blocked = True
|
|
214
|
-
while blocked:
|
|
215
|
-
|
|
216
|
-
session.refresh(self)
|
|
217
|
-
if not task.is_archive_required():
|
|
218
|
-
print(arch_done_msg.format(datetime.now()), flush=True)
|
|
219
|
-
task.archive_status = TaskArchiveStatus('complete')
|
|
220
|
-
session.commit()
|
|
221
|
-
return
|
|
222
|
-
|
|
223
|
-
if directory_value in self.directories_archiving:
|
|
224
|
-
print(block_msg.format(datetime.now()), flush=True)
|
|
225
|
-
sleep(sleep_time)
|
|
226
|
-
else:
|
|
227
|
-
try:
|
|
228
|
-
self.directories_archiving.append(directory_value)
|
|
229
|
-
session.commit()
|
|
230
|
-
print(apply_block_msg.format(datetime.now()), flush=True)
|
|
231
|
-
blocked = False
|
|
232
|
-
|
|
233
|
-
except IntegrityError:
|
|
234
|
-
# Another process has already set `directories_archiving`
|
|
235
|
-
session.rollback()
|
|
236
|
-
print(block_msg.format(datetime.now()), flush=True)
|
|
237
|
-
sleep(sleep_time)
|
|
238
|
-
|
|
239
|
-
except OperationalError:
|
|
240
|
-
# Database is likely locked.
|
|
241
|
-
session.rollback()
|
|
242
|
-
print(block_msg.format(datetime.now()), flush=True)
|
|
243
|
-
sleep(sleep_time)
|
|
244
|
-
|
|
245
|
-
if not blocked:
|
|
246
|
-
|
|
247
|
-
start_time = datetime.now()
|
|
248
|
-
print(unblock_msg.format(start_time), flush=True)
|
|
249
|
-
task.archive_status = TaskArchiveStatus('active')
|
|
250
|
-
task.archive_start_time = start_time
|
|
251
|
-
session.commit()
|
|
252
|
-
|
|
253
|
-
self._copy(src_dir, dst_dir, exclude)
|
|
254
|
-
|
|
255
|
-
end_time = datetime.now()
|
|
256
|
-
task.archive_status = TaskArchiveStatus('complete')
|
|
257
|
-
task.archive_end_time = end_time
|
|
258
|
-
self.directories_archiving.remove(directory_value)
|
|
259
|
-
session.commit()
|
|
260
|
-
|
|
261
|
-
print(remove_block_msg.format(end_time), flush=True)
|
|
262
|
-
|
|
263
|
-
else:
|
|
264
|
-
print(arch_done_msg.format(datetime.now()), flush=True)
|
|
265
|
-
task.archive_status = TaskArchiveStatus('complete')
|
|
266
|
-
session.commit()
|
|
267
|
-
|
|
268
|
-
def _copy(self, src_dir, dst_dir, exclude):
|
|
269
|
-
"""Do the actual copying.
|
|
270
|
-
|
|
271
|
-
Need to ensure this function catches all exceptions, so the block is
|
|
272
|
-
released if copying fails.
|
|
273
|
-
|
|
274
|
-
TODO: does copytree overwrite all files or just copy
|
|
275
|
-
non-existing files?
|
|
276
|
-
|
|
277
|
-
TODO: later (safely) copy the database to archive as well?
|
|
278
|
-
|
|
279
|
-
"""
|
|
280
|
-
|
|
281
|
-
ignore = [CONFIG.get('hpcflow_directory')] + (exclude or [])
|
|
282
|
-
start = datetime.now()
|
|
283
|
-
|
|
284
|
-
try:
|
|
285
|
-
|
|
286
|
-
if self.cloud_provider != CloudProvider.null:
|
|
287
|
-
try:
|
|
288
|
-
self.cloud_provider.archive_directory(src_dir, dst_dir, ignore)
|
|
289
|
-
except (CloudProviderError, CloudCredentialsError, ArchiveError) as err:
|
|
290
|
-
raise ArchiveError(err)
|
|
291
|
-
else:
|
|
292
|
-
if ignore:
|
|
293
|
-
ignore_func = ignore_patterns(*ignore)
|
|
294
|
-
else:
|
|
295
|
-
ignore_func = None
|
|
296
|
-
try:
|
|
297
|
-
copytree_multi(str(src_dir), str(dst_dir), ignore=ignore_func)
|
|
298
|
-
except shutil.Error as err:
|
|
299
|
-
raise ArchiveError(err)
|
|
300
|
-
|
|
301
|
-
except ArchiveError as err:
|
|
302
|
-
print('Archive copying error: {}'.format(err))
|
|
303
|
-
|
|
304
|
-
end = datetime.now()
|
|
305
|
-
copy_seconds = (end - start).total_seconds()
|
|
306
|
-
print('Archive to "{}" took {} seconds'.format(
|
|
307
|
-
self.name, copy_seconds), flush=True)
|
hpcflow/archive/cloud/cloud.py
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
"""`hpcflow.archive.cloud.cloud.py
|
|
2
|
-
|
|
3
|
-
TODO: if we have multiple cloud providers, perhaps it would be better to
|
|
4
|
-
implement the `upload_directory` function generally, and then just rely on
|
|
5
|
-
the provider-specific `upload_file` functions.
|
|
6
|
-
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import enum
|
|
10
|
-
|
|
11
|
-
from hpcflow.archive.cloud.providers import dropbox
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class CloudProvider(enum.Enum):
|
|
15
|
-
|
|
16
|
-
dropbox = 'dropbox'
|
|
17
|
-
onedrive = 'onedrive'
|
|
18
|
-
null = ''
|
|
19
|
-
|
|
20
|
-
def check_access(self):
|
|
21
|
-
if self.name == 'dropbox':
|
|
22
|
-
dropbox.check_access()
|
|
23
|
-
|
|
24
|
-
def archive_directory(self, local_path, remote_path, exclude):
|
|
25
|
-
if self.name == 'dropbox':
|
|
26
|
-
dropbox.archive_directory(
|
|
27
|
-
dropbox.get_dropbox(), local_path, remote_path, exclude)
|
|
28
|
-
|
|
29
|
-
def get_directories(self, path):
|
|
30
|
-
"""Get sub directories within a path"""
|
|
31
|
-
|
|
32
|
-
if self.name == 'dropbox':
|
|
33
|
-
dbx = dropbox.get_dropbox()
|
|
34
|
-
return dropbox.get_folders(dbx, path)
|
|
35
|
-
|
|
36
|
-
def check_exists(self, directory):
|
|
37
|
-
"""Check a given directory exists on the cloud storage."""
|
|
38
|
-
if self.name == 'dropbox':
|
|
39
|
-
directory = dropbox.normalise_path(directory)
|
|
40
|
-
dbx = dropbox.get_dropbox()
|
|
41
|
-
return dropbox.is_folder(dbx, directory)
|
|
42
|
-
|
|
43
|
-
def get_token(self):
|
|
44
|
-
if self.name == 'dropbox':
|
|
45
|
-
return dropbox.get_token()
|