From b89a492b6aab2245380958bac738f1de26e3c803 Mon Sep 17 00:00:00 2001 From: xiubuzhe Date: Tue, 17 Oct 2023 00:47:21 +0800 Subject: fix bash-completion --- etc/bash-complete-sunhpc | 55 ++++ lib/sunhpc/commands/build/initializes/__init__.py | 10 +- lib/sunhpc/commands/report/completion/__init__.py | 8 +- lib/sunhpc/core/app.py | 358 ++++++++++++++++++++++ lib/sunhpc/invoke.py | 2 + sbin/check-port | 46 +++ sbin/sunhpc-completion-backup | 49 --- 7 files changed, 467 insertions(+), 61 deletions(-) create mode 100644 etc/bash-complete-sunhpc create mode 100644 lib/sunhpc/core/app.py create mode 100755 sbin/check-port delete mode 100644 sbin/sunhpc-completion-backup diff --git a/etc/bash-complete-sunhpc b/etc/bash-complete-sunhpc new file mode 100644 index 0000000..fb272fe --- /dev/null +++ b/etc/bash-complete-sunhpc @@ -0,0 +1,55 @@ +# sunhpc(1) completion +# +# /etc/bash_completion.d/sunhpc +# + +_sunhpc_array_delete_at() +{ + eval "local ARRAY=(\"\${$1[@]}\")" + local i + local tmp=() + local lower=$2 + local upper=${3:-$lower} + + for i in "${!ARRAY[@]}"; do + if [[ "$i" -lt "$2" || "$i" -gt "${3-$2}" ]]; then + tmp=("${tmp[@]}" "${ARRAY[$i]}") + fi + done + eval "$1=(\"\${tmp[@]}\")" +} + +_sunhpc() +{ + local cur prev words cword i output + _init_completion || return + + _sunhpc_array_delete_at words $((cword+1)) ${#words[@]} + _sunhpc_array_delete_at words 0 + + for i in ${!words[@]}; do + words[i]="$(printf '%s' "${words[i]}" | xargs printf '%s\n' 2>/dev/null || true)" + done + + if [[ "$cur" =~ ^[[:space:]]+ ]]; then + cur='' + fi + + output="$(sunhpc report completion ${words[@]} 2>/dev/null)" + + if [ $? = 65 ]; then + compopt -o default + COMPREPLY=() + return 0 + fi + + #local IFS=$'\n' + COMPREPLY=( $( compgen -W '$output' -- ${cur} ) ) + + # do not append a space to words that end with = + [[ $COMPREPLY == *= ]] && compopt -o nospace + +} && +complete -F _sunhpc sunhpc + +# ex: ts=4 sw=4 et filetype=sh diff --git a/lib/sunhpc/commands/build/initializes/__init__.py b/lib/sunhpc/commands/build/initializes/__init__.py index acc87f7..2a93015 100644 --- a/lib/sunhpc/commands/build/initializes/__init__.py +++ b/lib/sunhpc/commands/build/initializes/__init__.py @@ -466,12 +466,12 @@ class Command(command): Networks = ''' CREATE TABLE Networks ( ID integer NOT NULL primary key autoincrement, - Node integer(11) default NULL, - MAC varchar(64) default NULL, - IP varchar(32) default NULL, + Node integer(11) default NULL, + MAC varchar(64) default NULL, + IP varchar(32) default NULL, Name varchar(128) default NULL, - Device varchar(32) default NULL, - Subnet integer(11) default NULL, + Device varchar(32) default NULL, + Subnet integer(11) default NULL, Foreign key(subnet) references subnets(id) on delete cascade on update restrict, Foreign key(node) references nodes(id) on delete cascade on update restrict )''' diff --git a/lib/sunhpc/commands/report/completion/__init__.py b/lib/sunhpc/commands/report/completion/__init__.py index aa75f40..b908d5b 100644 --- a/lib/sunhpc/commands/report/completion/__init__.py +++ b/lib/sunhpc/commands/report/completion/__init__.py @@ -67,7 +67,6 @@ class Command(sunhpc.commands.report.command): if o.MustBeRoot and not self.isRootUser(): sys.exit(0) - results = [] for arg in o.usage().split(): tmp = arg.split('=', 1) @@ -77,14 +76,9 @@ class Command(sunhpc.commands.report.command): tmpstr = arg.replace('[', '') tmpstr = tmpstr.replace(']', '') tmpstr = tmpstr.split('=')[0] + '=' - results.append(tmpstr) - #print (' '.join(results)) - - #print ('--add-interface= --set-net=') - print ('--envs= prefix=') - + print (' '.join(results)) RollName = "base" diff --git a/lib/sunhpc/core/app.py b/lib/sunhpc/core/app.py new file mode 100644 index 0000000..2bc627b --- /dev/null +++ b/lib/sunhpc/core/app.py @@ -0,0 +1,358 @@ +# +# Time for an initial checkin. Datastructure and general layout of the +# code is correct. Still need comparison code for File and RPM objects. +# + +import os +import sys +import types +import sunhpc +import getopt +import sunhpc.invoke +import xml +from xml.sax import saxutils +from xml.sax import handler +from xml.sax import make_parser +from xml.sax._exceptions import SAXParseException + +class Application: + + def __init__(self, argv=None): + + # Applets (code in the kickstart graph) doesn't pass sys.argv + # so pick it up anyway to keep everything working. + + if not argv: + argv = sys.argv + + self.args = [] + self.caller_args = argv[1:] + self.usage_command = os.path.basename(argv[0]) + self.usage_name = 'Application' + self.usage_version = 0 + self.rcfileHandler = RCFileHandler + self.rcfileList = [] + self.rcForce = [] + + self.projectName = 'sunhpc' + self.projectVersionName = 'base' + self.projectVersionMajor = sunhpc.version_major + self.projectVersionMinor = sunhpc.version_minor + self.projectVersionMicro = sunhpc.version_micro + + + self.getopt = sunhpc.core.utils.Struct() + self.getopt.s = [ 'h' ] + self.getopt.l = [ 'help', + 'list-rcfiles', + 'list-project-info', + 'rcfile=' + ] + + # Unset our local + try: + os.environ["LANG"] + except KeyError: + pass + + def run(self): + sys.exit(-1) + + def projectInfo(self): + return [ self.projectName, + self.projectVersionName, + int(self.projectVersionMajor), + int(self.projectVersionMinor), + int(self.projectVersionMicro) ] + + def getArgs(self): + return self.args + + def setArgs(self, argslist): + self.args = argslist + + + def parseArgs(self, rcbase=None): + """Parses the command line arguments and all the relevant + resource-control (RC) files for this application. The usage_command + (generally argv[0]) will determine which the name of our rcfile, + unless overrided with the rcbase argument.""" + + # Save any existing options + args = self.getArgs() + + # First pass to get rcfiles specified on the cmd line + self.setArgs(self.caller_args) + self.parseCommandLine(rcfile=1) + + # Parse Resource Control files + self.setArgs([]) + if not rcbase: + rcbase = self.usage_command + self.parseRC(rcbase) + + for rc in self.rcForce: + self.parseRCFile(rc, rcbase) + + # Command line options always win + self.setArgs(args + self.args + self.caller_args) + self.parseCommandLine() + + + def parseRC(self, rcbase, section=None): + rcfile = rcbase + 'rc' + + if not section: + section = rcbase + + # Where we look for resource-control files. First in + # the default 'etc' location, then HOME, finally in this dir. + # We use data from all three, such that later rc files take + # precedence. + + dirList = [ os.path.join(os.sep,'opt', self.projectName, 'etc') ] + if 'HOME' in os.environ: + dirList.append(os.environ['HOME']) + dirList.append('.') + + # Look for both hidden and visible rc files. + for dir in dirList: + self.parseRCFile(os.path.join(dir, '.' + rcfile), section) + self.parseRCFile(os.path.join(dir, rcfile), section) + + def parseRCFile(self, filename, section): + if os.path.isfile(filename) and filename not in self.rcfileList: + self.rcfileList.append(filename) + file = open(filename, 'r') + parser = make_parser() + handler = self.rcfileHandler(self) + if section: + handler.setSection(section) + parser.setContentHandler(handler) + try: + parser.parse(file) + except SAXParseException as msg: + print (filename, "XML parse exception: ", msg) + file.close() + + def parseCommandLine(self, rcfile=0): + """Calls getopt to parse the command line flags. In + rcfile mode we just get --rcfile options.""" + + short = '' + for e in self.getopt.s: + if isinstance(e, tuple): + short = short + e[0] + else: + short = short + e + + long = [] + for e in self.getopt.l: + if isinstance(e, tuple): + long.append(e[0]) + else: + long.append(e) + + try: + opts, args = getopt.getopt(self.args, short, long) + except getopt.GetoptError as msg: + sys.stderr.write("error - %s\n" % msg) + self.usage() + sys.exit(1) + + for c in opts: + if rcfile: + if c[0] != "--rcfile": + continue + self.parseArg(c) + + if not rcfile: + self.args = args + + def parseArg(self, c): + if c[0] in ('-h', '--help'): + self.help() + sys.exit(0) + elif c[0] == '--list-rcfiles': + print (self.rcfileList) + sys.exit(0) + elif c[0] == '--list-project-info': + print (self.projectInfo()) + sys.exit(0) + elif c[0] == '--rcfile': + self.rcForce.append(c[1]) + else: + return 0 + return 1 + + def usage(self): + + if 'COLUMNS' in os.environ: + cols = os.environ['COLUMNS'] + else: + cols = 80 + + usagelist = [ 'Usage: ', self.usage_command, ' ' ] + + # Build string of argument-free short options. + s = '[-' + for e in self.getopt.s: + if len(e) == 1: + s = s + e + s = s + ']' + if len(s) == 3: + s = '' + usagelist.append(s) + + # Add the argument short options to the above string + for e in self.getopt.s: + if isinstance(e, tuple): + v = e[0] + h = e[1] + else: + v = e + h = 'arg' + if len(v) != 1: + usagelist.append(' [-' + v[:-1] + ' ' + h + ']') + + # Add argument-free long options + for e in self.getopt.l: + if isinstance(e, tuple): + v = e[0] + else: + v = e + if v[len(v)-1] != '=': + usagelist.append(' [--' + v + ']') + + # Add argument long options + for e in self.getopt.l: + if isinstance(e, tuple): + v = e[0] + h = e[1] + else: + v = e + h = 'arg' + if v[len(v)-1] == '=': + usagelist.append(' [--' + v[:-1] + ' ' + h + ']') + + usagelist.append(self.usageTail()) + + # Print the usage, word wrapped to the correct screen size. + print (self.usage_name, '- version', self.usage_version) + l = 0 + s = '' + for e in usagelist: + if l + len(e) <= cols: + s = s + e + l = l + len(e) + else: + print (s) + l = len(e) + s = e + if s: + print (s) + + def help(self): + self.usage() + + def usageTail(self): + return '' + + def getArch(self): + return sunhpc.core.utils.getNativeArch() + +class RCFileHandler(sunhpc.core.utils.ParseXML): + + def __init__(self, application): + sunhpc.core.utils.ParseXML.__init__(self, application) + self.foundSection = 0 + self.section = self.app.usage_command + + def setSection(self, section): + self.section = section + + def startElement(self, name, attrs): + # + # need to convert all the attributes to ascii strings. + # starting in python 2, the xml parser puts the attributes in + # unicode which causes problems with sunhpc apps classes, specifically + # those that append path names found in the attributes to the sys.path + # + newattrs = {} + for (aname, avalue) in attrs.items(): + newattrs[aname] = str(attrs[aname]) + + if self.foundSection: + sunhpc.core.utils.ParseXML.startElement(self, name, newattrs) + elif name == self.section: + self.startElementSection(name, newattrs) + + def endElement(self, name): + if self.foundSection and name == self.foundSection: + self.endElementSection(name) + if self.foundSection: + sunhpc.core.utils.ParseXML.endElement(self, name) + + def getOptions(self): + return self.options + + + #
+ + def startElementSection(self, name, attrs): + parent = attrs.get('parent') + if parent: + self.app.parseRC(parent, parent) + self.foundSection = 1 + + def endElementSection(self, name, attrs): + self.foundSection = 0 + + # + + def startElement_usage(self, name, attrs): + usageName = attrs.get('name') + usageVersion = attrs.get('version') + + if usageName: + self.app.usage_name = usageName + if usageVersion: + self.app.usage_version = usageVersion + + #