idmtools-platform-comps 0.0.0.dev0__py3-none-any.whl → 0.0.2__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.
Files changed (64) hide show
  1. idmtools_platform_comps/__init__.py +25 -8
  2. idmtools_platform_comps/cli/__init__.py +4 -0
  3. idmtools_platform_comps/cli/cli_functions.py +50 -0
  4. idmtools_platform_comps/cli/comps.py +492 -0
  5. idmtools_platform_comps/comps_cli.py +48 -0
  6. idmtools_platform_comps/comps_operations/__init__.py +6 -0
  7. idmtools_platform_comps/comps_operations/asset_collection_operations.py +263 -0
  8. idmtools_platform_comps/comps_operations/experiment_operations.py +569 -0
  9. idmtools_platform_comps/comps_operations/simulation_operations.py +678 -0
  10. idmtools_platform_comps/comps_operations/suite_operations.py +228 -0
  11. idmtools_platform_comps/comps_operations/workflow_item_operations.py +269 -0
  12. idmtools_platform_comps/comps_platform.py +309 -0
  13. idmtools_platform_comps/plugin_info.py +168 -0
  14. idmtools_platform_comps/ssmt_operations/__init__.py +6 -0
  15. idmtools_platform_comps/ssmt_operations/simulation_operations.py +77 -0
  16. idmtools_platform_comps/ssmt_operations/workflow_item_operations.py +73 -0
  17. idmtools_platform_comps/ssmt_platform.py +44 -0
  18. idmtools_platform_comps/ssmt_work_items/__init__.py +4 -0
  19. idmtools_platform_comps/ssmt_work_items/comps_work_order_task.py +29 -0
  20. idmtools_platform_comps/ssmt_work_items/comps_workitems.py +113 -0
  21. idmtools_platform_comps/ssmt_work_items/icomps_workflowitem.py +71 -0
  22. idmtools_platform_comps/ssmt_work_items/work_order.py +54 -0
  23. idmtools_platform_comps/utils/__init__.py +4 -0
  24. idmtools_platform_comps/utils/assetize_output/__init__.py +4 -0
  25. idmtools_platform_comps/utils/assetize_output/assetize_output.py +125 -0
  26. idmtools_platform_comps/utils/assetize_output/assetize_ssmt_script.py +144 -0
  27. idmtools_platform_comps/utils/base_singularity_work_order.json +6 -0
  28. idmtools_platform_comps/utils/download/__init__.py +4 -0
  29. idmtools_platform_comps/utils/download/download.py +178 -0
  30. idmtools_platform_comps/utils/download/download_ssmt.py +81 -0
  31. idmtools_platform_comps/utils/download_experiment.py +116 -0
  32. idmtools_platform_comps/utils/file_filter_workitem.py +519 -0
  33. idmtools_platform_comps/utils/general.py +358 -0
  34. idmtools_platform_comps/utils/linux_mounts.py +73 -0
  35. idmtools_platform_comps/utils/lookups.py +123 -0
  36. idmtools_platform_comps/utils/package_version.py +489 -0
  37. idmtools_platform_comps/utils/python_requirements_ac/__init__.py +4 -0
  38. idmtools_platform_comps/utils/python_requirements_ac/create_asset_collection.py +155 -0
  39. idmtools_platform_comps/utils/python_requirements_ac/install_requirements.py +109 -0
  40. idmtools_platform_comps/utils/python_requirements_ac/requirements_to_asset_collection.py +374 -0
  41. idmtools_platform_comps/utils/python_version.py +40 -0
  42. idmtools_platform_comps/utils/scheduling.py +154 -0
  43. idmtools_platform_comps/utils/singularity_build.py +491 -0
  44. idmtools_platform_comps/utils/spatial_output.py +76 -0
  45. idmtools_platform_comps/utils/ssmt_utils/__init__.py +6 -0
  46. idmtools_platform_comps/utils/ssmt_utils/common.py +70 -0
  47. idmtools_platform_comps/utils/ssmt_utils/file_filter.py +568 -0
  48. idmtools_platform_comps/utils/sweeping.py +162 -0
  49. idmtools_platform_comps-0.0.2.dist-info/METADATA +100 -0
  50. idmtools_platform_comps-0.0.2.dist-info/RECORD +62 -0
  51. idmtools_platform_comps-0.0.2.dist-info/entry_points.txt +9 -0
  52. idmtools_platform_comps-0.0.2.dist-info/licenses/LICENSE.TXT +3 -0
  53. {idmtools_platform_comps-0.0.0.dev0.dist-info → idmtools_platform_comps-0.0.2.dist-info}/top_level.txt +1 -0
  54. ssmt_image/Dockerfile +52 -0
  55. ssmt_image/Makefile +21 -0
  56. ssmt_image/__init__.py +6 -0
  57. ssmt_image/bootstrap.sh +30 -0
  58. ssmt_image/build_docker_image.py +161 -0
  59. ssmt_image/pip.conf +3 -0
  60. ssmt_image/push_docker_image.py +49 -0
  61. ssmt_image/requirements.txt +9 -0
  62. idmtools_platform_comps-0.0.0.dev0.dist-info/METADATA +0 -41
  63. idmtools_platform_comps-0.0.0.dev0.dist-info/RECORD +0 -5
  64. {idmtools_platform_comps-0.0.0.dev0.dist-info → idmtools_platform_comps-0.0.2.dist-info}/WHEEL +0 -0
@@ -0,0 +1,489 @@
1
+ """idmtools Tools to filter versions of packages for requriements for asset collections.
2
+
3
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
4
+ """
5
+ import functools
6
+ import operator
7
+ import json
8
+ import os
9
+ import re
10
+ from abc import ABC
11
+ from datetime import datetime
12
+ from logging import getLogger, DEBUG
13
+ from typing import Optional, List, Type
14
+ from urllib import request
15
+ import requests
16
+ from packaging.requirements import Requirement
17
+ from packaging.version import Version, parse
18
+ from html.parser import HTMLParser
19
+
20
+ user_logger = getLogger('user')
21
+
22
+
23
+ PKG_PYPI = 'https://pypi.python.org/pypi/{}/json'
24
+ PYPI_PRODUCTION_SIMPLE = 'https://packages.idmod.org/artifactory/api/pypi/pypi-production/simple'
25
+
26
+ IDM_DOCKER_PROD = 'https://packages.idmod.org/artifactory/list/docker-production'
27
+ IDMTOOLS_DOCKER_PROD = f'{IDM_DOCKER_PROD}/idmtools/'
28
+ MANIFEST_URL = "https://hub.docker.com/v2/repositories/library/{repository}/tags/?page_size=25&page=1&name={tag}"
29
+
30
+ logger = getLogger(__name__)
31
+
32
+
33
+ class PackageHTMLParser(HTMLParser, ABC):
34
+ """Base Parser for our other parsers."""
35
+ previous_tag = None
36
+ pkg_version = None
37
+
38
+ def __init__(self):
39
+ """Constructor."""
40
+ super().__init__()
41
+ self.pkg_version = set()
42
+
43
+
44
+ class LinkHTMLParser(PackageHTMLParser):
45
+ """Parse hrefs from links."""
46
+
47
+ def handle_starttag(self, tag, attrs):
48
+ """Parse links and extra hrefs."""
49
+ self.previous_tag = tag
50
+ if tag != 'a':
51
+ return
52
+
53
+ attr = dict(attrs)
54
+ v = attr['href']
55
+ v = v.rstrip('/')
56
+ self.pkg_version.add(v)
57
+
58
+
59
+ class LinkNameParser(PackageHTMLParser):
60
+ """
61
+ Provides parsing of packages from pypi/arfifactory.
62
+
63
+ We parse links that match versions patterns
64
+ """
65
+ in_link = False
66
+ ver_pattern = re.compile(r'^[\d\.brcdev\+nightly]+$')
67
+
68
+ def handle_starttag(self, tag, attrs):
69
+ """Handle begin of links."""
70
+ self.previous_tag = tag
71
+ self.in_link = tag == "a"
72
+
73
+ def handle_endtag(self, tag):
74
+ """End link tags."""
75
+ if tag == "a":
76
+ self.in_link = False
77
+
78
+ def handle_data(self, data):
79
+ """Process links."""
80
+ if self.in_link:
81
+ parts = data.split("-")
82
+ if len(parts) >= 2:
83
+ if self.ver_pattern.match(parts[1]):
84
+ self.pkg_version.add(parts[1])
85
+ elif parts[1].endswith(".zip"):
86
+ self.pkg_version.add(parts[1][:-4])
87
+ elif parts[1].endswith(".tar.gz"):
88
+ self.pkg_version.add(parts[1][:-7])
89
+
90
+
91
+ def get_latest_package_version_from_pypi(pkg_name, display_all=False):
92
+ """
93
+ Utility to get the latest version for a given package name.
94
+
95
+ Args:
96
+ pkg_name: package name given
97
+ display_all: determine if output all package releases
98
+
99
+ Returns: the latest version of ven package
100
+ """
101
+ url = f'https://pypi.python.org/pypi/{pkg_name}/json'
102
+ try:
103
+ releases = json.loads(request.urlopen(url).read())['releases']
104
+ except Exception:
105
+ return None
106
+
107
+ all_releases = sorted(releases, key=parse, reverse=True)
108
+
109
+ if display_all:
110
+ print(all_releases)
111
+
112
+ release_versions = [ver for ver in all_releases if not parse(ver).is_prerelease]
113
+ latest_version = release_versions[0]
114
+
115
+ return latest_version
116
+
117
+
118
+ def get_latest_pypi_package_version_from_artifactory(pkg_name, display_all=False, base_version: str = None):
119
+ """
120
+ Utility to get the latest version for a given package name.
121
+
122
+ Args:
123
+ pkg_name: package name given
124
+ display_all: determine if output all package releases
125
+ base_version: Base version
126
+
127
+ Returns: the latest version of ven package
128
+ """
129
+ pkg_url = "/".join([PYPI_PRODUCTION_SIMPLE, pkg_name])
130
+ return get_latest_version_from_site(pkg_url, display_all=display_all, base_version=base_version)
131
+
132
+
133
+ def get_pypi_package_versions_from_artifactory(pkg_name, display_all=False, base_version: str = None,
134
+ exclude_pre_release: bool = True):
135
+ """
136
+ Utility to get versions of a package in artifactory.
137
+
138
+ Args:
139
+ pkg_name: package name given
140
+ display_all: determine if output all package releases
141
+ base_version: Base version
142
+ exclude_pre_release: Exclude any prerelease versions
143
+
144
+ Returns: the latest version of ven package
145
+ """
146
+ pkg_url = "/".join([PYPI_PRODUCTION_SIMPLE, pkg_name])
147
+ return get_versions_from_site(pkg_url, base_version, display_all=display_all, parser=LinkNameParser,
148
+ exclude_pre_release=exclude_pre_release)
149
+
150
+
151
+ def get_latest_ssmt_image_version_from_artifactory(pkg_name='comps_ssmt_worker', base_version: Optional[str] = None,
152
+ display_all=False):
153
+ """
154
+ Utility to get the latest version for a given package name.
155
+
156
+ Args:
157
+ pkg_name: package name given
158
+ base_version: Optional base version. Versions above this will not be added.
159
+ display_all: determine if output all package releases
160
+
161
+ Returns: the latest version of ven package
162
+ """
163
+ pkg_path = IDMTOOLS_DOCKER_PROD
164
+ pkg_url = "/".join([pkg_path, pkg_name])
165
+ base_version = ".".join(base_version.replace("+nightly", "").split(".")[:2])
166
+ return get_latest_version_from_site(pkg_url, base_version=base_version, display_all=display_all,
167
+ parser=LinkHTMLParser)
168
+
169
+
170
+ def get_docker_manifest(image_path="idmtools/comps_ssmt_worker", repo_base=IDM_DOCKER_PROD):
171
+ """
172
+ Get docker manifest from IDM Artifactory. It mimics latest even when user has no latest tag defined.
173
+
174
+ Args:
175
+ image_path:Path of docker image we want
176
+ repo_base:Base of the repo
177
+
178
+ Returns:
179
+ None
180
+
181
+ Raises:
182
+ ValueError - When the manifest cannot be found
183
+ """
184
+ if ":" not in image_path:
185
+ image_path += ":latest"
186
+
187
+ path, tag = image_path.split(":")
188
+ if tag == "latest":
189
+ url = "/".join([IDM_DOCKER_PROD, path])
190
+ response = requests.get(url)
191
+ content = response.text
192
+ lines = [link.split(">") for link in content.split("\n") if "<a href" in link and "pre" not in link]
193
+ lines = {item_date[1].replace("/</a", ''): datetime.strptime(item_date[2].strip(" -"), '%d-%b-%Y %H:%M') for
194
+ item_date in lines}
195
+ tag = list(sorted(lines.items(), key=operator.itemgetter(1), reverse=True))[0][0]
196
+ image_path = ":".join([path, tag])
197
+ final_path = "/".join([path, tag, "manifest.json"])
198
+ pkg_path = f'{repo_base}/{final_path}'
199
+ response = requests.get(pkg_path)
200
+ if response.status_code != 200:
201
+ raise ValueError("Could not find manifest for file")
202
+ return response.json(), image_path
203
+
204
+
205
+ def get_digest_from_docker_hub(repo, tag='latest'):
206
+ """
207
+ Get the digest for image from docker.
208
+
209
+ Args:
210
+ repo: string, repository (e.g. 'library/fedora')
211
+ tag: string, tag of the repository (e.g. 'latest')
212
+ """
213
+ response = requests.get(
214
+ MANIFEST_URL.format(repository=repo, tag=tag)
215
+ )
216
+ manifest = response.json()
217
+ if response.ok and manifest['count']:
218
+ images = list(filter(lambda x: x['architecture'] == "amd64", manifest['results'][0]['images']))
219
+ if len(images):
220
+ return images[0]['digest']
221
+
222
+ return None
223
+
224
+
225
+ @functools.lru_cache(8)
226
+ def fetch_versions_from_server(pkg_url: str, parser: Type[PackageHTMLParser] = LinkHTMLParser) -> List[str]:
227
+ """
228
+ Fetch all versions from server.
229
+
230
+ Args:
231
+ pkg_url: Url to fetch
232
+ parser: Parser tp use
233
+
234
+ Returns:
235
+ All the releases for a package
236
+ """
237
+ resp = requests.get(pkg_url)
238
+ pkg_name = pkg_url.split('/')[-1]
239
+ if resp.status_code != 200:
240
+ logger.warning(f"Error fetching package {pkg_name} information. Status code: {resp.status_code}")
241
+ return []
242
+
243
+ html_str = resp.text
244
+
245
+ parser = parser()
246
+ parser.feed(html_str)
247
+ releases = parser.pkg_version
248
+ releases = [v for v in releases if not v.startswith('.')]
249
+
250
+ all_releases = sorted(releases, key=parse, reverse=True)
251
+ return all_releases
252
+
253
+
254
+ def fetch_versions_from_artifactory(pkg_name: str, parser: Type[PackageHTMLParser] = LinkHTMLParser) -> List[str]:
255
+ """
256
+ Fetch all versions from server.
257
+
258
+ Args:
259
+ pkg_name: Url to fetch
260
+ parser: Parser tp use
261
+
262
+ Returns:
263
+ Available releases
264
+ """
265
+ pkg_path = IDM_DOCKER_PROD
266
+ pkg_url = os.path.join(pkg_path, pkg_name)
267
+
268
+ resp = requests.get(pkg_url)
269
+ if resp.status_code != 200:
270
+ logger.warning('Could not fetch URL')
271
+ return None
272
+
273
+ html_str = resp.text
274
+
275
+ parser = parser()
276
+ parser.feed(html_str)
277
+ releases = parser.pkg_version
278
+ releases = [v for v in releases if not v.startswith('.')]
279
+
280
+ all_releases = sorted(releases, key=parse, reverse=True)
281
+ return all_releases
282
+
283
+
284
+ @functools.lru_cache(3)
285
+ def get_versions_from_site(pkg_url, base_version: Optional[str] = None, display_all=False,
286
+ parser: Type[PackageHTMLParser] = LinkNameParser, exclude_pre_release: bool = True):
287
+ """
288
+ Utility to get the the available versions for a package.
289
+
290
+ The default properties filter out pre releases. You can also include a base version to only list items starting with a particular version
291
+
292
+ Args:
293
+ pkg_url: package name given
294
+ base_version: Optional base version. Versions above this will not be added. For example, to get versions 1.18.5, 1.18.4, 1.18.3, 1.18.2 pass 1.18
295
+ display_all: determine if output all package releases
296
+ parser: Parser needs to be a HTMLParser that returns a pkg_versions
297
+ exclude_pre_release: Exclude prerelease versions
298
+
299
+ Returns: the latest version of ven package
300
+
301
+ Raises:
302
+ ValueError - If a latest versions cannot be determined
303
+ """
304
+ all_releases = fetch_versions_from_server(pkg_url, parser=parser)
305
+ if all_releases is None:
306
+ raise ValueError(
307
+ f"Could not determine latest version for package {pkg_url}. You can manually specify a version to avoid this error")
308
+
309
+ if display_all:
310
+ print(all_releases)
311
+ if exclude_pre_release:
312
+ ver_pattern = re.compile(r'^[\d\.]+$')
313
+ release_versions = [ver for ver in all_releases if ver_pattern.match(ver)]
314
+ else:
315
+ release_versions = all_releases
316
+
317
+ if base_version:
318
+ release_versions = [ver for ver in release_versions if ver.startswith(base_version)]
319
+
320
+ # comps_ssmt_worker will store only x.x.x.x
321
+ if 'comps_ssmt_worker' in pkg_url.lower():
322
+ release_versions = [ver for ver in release_versions if len(ver.split('.')) == 4]
323
+ return release_versions
324
+
325
+
326
+ @functools.lru_cache(3)
327
+ def get_latest_version_from_site(pkg_url, base_version: Optional[str] = None, display_all=False,
328
+ parser: Type[PackageHTMLParser] = LinkNameParser, exclude_pre_release: bool = True):
329
+ """
330
+ Utility to get the latest version for a given package name.
331
+
332
+ Args:
333
+ pkg_url: package name given
334
+ base_version: Optional base version. Versions above this will not be added.
335
+ display_all: determine if output all package releases
336
+ parser: Parser needs to be a HTMLParser that returns a pkg_versions
337
+ exclude_pre_release: Exclude pre-release versions
338
+
339
+ Returns: the latest version of ven package
340
+ """
341
+ if logger.isEnabledFor(DEBUG):
342
+ logger.debug(f"Fetching version from {pkg_url} with base {base_version}")
343
+ release_versions = get_versions_from_site(pkg_url, base_version, display_all=display_all, parser=parser,
344
+ exclude_pre_release=exclude_pre_release)
345
+ if base_version:
346
+ # only use the longest match latest
347
+ version_compatible_portion = ".".join(base_version.split(".")[:2])
348
+ if logger.isEnabledFor(DEBUG):
349
+ logger.debug(
350
+ f"Finding latest of matches for version {base_version} from {release_versions} using {version_compatible_portion}")
351
+
352
+ for ver in release_versions:
353
+ if ".".join(ver.split('.')[:2]) == version_compatible_portion:
354
+ return ver
355
+ return None
356
+ return release_versions[0] if release_versions else None
357
+
358
+
359
+ def fetch_package_versions_from_pypi(pkg_name):
360
+ """
361
+ Utility to get the latest version for a given package name.
362
+
363
+ Args:
364
+ pkg_name: package name given
365
+
366
+ Returns: the latest version of ven package
367
+ """
368
+ url = PKG_PYPI.format(pkg_name)
369
+ try:
370
+ releases = json.loads(request.urlopen(url).read())['releases']
371
+ except Exception:
372
+ return None
373
+
374
+ return releases
375
+
376
+
377
+ def fetch_package_versions(pkg_name, is_released=True, sort=True, display_all=False):
378
+ """
379
+ Utility to get the latest version for a given package name.
380
+
381
+ Args:
382
+ pkg_name: package name given
383
+ is_released: get released version only
384
+ sort: make version sorted or not
385
+ display_all: determine if output all package releases
386
+
387
+ Returns: the latest version of ven package
388
+ """
389
+ # First fetch versions from Artifactory
390
+ pkg_url = "/".join([PYPI_PRODUCTION_SIMPLE, pkg_name])
391
+ versions = fetch_versions_from_server(pkg_url, parser=LinkNameParser)
392
+
393
+ if versions is None:
394
+ versions = fetch_package_versions_from_pypi(pkg_name)
395
+
396
+ if sort:
397
+ versions = sorted(versions, key=parse, reverse=True)
398
+
399
+ if is_released:
400
+ versions = [ver for ver in versions if not parse(ver).is_prerelease]
401
+
402
+ if display_all:
403
+ print(display_all)
404
+
405
+ return versions
406
+
407
+
408
+ def get_highest_version(pkg_requirement: str):
409
+ """
410
+ Utility to get the latest version for a given package name.
411
+
412
+ Args:
413
+ pkg_requirement: package requirement given
414
+ Returns: the highest valid version of the package
415
+ """
416
+ req = Requirement(pkg_requirement)
417
+ available_versions = fetch_package_versions(req.name)
418
+
419
+ # Filter versions that satisfy the specifier
420
+ valid_versions = [Version(version) for version in available_versions if parse(version) in req.specifier]
421
+
422
+ if not valid_versions:
423
+ return None # No valid versions found
424
+
425
+ # Return the highest valid version
426
+ return str(max(valid_versions))
427
+
428
+
429
+ def get_latest_version(pkg_name):
430
+ """
431
+ Utility to get the latest version for a given package name.
432
+
433
+ Args:
434
+ pkg_name: package name given
435
+
436
+ Returns: the latest version of package
437
+ """
438
+ version = get_highest_version(pkg_name)
439
+ if version is None:
440
+ user_logger.info(f"No valid versions found for '{pkg_name}'")
441
+ exit(1)
442
+ return version
443
+
444
+
445
+ def get_latest_compatible_version(pkg_name, base_version=None, versions=None, validate=True):
446
+ """
447
+ Utility to get the latest compatible version from a given version list.
448
+
449
+ Args:
450
+ base_version: Optional base version. Versions above this will not be added.
451
+ pkg_name: package name given
452
+ versions: user input of version list
453
+ validate: bool, if True, will validate base_version
454
+
455
+ Returns: the latest compatible version from versions
456
+
457
+ Raises:
458
+ Exception - If we cannot find version
459
+ Notes:
460
+ - TODO - Make custom exception or use ValueError
461
+ """
462
+ if versions is None:
463
+ versions = fetch_package_versions(pkg_name)
464
+
465
+ # Return None if given version list is None or empty
466
+ if not versions:
467
+ return None
468
+
469
+ # Return the latest version if no base_version is given
470
+ if base_version is None:
471
+ return versions[0]
472
+
473
+ # Cleanup
474
+ base_version = base_version.replace('+nightly', '')
475
+
476
+ # Make sure the input is valid
477
+ parsed_version_to_check = parse(base_version)
478
+
479
+ # Check if the version is in the list
480
+ is_in_list = any(parsed_version_to_check == parse(version) for version in versions)
481
+ if not is_in_list and validate:
482
+ user_logger.info(f"Could not find the version of '{base_version}' for '{pkg_name}'.")
483
+ return None
484
+
485
+ # Find all possible candidates
486
+ candidates = [version for version in versions if version.startswith(base_version)]
487
+
488
+ # Pick the latest
489
+ return candidates[0]
@@ -0,0 +1,4 @@
1
+ """idmtools python requirement ac output.
2
+
3
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
4
+ """
@@ -0,0 +1,155 @@
1
+ """idmtools create asset collection script.
2
+
3
+ This is part of the RequirementsToAssetCollection tool. This is ran on the SSMT to convert installed files to a AssetCollection.
4
+
5
+ Copyright 2021, Bill & Melinda Gates Foundation. All rights reserved.
6
+ """
7
+ import os
8
+ import sys
9
+ from COMPS import Client
10
+ from COMPS.Data import AssetCollectionFile, QueryCriteria
11
+ from COMPS.Data import Experiment
12
+ from COMPS.Data.AssetCollection import AssetCollection
13
+ from idmtools.utils.hashing import calculate_md5
14
+
15
+ MD5_KEY = 'idmtools-requirements-md5-{}'
16
+ AC_FILE = 'ac_info.txt'
17
+ LIBRARY_ROOT_PREFIX = 'L'
18
+
19
+
20
+ def build_asset_file_list(prefix=LIBRARY_ROOT_PREFIX):
21
+ """
22
+ Utility function to build all library files.
23
+
24
+ Args:
25
+ prefix: used to identify library files
26
+
27
+ Returns: file paths as a list
28
+ """
29
+ output = []
30
+ for root, _, filenames in os.walk(prefix):
31
+ for filename in filenames:
32
+ asset = AssetCollectionFile(file_name=os.path.basename(filename),
33
+ relative_path=os.path.join("site-packages",
34
+ root.replace(prefix, "").strip("/")).strip("/"),
35
+ md5_checksum=calculate_md5(os.path.join(root, filename))
36
+ )
37
+ output.append(asset)
38
+
39
+ return output
40
+
41
+
42
+ def get_first_simulation_of_experiment(exp_id):
43
+ """
44
+ Retrieve the first simulation from an experiment.
45
+
46
+ Args:
47
+ exp_id: use input (experiment id)
48
+
49
+ Returns: list of files paths
50
+ """
51
+ comps_exp = Experiment.get(exp_id)
52
+ comps_sims = comps_exp.get_simulations(QueryCriteria().select_children('hpc_jobs'))
53
+ comps_sim = comps_sims[0]
54
+
55
+ return comps_sim
56
+
57
+
58
+ def main(): # pragma: no cover
59
+ """Main entry point for our create asset collection script."""
60
+ print(sys.argv)
61
+
62
+ if len(sys.argv) < 3:
63
+ raise Exception(
64
+ "The script needs to be called with `python <model.py> <experiment_id> <endpoint> <os_str>'.\n{}".format(
65
+ " ".join(sys.argv)))
66
+
67
+ # Get the experiments
68
+ exp_id = sys.argv[1]
69
+ print('exp_id: ', exp_id)
70
+
71
+ # Get endpoint
72
+ endpoint = sys.argv[2]
73
+ print('endpoint: ', endpoint)
74
+
75
+ # Platform key
76
+ os_target = sys.argv[3]
77
+ print('os: ', os_target)
78
+
79
+ client = Client()
80
+ client.login(endpoint)
81
+
82
+ # Retrieve the first simulation of the experiment
83
+ comps_sim = get_first_simulation_of_experiment(exp_id)
84
+ print('sim_id: ', comps_sim.id)
85
+
86
+ # Build files metadata
87
+ base_path = os.path.join(comps_sim.hpc_jobs[-1].working_directory, LIBRARY_ROOT_PREFIX)
88
+ asset_files = build_asset_file_list(prefix=base_path)
89
+ print('asset files count: ', len(asset_files))
90
+
91
+ # Output files
92
+ max_files = 10
93
+ print('Display the first 10 files:\n',
94
+ "\n".join([f"{a.relative_path}/{a.file_name}" for a in asset_files[0:max_files]]))
95
+
96
+ # Retrieve experiment's tags
97
+ comps_exp = Experiment.get(exp_id, QueryCriteria().select_children('tags'))
98
+ exp_tags = comps_exp.tags
99
+
100
+ # Retrieve experiment's tags
101
+ _reserved_tag = ['idmtools', 'task_type', MD5_KEY.format(os_target)]
102
+ comps_exp = Experiment.get(exp_id, QueryCriteria().select_children('tags'))
103
+ user_tags = {key: value for key, value in comps_exp.tags.items() if key not in _reserved_tag}
104
+
105
+ # Get md5_str
106
+ md5_str = exp_tags.get(MD5_KEY.format(os_target), None)
107
+
108
+ # Collect ac's tags
109
+ ac = AssetCollection()
110
+ tags = {MD5_KEY.format(os_target): md5_str}
111
+ tags.update(user_tags)
112
+ ac.set_tags(tags)
113
+
114
+ # Create asset collection
115
+ for af in asset_files:
116
+ ac.add_asset(af)
117
+
118
+ sys.stdout.flush()
119
+ missing_files = ac.save(return_missing_files=True)
120
+
121
+ # If COMPS responds that we're missing some files, then try creating it again,
122
+ # uploading only the files that COMPS doesn't already have.
123
+ if missing_files:
124
+ print(f"Total of {len(ac.assets) - len(missing_files)} files currently in comps. Resolving missing files")
125
+ ac2 = AssetCollection()
126
+ ac2.set_tags(tags)
127
+
128
+ for acf in ac.assets:
129
+ if acf.md5_checksum in missing_files:
130
+ rp = acf.relative_path
131
+ fn = acf.file_name
132
+ acf2 = AssetCollectionFile(fn, rp, tags=acf.tags)
133
+ rfp = os.path.join(base_path, rp.replace("site-packages", "").strip(os.path.sep), fn)
134
+ ac2.add_asset(acf2, rfp)
135
+ else:
136
+ ac2.add_asset(acf)
137
+
138
+ print("\n\n\n=====================\nUploading files not in comps: " + "\n".join(
139
+ [f"{a.relative_path}/{a.file_name}" for a in ac2.assets if
140
+ a.md5_checksum in missing_files or a.md5_checksum is None]))
141
+
142
+ sys.stdout.flush()
143
+ ac2.save()
144
+ ac = ac2
145
+ # Output ac
146
+ print('ac_id: ', ac.id)
147
+
148
+ # write ac_id to file ac_info.txt
149
+ with open(AC_FILE, 'w') as outfile:
150
+ outfile.write(str(ac.id))
151
+ sys.stdout.flush()
152
+
153
+
154
+ if __name__ == "__main__": # pragma: no cover
155
+ main()