The kiwi build process mostly does the right thing in terms of executing with the correct Python interpreter throughout the build process, with the exception of the Makefile not correctly locating the versioned Python interpreter executable path, and the bash completion generator being executed using '/usr/bin/python' without regard for what the target environment was. This is a problem when a build environment complying with PEP 394 as it stands today does not have Python 2 installed, such as when kiwi is being built as a Python 3-only package in Fedora. Thus, the Makefile has been adjusted to not only correctly locate the versioned Python interpreter, but to also execute 'completion_helper' with the correct interpreter. Additionally, a trivial change to the shebang to 'completion_helper' was made to be consistent with other Python-based build helper scripts. This is part of the overall effort to eliminate the dependencies on Python 2 in Fedora. Reference: https://fedoraproject.org/wiki/FinalizingFedoraSwitchtoPython3
253 lines
9.0 KiB
Python
Executable File
253 lines
9.0 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
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
|
|
complete -F _kiwi -o default kiwi-ng-2
|
|
complete -F _kiwi -o default kiwi-ng-3
|
|
''').strip())
|