251 lines
8.9 KiB
Python
Executable File
251 lines
8.9 KiB
Python
Executable File
#!/usr/bin/python3
|
|
|
|
from textwrap import dedent
|
|
|
|
import subprocess
|
|
import re
|
|
import sys
|
|
|
|
import collections
|
|
import pprint
|
|
|
|
|
|
class AutoVivification(dict):
|
|
def __getitem__(self, item):
|
|
try:
|
|
return dict.__getitem__(self, item)
|
|
except KeyError:
|
|
value = self[item] = type(self)()
|
|
return value
|
|
|
|
|
|
class AppHash:
|
|
def __init__(self):
|
|
tasks = [
|
|
'kiwi/cli.py',
|
|
'kiwi/tasks/*.py'
|
|
]
|
|
call_parm = ['bash', '-c', 'cat %s' % ' '.join(tasks)]
|
|
cmd = subprocess.Popen(
|
|
call_parm, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
|
|
)
|
|
begin = False
|
|
cur_path = ''
|
|
self.result = AutoVivification()
|
|
for line in cmd.communicate()[0].decode().split('\n'):
|
|
usage = re.search('^usage: (.*)', line)
|
|
if usage:
|
|
begin = True
|
|
if re.match('.*--help', line):
|
|
mod_line = re.sub('[\[\]\|]', '', usage.group(1))
|
|
mod_line = re.sub('-h ', '', mod_line)
|
|
key_list = mod_line.split()
|
|
result_keys = self.validate(key_list)
|
|
cur_path = self.merge(result_keys, self.result)
|
|
else:
|
|
key_list = usage.group(1).split()
|
|
result_keys = self.validate(key_list)
|
|
cur_path = self.merge(result_keys, self.result)
|
|
elif begin:
|
|
if not line:
|
|
begin = False
|
|
else:
|
|
if re.match('.*--version', line):
|
|
mod_line = re.sub('[\[\]\|]', '', line)
|
|
mod_line = re.sub('-v ', '', mod_line)
|
|
key_list = mod_line.split()
|
|
result_keys = self.validate(key_list)
|
|
cur_path = self.merge(result_keys, self.result)
|
|
elif re.match('.*kiwi --compat', line):
|
|
mod_line = re.sub('[\[\]\|]', '', line)
|
|
mod_line = re.sub('<legacy_args>...', '', mod_line)
|
|
key_list = mod_line.split()
|
|
result_keys = self.validate(key_list)
|
|
cur_path = self.merge(result_keys, self.result)
|
|
elif re.match('.*kiwi \[', line):
|
|
line = line.replace('[', '')
|
|
line = line.replace(']', '')
|
|
line = line.replace('|', '')
|
|
key_list = line.split()
|
|
key_list.pop(0)
|
|
for global_opt in key_list:
|
|
result_keys = self.validate(
|
|
['kiwi', global_opt]
|
|
)
|
|
cur_path = self.merge(result_keys, self.result)
|
|
elif re.match(' \[', line):
|
|
line = line.replace('[', '')
|
|
line = line.replace(']', '')
|
|
line = line.replace('|', '')
|
|
key_list = line.split()
|
|
for global_opt in key_list:
|
|
result_keys = self.validate(
|
|
['kiwi', global_opt]
|
|
)
|
|
cur_path = self.merge(result_keys, self.result)
|
|
elif re.match(' \[', line):
|
|
opt_val = re.search(' \[(--.*)', line)
|
|
global_opt = opt_val.group(1)
|
|
global_opt = global_opt.replace('[', '')
|
|
global_opt = global_opt.replace(']', '')
|
|
global_opt = global_opt.replace('|', '')
|
|
result_keys = self.validate(
|
|
['kiwi', global_opt]
|
|
)
|
|
cur_path = self.merge(result_keys, self.result)
|
|
elif re.match('.*kiwi', line):
|
|
mandatory_options = re.search(
|
|
'(.*kiwi.*?) (--.*)', line
|
|
)
|
|
if mandatory_options:
|
|
line = mandatory_options.group(1)
|
|
key_list = line.split()
|
|
result_keys = self.validate(key_list)
|
|
cur_path = self.merge(result_keys, self.result)
|
|
if mandatory_options:
|
|
for option in mandatory_options.group(2).split():
|
|
mod_line = cur_path + ' ' + option
|
|
key_list = mod_line.split()
|
|
result_keys = self.validate(key_list)
|
|
self.merge(result_keys, self.result)
|
|
else:
|
|
if 'kiwi --' in cur_path:
|
|
cur_path = ''
|
|
for mod_line in line.strip().split('|'):
|
|
mod_line = cur_path + ' ' + mod_line
|
|
mod_line = re.sub('[\[\]]', '', mod_line)
|
|
mod_line = re.sub('-h ', '', mod_line)
|
|
key_list = mod_line.split()
|
|
result_keys = self.validate(key_list)
|
|
self.merge(result_keys, self.result)
|
|
|
|
def merge(self, key_list, result):
|
|
raw_key_path = " ".join(key_list)
|
|
key_path = ''
|
|
for key in key_list:
|
|
key_path += '[\'' + key + '\']'
|
|
expression = 'self.result' + key_path
|
|
exec(expression)
|
|
return raw_key_path
|
|
|
|
def validate(self, key_list):
|
|
result_keys = []
|
|
for key in key_list:
|
|
option = re.search('^\[(--.*)=|^\[(.*)\]', key)
|
|
mandatory = re.search('^(--.*)=', key)
|
|
if option:
|
|
if option.group(1):
|
|
result_keys.append(option.group(1))
|
|
elif mandatory:
|
|
if mandatory.group(1):
|
|
result_keys.append(mandatory.group(1))
|
|
elif re.search('<servicename>|<command>|<args>...', key):
|
|
pass
|
|
else:
|
|
key = key.replace('<','__')
|
|
key = key.replace('>','__')
|
|
result_keys.append(key)
|
|
return result_keys
|
|
|
|
|
|
class AppTree:
|
|
def __init__(self):
|
|
self.completion = AppHash()
|
|
self.level_dict = {}
|
|
|
|
def traverse(self, tree=None, level=0, origin=None):
|
|
if not tree:
|
|
tree = self.completion.result['kiwi']
|
|
if not origin:
|
|
origin = 'kiwi'
|
|
for key in tree:
|
|
try:
|
|
if self.level_dict[str(level)]:
|
|
pass
|
|
except KeyError:
|
|
self.level_dict[str(level)] = {}
|
|
try:
|
|
if self.level_dict[str(level)][origin]:
|
|
pass
|
|
except KeyError:
|
|
self.level_dict[str(level)][origin] = []
|
|
|
|
if not key in self.level_dict[str(level)][origin]:
|
|
self.level_dict[str(level)][origin].append(key)
|
|
|
|
if tree[key]:
|
|
self.traverse(tree[key], level + 1, key)
|
|
|
|
|
|
|
|
tree = AppTree()
|
|
tree.traverse()
|
|
|
|
# helpful for debugging
|
|
# pp = pprint.PrettyPrinter(indent=4)
|
|
# pp.pprint(tree.completion.result)
|
|
|
|
sorted_levels = collections.OrderedDict(
|
|
sorted(tree.level_dict.items())
|
|
)
|
|
|
|
print(dedent('''
|
|
#========================================
|
|
# _kiwi
|
|
#----------------------------------------
|
|
function setupCompletionLine {
|
|
local comp_line=$(echo $COMP_LINE | sed -e 's@kiwi-ng@kiwi@')
|
|
local result_comp_line
|
|
local prev_was_option=0
|
|
for item in $comp_line; do
|
|
if [ $prev_was_option = 1 ];then
|
|
prev_was_option=0
|
|
continue
|
|
fi
|
|
if [[ $item =~ -.* ]];then
|
|
prev_was_option=1
|
|
continue
|
|
fi
|
|
result_comp_line="$result_comp_line $item"
|
|
done
|
|
echo $result_comp_line
|
|
}
|
|
|
|
function _kiwi {
|
|
local cur prev opts
|
|
_get_comp_words_by_ref cur prev
|
|
local cmd=$(setupCompletionLine | awk -F ' ' '{ print $NF }')
|
|
''').strip())
|
|
|
|
print(' for comp in $prev $cmd;do')
|
|
print(' case "$comp" in')
|
|
for level in sorted_levels:
|
|
if level == '0':
|
|
continue
|
|
for sub in sorted(sorted_levels[level]):
|
|
print(' "%s")' % (sub))
|
|
print(' __comp_reply "%s"' % \
|
|
(" ".join(sorted(sorted_levels[level][sub])))
|
|
)
|
|
print(' return 0')
|
|
print(' ;;')
|
|
print(' esac')
|
|
print(' done')
|
|
print(' __comp_reply "%s"' % \
|
|
(" ".join(sorted(sorted_levels['0']['kiwi'])))
|
|
)
|
|
print(' return 0')
|
|
print('}')
|
|
print(dedent('''
|
|
#========================================
|
|
# comp_reply
|
|
#----------------------------------------
|
|
function __comp_reply {
|
|
word_list=$@
|
|
COMPREPLY=($(compgen -W "$word_list" -- ${cur}))
|
|
}
|
|
|
|
complete -F _kiwi -o default kiwi
|
|
complete -F _kiwi -o default kiwi-ng
|
|
''').strip())
|