1
1
import typing as ty
2
2
import json
3
3
import attr
4
+ from urllib .request import urlretrieve
4
5
import subprocess as sp
5
6
import os
6
7
from pathlib import Path
@@ -25,7 +26,7 @@ class BoshTask(ShellCommandTask):
25
26
26
27
def __init__ (
27
28
self ,
28
- zenodo = None ,
29
+ zenodo_id = None ,
29
30
bosh_file = None ,
30
31
audit_flags : AuditFlag = AuditFlag .NONE ,
31
32
cache_dir = None ,
@@ -43,7 +44,7 @@ def __init__(
43
44
44
45
Parameters
45
46
----------
46
- zenodo : :obj: str
47
+ zenodo_id : :obj: str
47
48
Zenodo ID
48
49
bosh_file : : str
49
50
json file with the boutiques descriptors
@@ -65,16 +66,19 @@ def __init__(
65
66
TODO
66
67
67
68
"""
68
- if (bosh_file and zenodo ) or not (bosh_file or zenodo ):
69
- raise Exception ("either bosh or zenodo has to be specified" )
70
- elif zenodo :
71
- bosh_file = self ._download_spec (zenodo )
69
+ self .cache_dir = cache_dir
70
+ if (bosh_file and zenodo_id ) or not (bosh_file or zenodo_id ):
71
+ raise Exception ("either bosh or zenodo_id has to be specified" )
72
+ elif zenodo_id :
73
+ self .bosh_file = self ._download_spec (zenodo_id )
74
+ else :
75
+ self .bosh_file = bosh_file
72
76
73
77
# retry logic - an error on travis is raised randomly, not able to reproduce
74
78
tries , tries_max = 0 , 7
75
79
while tries < tries_max :
76
80
try :
77
- with bosh_file .open () as f :
81
+ with self . bosh_file .open () as f :
78
82
self .bosh_spec = json .load (f )
79
83
break
80
84
except json .decoder .JSONDecodeError :
@@ -88,37 +92,42 @@ def __init__(
88
92
if output_spec is None :
89
93
output_spec = self ._prepare_output_spec ()
90
94
self .output_spec = output_spec
91
- self .bindings = []
95
+ self .bindings = ["-v" , f" { self . bosh_file . parent } : { self . bosh_file . parent } :ro" ]
92
96
93
97
super (BoshTask , self ).__init__ (
94
98
name = name ,
95
99
input_spec = input_spec ,
96
100
output_spec = output_spec ,
97
- executable = ["bosh" , "exec" , "launch" , str ( bosh_file ) ],
101
+ executable = ["bosh" , "exec" , "launch" ],
98
102
args = ["-s" ],
99
103
audit_flags = audit_flags ,
100
104
messengers = messengers ,
101
105
messenger_args = messenger_args ,
102
- cache_dir = cache_dir ,
106
+ cache_dir = self . cache_dir ,
103
107
strip = strip ,
104
108
rerun = rerun ,
105
109
** kwargs ,
106
110
)
107
111
self .strip = strip
108
112
109
- def _download_spec (self , zenodo ):
110
- """ usind bosh pull to download the zenodo file"""
111
- spec_file = (
112
- Path (os .environ ["HOME" ])
113
- / ".cache/boutiques/production"
114
- / (zenodo .replace ("." , "-" ) + ".json" )
115
- )
116
- for i in range (3 ):
117
- if not spec_file .exists ():
118
- sp .run (["bosh" , "pull" , zenodo ])
119
- if not spec_file .exists ():
120
- raise Exception (f"can't pull zenodo file { zenodo } " )
121
- return spec_file
113
+ def _download_spec (self , zenodo_id ):
114
+ """
115
+ usind boutiques Searcher to find url of zenodo file for a specific id,
116
+ and download the file to self.cache_dir
117
+ """
118
+ from boutiques .searcher import Searcher
119
+
120
+ searcher = Searcher (zenodo_id , exact_match = True )
121
+ hits = searcher .zenodo_search ().json ()["hits" ]["hits" ]
122
+ if len (hits ) == 0 :
123
+ raise Exception (f"can't find zenodo spec for { zenodo_id } " )
124
+ elif len (hits ) > 1 :
125
+ raise Exception (f"too many hits for { zenodo_id } " )
126
+ else :
127
+ zenodo_url = hits [0 ]["files" ][0 ]["links" ]["self" ]
128
+ zenodo_file = self .cache_dir / f"zenodo.{ zenodo_id } .json"
129
+ urlretrieve (zenodo_url , zenodo_file )
130
+ return zenodo_file
122
131
123
132
def _prepare_input_spec (self ):
124
133
""" creating input spec from the zenodo file"""
@@ -175,13 +184,17 @@ def _prepare_output_spec(self):
175
184
176
185
def _command_args_single (self , state_ind , ind = None ):
177
186
"""Get command line arguments for a single state"""
178
- input_filepath = self ._input_file (state_ind = state_ind , ind = ind )
187
+ input_filepath = self ._bosh_invocation_file (state_ind = state_ind , ind = ind )
179
188
cmd_list = (
180
- self .inputs .executable + [input_filepath ] + self .inputs .args + self .bindings
189
+ self .inputs .executable
190
+ + [str (self .bosh_file ), input_filepath ]
191
+ + self .inputs .args
192
+ + self .bindings
181
193
)
182
194
return cmd_list
183
195
184
- def _input_file (self , state_ind , ind = None ):
196
+ def _bosh_invocation_file (self , state_ind , ind = None ):
197
+ """creating bosh invocation file - json file with inputs values"""
185
198
input_json = {}
186
199
for f in attr_fields (self .inputs ):
187
200
if f .name in ["executable" , "args" ]:
0 commit comments