11import typing as ty
22import json
33import attr
4+ from urllib .request import urlretrieve
45import subprocess as sp
56import os
67from pathlib import Path
@@ -25,7 +26,7 @@ class BoshTask(ShellCommandTask):
2526
2627 def __init__ (
2728 self ,
28- zenodo = None ,
29+ zenodo_id = None ,
2930 bosh_file = None ,
3031 audit_flags : AuditFlag = AuditFlag .NONE ,
3132 cache_dir = None ,
@@ -43,7 +44,7 @@ def __init__(
4344
4445 Parameters
4546 ----------
46- zenodo : :obj: str
47+ zenodo_id : :obj: str
4748 Zenodo ID
4849 bosh_file : : str
4950 json file with the boutiques descriptors
@@ -65,16 +66,19 @@ def __init__(
6566 TODO
6667
6768 """
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
7276
7377 # retry logic - an error on travis is raised randomly, not able to reproduce
7478 tries , tries_max = 0 , 7
7579 while tries < tries_max :
7680 try :
77- with bosh_file .open () as f :
81+ with self . bosh_file .open () as f :
7882 self .bosh_spec = json .load (f )
7983 break
8084 except json .decoder .JSONDecodeError :
@@ -88,37 +92,42 @@ def __init__(
8892 if output_spec is None :
8993 output_spec = self ._prepare_output_spec ()
9094 self .output_spec = output_spec
91- self .bindings = []
95+ self .bindings = ["-v" , f" { self . bosh_file . parent } : { self . bosh_file . parent } :ro" ]
9296
9397 super (BoshTask , self ).__init__ (
9498 name = name ,
9599 input_spec = input_spec ,
96100 output_spec = output_spec ,
97- executable = ["bosh" , "exec" , "launch" , str ( bosh_file ) ],
101+ executable = ["bosh" , "exec" , "launch" ],
98102 args = ["-s" ],
99103 audit_flags = audit_flags ,
100104 messengers = messengers ,
101105 messenger_args = messenger_args ,
102- cache_dir = cache_dir ,
106+ cache_dir = self . cache_dir ,
103107 strip = strip ,
104108 rerun = rerun ,
105109 ** kwargs ,
106110 )
107111 self .strip = strip
108112
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
122131
123132 def _prepare_input_spec (self ):
124133 """ creating input spec from the zenodo file"""
@@ -175,13 +184,17 @@ def _prepare_output_spec(self):
175184
176185 def _command_args_single (self , state_ind , ind = None ):
177186 """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 )
179188 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
181193 )
182194 return cmd_list
183195
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"""
185198 input_json = {}
186199 for f in attr_fields (self .inputs ):
187200 if f .name in ["executable" , "args" ]:
0 commit comments