openGauss-OM/script/gspylib/common/CommandLineParser.py
2020-12-16 17:25:24 +08:00

408 lines
17 KiB
Python

# -*- coding:utf-8 -*-
# Copyright (c) 2020 Huawei Technologies Co.,Ltd.
#
# openGauss is licensed under Mulan PSL v2.
# You can use this software according to the terms
# and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# ----------------------------------------------------------------------------
"""
@brief The command line parser module.
@details Parse command line parameters and store them as variables with
the same name.
"""
# export module
__all__ = ["CommandLineParser", "Option"]
# system import.
import sys as _sys
import optparse as _optparse
# import typing for comment.
try:
from typing import Dict
from typing import List
from typing import Tuple
from typing import Any
except ImportError:
Dict = dict
List = list
Tuple = tuple
Any = str or int or complex or list or dict
# local import
from gspylib.common.ErrorCode import ErrorCode
class Option(_optparse.Option, object):
"""
The command line option class which use to the "OptionParser" instance.
But this class does not accept the "dest"
parameter.
"""
def __init__(self, *args, **kwargs):
"""
Initialize the command line option instance.
:param args: The command line command string, maximum
length is 2.
:param kwargs: The command line command parameters.
:param action: The named parameter, specified command line
parameter action allowed by option parser.
:param type: The named parameter, specified command line
parameter type of current option.
:param default: The named parameter, specified command line
parameter default value.
:param nargs: The named parameter, specified the number of
the command line parameter value.
:param const: The named parameter, specified the const
value of the command line parameter.
:param choices: The named parameter, specified the choice
range of the command line parameter, the item
in the choices list must be string type,
and must not set the "type" parameter.
Otherwise, it will lead to unexpected errors.
:param callback: The named parameter, specified the handler
function for the command line parameter.
:param callback_args: The named parameter, specified the unnamed
parameters of the handler function for the
command line parameter.
:param callback_kwargs: The named parameter, specified the named
parameters of the handler function for the
command line parameter.
:param help: The named parameter, the help string for the
command line parameter.
:param metavar: The named parameter, the display string for
the command line parameter value.
:type args: str
:type kwargs: *
:type action: str
:type type: str
:type default: *
:type nargs: int
:type const: *
:type choices: List[str]
:type callback: function
:type callback_args: tuple
:type callback_kwargs: dict
:type help: str
:type metavar: str
"""
# Remove the "dest" parameter.
if "dest" in kwargs:
kwargs.pop("dest")
# Initialize the command line option instance.
_optparse.Option.__init__(self, *args, **kwargs)
class OptionParser(_optparse.OptionParser, object):
"""
The command line option parser.
"""
def __init__(self, *args, **kwargs):
"""
Initialize the internal command line parser.
:param args: The additional unnamed parameter of the
command line parser.
:param kwargs: The additional named parameter of the
command line parser.
:param usage: A usage string for your program. Before
it is displayed to the user, "%prog" will
be expanded to the name of your program
(prog or os.path.basename(sys.argv[0])).
:param option_list: A list of option instance for this parser.
:param option_class: The command line option class type,
default is "optparse.Option".
:param version: The version string for this scripts.
:param conflict_handler: The solutions after command line options
conflict, "resolve" will override before
option, "errors" will raise error,
default is "error".
:param description: A paragraph of text giving a brief
overview of your program. optparse re-formats
this paragraph to fit the current
terminal width and prints it when the user
requests help (after usage, but before
the list of options).
:param formatter: The formatter instance for the
description information.
:param add_help_option: Whether add the help option instance
automatically.
:param prog: The name of the current program (to
override os.path.basename(sys.argv[0])).
:param epilog: A paragraph of help text to print after
option help.
:type args: str | list | bool | type |
_optparse.IndentedHelpFormatter
:type kwargs: str | list | bool | type |
_optparse.IndentedHelpFormatter
:type usage: str
:type option_list: List[Option]
:type option_class: type
:type version: str
:type conflict_handler: str
:type description: str
:type formatter: _optparse.IndentedHelpFormatter
:type add_help_option: bool
:type prog: str
:type epilog: str
"""
# Call the parent init function.
_optparse.OptionParser.__init__(self, *args, **kwargs)
def print_help(self, _file=_sys.stderr):
"""
print_help(file : file = stderr)
Print an extended help message, listing all options and any help
text provided with them, to 'file' (default
stderr).
:param _file: The file descriptor instance.
:type _file: file
:rtype: None
"""
_optparse.OptionParser.print_help(self, _file)
def print_usage(self, _file=_sys.stderr):
"""
print_usage(file : file = stderr)
Print the usage message for the current program (self.usage) to
'file' (default stderr). Any occurrence of the
string "%prog" in self.usage is replaced with the name of the
current program (basename of sys.argv[0]).
Does nothing if self.usage is empty or not defined.
:param _file: The file descriptor instance.
:type _file: file
:rtype: None
"""
_optparse.OptionParser.print_usage(self, _file)
def print_version(self, _file=_sys.stderr):
"""
print_version(file : file = stderr)
Print the version message for this program (self.version) to 'file'
(default stderr). As with print_usage(),
any occurrence of "%prog" in self.version is replaced by the
current program's name. Does nothing if
self.version is empty or undefined.
:param _file: The file descriptor instance.
:type _file: file
:rtype: None
"""
_optparse.OptionParser.print_version(self, _file)
def error(self, _msg):
"""
error(msg : string)
Print a usage message incorporating 'msg' to stderr and exit. If you
override this in a subclass, it should not
return -- it should either exit or raise an exception.
:param _msg: The error message.
:type _msg: str
:rtype: None
"""
raise Exception(ErrorCode.GAUSS_500["GAUSS_50015"] % _msg)
class CommandLineMetaClass(type):
"""
The command line parser metaclass.
Used to magically save command line parsing options instances.
"""
def __new__(mcs, name, bases, attrs):
"""
Create an new command line parser class.
:param name: The name of the current class.
:param bases: The parent instances of the current class.
:param attrs: The attribute dict of the current class.
:type name: str
:type bases: Tuple[type]
:type attrs: Dict[str, Any]
:return:
"""
# If it is the base command line parser class, we will do nothing.
if name == "CommandLineOption":
return type.__new__(mcs, name, bases, attrs)
# Store the command line option instance mapping.
mappings = {}
# Store the attribute key-value pair list of the current class.
items = list(attrs.items())
# Store the command line option instance to the mapping, and remove
# it from current class attribute.
for key, value in items:
if isinstance(value, Option):
mappings.setdefault(key, value)
attrs.pop(key)
# Add the additional function.
if value.action in ["append", "append_const", "count"]:
def ensure_value(_self, _attr, _value):
"""
Ensure the non-existence of object attributes and
set the value of attributes.
:param _self: The object instance.
:param _attr: The object attribute name.
:param _value: The object attribute value.
:type _self: Option
:type _attr: str
:type _value: *
:return: Return the object attribute value.
:rtype: *
"""
if not hasattr(_self, _attr) or getattr(_self,
_attr) is None:
setattr(_self, _attr, _value)
return getattr(_self, _attr)
# Add function.
attrs["ensure_value"] = ensure_value
# Store the mapping into a named parameter of current class.
attrs["__mappings__"] = mappings
return type.__new__(mcs, name, bases, attrs)
class CommandLineParser(object):
"""
The base class of the command line parser.
"""
# Set the metaclass type, this approach is not supported python 3.x.
__metaclass__ = CommandLineMetaClass
def __init__(self, _parameters=None, *args, **kwargs):
"""
Initialize the command line parser.
:param _parameters: The command line parameters list,
default is sys.argv.
:param args: The additional unnamed parameter of the
command line parser.
:param kwargs: The additional named parameter of the
command line parser.
:param usage: A usage string for your program. Before
it is displayed to the user, "%prog" will
be expanded to the name of your program
(prog or os.path.basename(sys.argv[0])).
:param option_list: A list of option instance for this parser.
:param option_class: The command line option class type,
default is "optparse.Option".
:param version: The version string for this scripts.
:param conflict_handler: The solutions after command line options
conflict, "resolve" will override before
option, "errors" will raise error,
default is "error".
:param description: A paragraph of text giving a brief
overview of your program. optparse re-formats
this paragraph to fit the current
terminal width and prints it when the user
requests help (after usage, but before
the list of options).
:param formatter: The formatter instance for the
description information.
:param add_help_option: Whether add the help option instance
automatically.
:param prog: The name of the current program (to
override os.path.basename(sys.argv[0])).
:param epilog: A paragraph of help text to print after
option help.
:type _parameters: List[str] | None
:type args: str | list | bool | type |
_optparse.IndentedHelpFormatter
:type kwargs: str | list | bool | type |
_optparse.IndentedHelpFormatter
:type usage: str
:type option_list: List[Option]
:type option_class: type
:type version: str
:type conflict_handler: str
:type description: str
:type formatter: _optparse.IndentedHelpFormatter
:type add_help_option: bool
:type prog: str
:type epilog: str
"""
# Create a new command line parser.
opt = OptionParser(*args, **kwargs)
# Add the "dest" attribute to the command line option instance,
# and add the option instance to the parser.
# noinspection PyUnresolvedReferences
for key, value in list(self.__mappings__.items()):
setattr(value, "dest", key)
opt.add_option(value)
# Parse the command line parameter.
if not _parameters:
_parameters = _sys.argv[1:]
_, unknown_args = opt.parse_args(_parameters, self)
# If some command line parameter does not supplied by user, we will
# set it to "None".
# noinspection PyUnresolvedReferences
for key in list(self.__mappings__.keys()):
if not hasattr(self, key):
# noinspection PyUnresolvedReferences
value = self.__mappings__.get(key)
if hasattr(value, "default") and getattr(value,
"default") != \
_optparse.NO_DEFAULT:
setattr(self, key, getattr(value, "default"))
elif hasattr(value, "const") and getattr(value,
"const") != \
_optparse.NO_DEFAULT:
setattr(self, key, getattr(value, "const"))
else:
setattr(self, key, None)
# If it contains configuration that cannot be resolved, save it.
if unknown_args:
setattr(self, "unknown_args", unknown_args)
class ExecuteCommand(object):
"""
"""
def __init__(self):
"""
"""
pass