Skip to content

Commit 1c9fb74

Browse files
committed
Added support for mvscmd
Create something that hides some of the complexity associated with creating ddd. Signed-off-by: Frank De Gilio <degilio@us.ibm.com>
1 parent 0a6935c commit 1c9fb74

2 files changed

Lines changed: 220 additions & 0 deletions

File tree

samples/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,10 @@ There are also longer scripts that can be useful:
1717
|[smpe_list.py](smpe_list.py) | Sample code showing how to convert from JCL to Python using the list feature of SMPE.
1818
|[SMPElistDefaults.yaml](SMPElistDefaults.yaml) | Definitions that `smpe_list.py` needs. Must be put in the same directory as `smpe_list.py`. Changes need to be made to match the user's system.
1919
|[console.sh](console.sh)|Run `opercmd` interactively.
20+
<<<<<<< Updated upstream
21+
=======
22+
|[member_copy.py](member_copy.py) | Copy members from one data set to another.
23+
|[mvs_command_support.py](mvs_command_support.py) | Set of helper functions to help people using mvscommand. Useful for people who are new to the platform.
24+
>>>>>>> Stashed changes
2025
|[runjcl.py](runjcl.py)| Submit a JCL job and print job status.
2126
|[runrexx.py](runrexx.py)| Run a Rexx program in IKJEFT01 and return the data for processing

samples/mvs_command_support.py

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
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

Comments
 (0)