1+ #!/usr/bin/env python3
2+ """Provide support for mvscmd dds
3+ """
4+ import os
5+ import subprocess
6+ from datetime import datetime
7+ from zoautil_py import datasets , mvscmd
8+ from zoautil_py .types import DDStatement , FileDefinition , DatasetDefinition
9+
10+ _mcs_data_set_list = []
11+
12+ def get_zos_userid () -> str :
13+ """Get the z/OS userid from the system.
14+ Parameters: None
15+ Return:
16+ user_id - <str>: The z/OS user id of the caller
17+ """
18+ uid = str (subprocess .run (["id" ], shell = True , capture_output = True , check = False ).stdout )
19+ user_id = uid [(uid .find ("(" )+ 1 ):uid .find (")" )]
20+ return user_id
21+
22+
23+ def create_temp_dataset (options : dict = None ) -> dict :
24+ """Create a temporary dataset.
25+ Create a dataset and return all the necessary info about it as a dictionary
26+
27+ Paramters:
28+ options - <dict> (optional): All of the options that one could set to create
29+ a dataset in ZOAU. Defaults to None.
30+ Return:
31+ dataset_dictionary - <dict>: A complete dictionary contains info of the
32+ created temporary dataset
33+ """
34+ zos_userid = get_zos_userid ()
35+ dataset_name = f"{ zos_userid } .TEMPRARY"
36+ dataset_name = datasets .tmp_name (dataset_name )
37+ _mcs_data_set_list .append (dataset_name )
38+ if options is None :
39+ dataset_object = datasets .create (dataset_name ,"SEQ" ,)
40+ else :
41+ dataset_object = datasets .create (dataset_name , ** options )
42+ return dataset_object .to_dict ()
43+
44+ def create_non_temp_dataset (options : dict = None ) -> dict :
45+ """Create a temporary dataset.
46+ Create a dataset and return all the necessary info about it as a dictionary
47+
48+ Paramters:
49+ options - <dict> (optional): All of the options that one could set to create
50+ a dataset in ZOAU. Defaults to None.
51+ Return:
52+ dataset_dictionary - <dict>: A complete dictionary contains info of the
53+ created temporary dataset
54+ """
55+ if options is None or "name" not in options :
56+ zos_userid = get_zos_userid ()
57+ dataset_name = datasets .tmp_name (zos_userid )
58+ else :
59+ dataset_name = datasets .tmp_name (options ["name" ])
60+ if options is None :
61+ dataset_object = datasets .create (dataset_name ,"SEQ" )
62+ else :
63+ dataset_object = datasets .create (dataset_name , ** options )
64+
65+ # Keep track of datasets you create in a global variable
66+ _mcs_data_set_list .append (dataset_name )
67+
68+ return dataset_object .to_dict ()
69+
70+ def get_temp_file_name (name : str = None , working_directory : str = "/tmp" ) -> str :
71+ """Define a temporary filename to be used the filesystem
72+
73+ Parameters:
74+ name - <str> (optional): A string containing the name of the file.
75+ Defaults to None
76+ working_directory - <str>(optional): A directory where the file can live.
77+ Defaults to tmp
78+ Return:
79+ filename - <str>: The name of the created file
80+ """
81+ # First lets make sure the name has the word TEMPORARY in it
82+ if name is None :
83+ name = "TEMPRARY"
84+ else :
85+ name = f"{ name } .TEMPRARY"
86+
87+ # We get a data and timestamp to ensure that the file name is unique
88+ static_time = str (datetime .now ().timestamp ())
89+ temp_file_name = f"{ working_directory } /{ name } .{ static_time } "
90+
91+ # Keep track of all the files in our global _mcs_data_set_list too
92+ _mcs_data_set_list .append (temp_file_name
93+ )
94+ # Now we can return the generated name
95+ return temp_file_name
96+
97+
98+
99+ def create_input_file (input_list : list , input_file_name : str , codepage : str = "cp1047" ):
100+ """Create the input file that will be used for an input DD. It is meant to
101+ fit the 72 character limit that is in JCL card decks
102+
103+ Parameters:
104+ input_list - <list>: List of strings containing the input
105+ input_file_name - <str>: The name of the file
106+ codepage - <str> (optional): The codepage to use when writing the data.
107+ Defaults to "cp1047".
108+ """
109+ # (make sure it's EBCDIC and less than 72 bytes)
110+ with open (input_file_name , "w" , encoding = codepage ) as sysin :
111+ for listitem in input_list :
112+ if len (listitem ) > 72 :
113+ print ("Input lines must be less than 72 chars\n " )
114+ print (f"{ listitem } is length: { len (listitem )} and is ignored" )
115+
116+ else :
117+ sysin .write (f"{ listitem } \n " )
118+
119+
120+ def create_input_dd (input_list : list , ddname : str = "SYSIN" )-> DDStatement :
121+ """Create an input DD basedd on a list
122+
123+ Parameters:
124+ input_list - <list>: A list of strings which is input to the DD
125+ ddname - <str> (optional): The DDName used for input. Defaults to "SYSIN".
126+ Return:
127+ <DDStatement>: The created DD statement
128+ """
129+ # First we need to create the name of the temporary file
130+ # Use the ddname in the file
131+ temporary_file_name = get_temp_file_name (ddname )
132+
133+ # Now create the file that will hold the input
134+ create_input_file (input_list , temporary_file_name )
135+
136+ # Now create the DD that will hold the input
137+
138+ return DDStatement (ddname , FileDefinition (temporary_file_name ))
139+
140+
141+ def cleanup_temporaries (debugging :bool = False ):
142+ """Remove any temporary files or datasets
143+
144+ Args:
145+ debugging - <bool> (optional): Debug flag. If set keep files around
146+ _mcs_data_set_list - <list> (implicit): Global variable that is updated
147+ whenever a dataaet or file is created
148+ Return:
149+ None
150+ """
151+ for dataset in _mcs_data_set_list :
152+ print (dataset )
153+ if "TEMPRARY" in dataset :
154+ if "/" in dataset :
155+ if debugging :
156+ print (f"Temporary file: { dataset } has not been erased" )
157+ else :
158+ os .remove (dataset )
159+ else :
160+ if debugging :
161+ print (f"Temporary Dataset: { dataset } has not been erased" )
162+ else :
163+ # All uppercase names are DATASETS
164+ return_code = datasets .delete (dataset )
165+ if return_code != 0 :
166+ print (f"Error erasing { dataset } " )
167+
168+ def main ():
169+ """Test this with a SMPE list
170+ """
171+ # First define a list of DD statements
172+ dd_list = []
173+
174+ # Create an input dd to list the Global Zone
175+ dd_list .append (create_input_dd ([" SET BDY(GLOBAL)." ," LIST. " ],ddname = "SMPCNTL" ))
176+
177+ # Define the Workspace dataset
178+ workspace_dataset = {"type" :"PDS" ,"primary_space" :"1G" ,"secondary_space" :"1G" ,
179+ "block_size" :3200 ,"record_format" :"FB" ,"record_length" :80 ,
180+ "volumes" :"USRAT8" }
181+ workspace_dataset = create_temp_dataset (workspace_dataset )
182+
183+ # Add it to the DD list
184+ dd_list .append (DDStatement ("SMPWRK6" ,DatasetDefinition (workspace_dataset ["name" ])))
185+
186+ # Define the Dummy DDs
187+ dd_list .append (DDStatement ("SMPLOG" ,"DUMMY" ))
188+ dd_list .append (DDStatement ("SMPLOGA" ,"DUMMY" ))
189+
190+ # Define the Global CSI
191+ dd_list .append (DDStatement ("SMPCSI" ,DatasetDefinition ("AT4SMP.GLOBAL.CSI" )))
192+
193+ # Define the output dataset
194+ output_dataset = {"type" :"SEQ" ,"primary_space" :"5M" ,"secondary_space" :"5M" ,"volumes" :"USRAT8" }
195+
196+ # Create the output dataset
197+ output_dataset = create_non_temp_dataset (output_dataset )
198+
199+ # Add it to the DD list
200+ dd_list .append (DDStatement ("SMPLIST" ,DatasetDefinition (output_dataset ['name' ])))
201+
202+ # Now run the Command
203+ command_return_dictionary = mvscmd .execute_authorized (pgm = "GIMSMP" , dds = dd_list ).to_dict ()
204+
205+ if command_return_dictionary ['rc' ]> 0 :
206+ print (f"Command failed with a return code of: { command_return_dictionary ['rc' ]} " )
207+ else :
208+ print (f"Command succeeded. Output can be found in: { output_dataset ['name' ]} " )
209+
210+ # Remove the temporary file and Dataset
211+ cleanup_temporaries (False )
212+
213+ if __name__ == "__main__" :
214+ main ()
215+
0 commit comments