-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathviya-ark.py
139 lines (116 loc) · 5.15 KB
/
viya-ark.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
####################################################################
# ### viya-ark.py ###
####################################################################
# ### Author: SAS Institute Inc. ###
####################################################################
# ###
# Copyright (c) 2020, SAS Institute Inc., Cary, NC, USA. ###
# All Rights Reserved. ###
# SPDX-License-Identifier: Apache-2.0 ###
# ###
####################################################################
import importlib
import inspect
import os
import pkgutil
import sys
from viya_ark_library.command import Command
# command line options #
_HELP_SHORT_OPT_ = "h"
_HELP_LONG_OPT_ = "help"
# return codes #
_SUCCESS_RC_ = 0
_BAD_OPT_RC_ = 1
################
# Main #
################
def main(argv: list):
"""
The main executable method for the viya-ark launcher script.
:param argv: The list of arguments passed at invocation.
"""
try:
# get the requested command value #
command_name = argv[0]
# print the usage and exit, if requested #
if command_name in (f"-{_HELP_SHORT_OPT_}", f"--{_HELP_LONG_OPT_}"):
usage(_SUCCESS_RC_)
# convert any dashes in the given command to underscores to align with Pythonic package/module standards #
command_module_name = command_name.replace("-", "_")
# attempt to import the requested command module #
imported_module = None
try:
imported_module = importlib.import_module(f"{command_module_name}.{command_module_name}")
except ModuleNotFoundError:
print()
print(f"ERROR: Command [{command_name}] not found.")
usage(_BAD_OPT_RC_)
# find any attributes in the module that implement the Command class using reflection #
command = None
for attribute_name in dir(imported_module):
# get the current module attribute by name #
attribute = getattr(imported_module, attribute_name)
# if the attribute is: #
# (1) a class -AND- #
# (2) a subclass of Command -AND- #
# (3) not abstract #
# then the attribute defines a command for the project. #
if inspect.isclass(attribute) and issubclass(attribute, Command) and not inspect.isabstract(attribute):
command = attribute
# the Command implementation was found, the loop can break #
break
if command is not None:
# call the Command's run() method to delegate execution to the module, pass all relevant arguments #
command.run(argv[1:])
else:
# if a Command implementation wasn't found, print the usage message #
print()
print(f"ERROR: Command [{command_name}] not found.")
usage(_BAD_OPT_RC_)
except IndexError:
# if the launcher script wasn't given enough args, print the usage #
print()
print("ERROR: A command must be provided.")
usage(_BAD_OPT_RC_)
#################
# Usage #
#################
def usage(exit_code: int):
"""
Prints the usage statement for the viya-ark launcher script and exits with the provided exit_code.
:param exit_code: The code to return upon exit.
"""
commands = list()
# walk through all packages parallel to this script #
paths = [os.path.realpath(os.path.dirname(__file__))]
for importer, name, is_package in pkgutil.walk_packages(path=paths):
# skip any objects that are packages (i.e. not modules) #
if not is_package:
# import the current module #
try:
importlib.import_module(name)
except ModuleNotFoundError as e:
# ignore any issues importing pytest, raise any other module import errors
if e.name != "pytest":
raise e
for subclass in Command.__subclasses__():
# create a tuple of command details by calling the command_name() and command_desc() methods #
command_details = (subclass().command_name(), subclass().command_desc())
# add the command details to the list of discovered commands #
commands.append(command_details)
# print the commands as well as the static help command to stdout #
print()
print(f"Usage: {os.path.basename(__file__)} <command> [options]")
print()
print("Commands:")
for command in commands:
print(" {:<30} {}".format(command[0], command[1]))
help_cmd_display = f"-{_HELP_SHORT_OPT_}, --{_HELP_LONG_OPT_}"
print(" {:<30} {}".format(help_cmd_display, "Display usage for viya-ark."))
print()
sys.exit(exit_code)
##################
# __main__ #
##################
if __name__ == "__main__":
main(sys.argv[1:])