Add & implement askNecessaryQuestions
This commit is contained in:
128
install.sh
128
install.sh
@@ -19,7 +19,7 @@ function getFilteredModules() {
|
|||||||
if [ "${#module}" -eq 0 ]; then
|
if [ "${#module}" -eq 0 ]; then
|
||||||
echo "${allModules[@]}"
|
echo "${allModules[@]}"
|
||||||
else
|
else
|
||||||
local modulesToKeep=()
|
local mod modulesToKeep=()
|
||||||
for mod in "${allModules[@]}"; do
|
for mod in "${allModules[@]}"; do
|
||||||
local foundAtIndex="${module[(Ie)${mod}]}"
|
local foundAtIndex="${module[(Ie)${mod}]}"
|
||||||
if [ "${inverse}" != 'true' -a "${foundAtIndex}" -gt 0 ]; then
|
if [ "${inverse}" != 'true' -a "${foundAtIndex}" -gt 0 ]; then
|
||||||
@@ -32,6 +32,130 @@ function getFilteredModules() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function runModule() {
|
||||||
|
local mod="$1"
|
||||||
|
shift
|
||||||
|
${_DIR:-.}/${mod} "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseQuestionLine() {
|
||||||
|
local questionType parameterName question value arguments args
|
||||||
|
local -A typeMap=([i]=info [p]=password [c]=confirm [s]=select)
|
||||||
|
[ -z "${line}" ] && return
|
||||||
|
[ "${line[2]}" != ':' ] && return 10
|
||||||
|
|
||||||
|
questionType="${typeMap[${line[1]}]}"
|
||||||
|
[ -z "${questionType}" ] && return 11
|
||||||
|
|
||||||
|
# remove question type
|
||||||
|
[ "${line[3]}" = ' ' ] && line="${line:3}" || line="${line:2}"
|
||||||
|
|
||||||
|
line=("${(s.=.)line[@]}")
|
||||||
|
parameterName="${line[1]}"
|
||||||
|
[ -z "${parameterName}" ] && return 12
|
||||||
|
[ "${parameterName[1]}" = '-' ] && return 13
|
||||||
|
|
||||||
|
# remove parameter name
|
||||||
|
line="${(j.=.)${(@)line:1}}"
|
||||||
|
|
||||||
|
line=("${(s. #.)line}")
|
||||||
|
question="${line[1]}"
|
||||||
|
[ -z "${question}" ] && return 14
|
||||||
|
|
||||||
|
# remove question part
|
||||||
|
line="${(j. #.)${(@)line:1}}"
|
||||||
|
|
||||||
|
if [ -n "${line}" ]; then
|
||||||
|
arguments=("${(s.;.)line}")
|
||||||
|
for arg in "${arguments[@]}"; do
|
||||||
|
arg=("${(s.:.)arg}")
|
||||||
|
[ -z "${arg[1]}" ] && return 15
|
||||||
|
arg[1]="`trim "${arg[1]}"`"
|
||||||
|
arg[2]="`trim "${arg[2]}"`"
|
||||||
|
questionType+=";${(j.:.)arg}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
printf -v value '%s\n%s' "${question}" "${questionType}"
|
||||||
|
questions+=("${parameterName}" "${value}")
|
||||||
|
}
|
||||||
|
|
||||||
|
function populateQuestionsWithModuleRequiredInformation() {
|
||||||
|
for line in "${(f)$(runModule "${mod}" --show-required-information)}"; do
|
||||||
|
parseQuestionLine
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertQuestionArgsToAskUserArgs() {
|
||||||
|
local arg argName argValue
|
||||||
|
local instructions=("${(s.;.)questionArgs}")
|
||||||
|
local questionType="${instructions[1]}"
|
||||||
|
shift instructions
|
||||||
|
|
||||||
|
if [ "${questionType}" = 'info' ]; then
|
||||||
|
args=(info)
|
||||||
|
elif [ "${questionType}" = 'password' ]; then
|
||||||
|
args=('-p' info)
|
||||||
|
elif [ "${questionType}" = 'confirm' ]; then
|
||||||
|
args=(confirm)
|
||||||
|
elif [ "${questionType}" = 'select' ]; then
|
||||||
|
for arg in "${instructions[@]}"; do
|
||||||
|
arg=("${(s.:.)arg}")
|
||||||
|
[ "${#arg}" -lt 2 ] && continue
|
||||||
|
argName="${arg[1]}"
|
||||||
|
argValue="${arg[2]}"
|
||||||
|
[ "${argName}" != 'choose from' ] && continue
|
||||||
|
choices=("${(s.,.)argValue}")
|
||||||
|
done
|
||||||
|
[ "${#choices}" -ge 1 ] || return 10
|
||||||
|
args=(choose)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function askUserQuestion() {
|
||||||
|
local choices
|
||||||
|
local questionAndArgs=("${(f)questions[$questionID]}") args=()
|
||||||
|
local question="${questionAndArgs[1]}" questionArgs="${questionAndArgs[2]}"
|
||||||
|
convertQuestionArgsToAskUserArgs
|
||||||
|
askUser "${args[@]}" "${question}"
|
||||||
|
value="${REPLY}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateConfigKeysFromQuestionID() {
|
||||||
|
setopt localoptions extendedglob
|
||||||
|
[ $# -lt 2 -o -z "$1" -o -z "$2" ] && return
|
||||||
|
local modName="${1}" questID="${2}"
|
||||||
|
modName="${${${${modName//-##/_}/#_/}/%_/}//[^A-Za-z_]/}"
|
||||||
|
questID="${${${${questID//-##/_}/#_/}/%_/}//[^A-Za-z_]/}"
|
||||||
|
configkeys=("${modName}" questions "${questID}")
|
||||||
|
}
|
||||||
|
|
||||||
|
function answerQuestionsFromConfigOrAskUser() {
|
||||||
|
local questionID
|
||||||
|
config setappname "de.astzweig.macos.system-setup"
|
||||||
|
for questionID in "${(k)questions[@]}"; do
|
||||||
|
local value configkeys=()
|
||||||
|
generateConfigKeysFromQuestionID "${mod}" "${questionID}"
|
||||||
|
value="`config read "${configkeys[@]}"`"
|
||||||
|
if [ -z "${value}" ]; then
|
||||||
|
askUserQuestion
|
||||||
|
config write "${value}" "${configkeys[@]}"
|
||||||
|
fi
|
||||||
|
answers+=("${mod}_${questionID}" "${value}")
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function askNecessaryQuestions() {
|
||||||
|
local mod
|
||||||
|
local -A answers
|
||||||
|
for mod in "${modulesToInstall[@]}"; do
|
||||||
|
local -A questions=()
|
||||||
|
populateQuestionsWithModuleRequiredInformation
|
||||||
|
answerQuestionsFromConfigOrAskUser
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
eval "`docopts -f -V - -h - : "$@" <<- USAGE
|
eval "`docopts -f -V - -h - : "$@" <<- USAGE
|
||||||
Usage: $0 [options] [<module>...]
|
Usage: $0 [options] [<module>...]
|
||||||
@@ -50,9 +174,11 @@ function main() {
|
|||||||
local modulesToInstall=(`getFilteredModules`)
|
local modulesToInstall=(`getFilteredModules`)
|
||||||
ensureDocopts
|
ensureDocopts
|
||||||
autoloadZShLib
|
autoloadZShLib
|
||||||
|
askNecessaryQuestions
|
||||||
hio debug "Current working dir is: `pwd`"
|
hio debug "Current working dir is: `pwd`"
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ "${ZSH_EVAL_CONTEXT}" == toplevel ]]; then
|
if [[ "${ZSH_EVAL_CONTEXT}" == toplevel ]]; then
|
||||||
|
_DIR="${0:A:h}"
|
||||||
main
|
main
|
||||||
fi
|
fi
|
||||||
|
|||||||
63
spec/answerQuestionsFromConfigOrAskUser_spec.sh
Normal file
63
spec/answerQuestionsFromConfigOrAskUser_spec.sh
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
Describe 'answerQuestionsFromConfigOrAskUser'
|
||||||
|
Include ./install.sh
|
||||||
|
mod="testmod"
|
||||||
|
|
||||||
|
It 'does nothing if module has no questions'
|
||||||
|
declare -A questions=()
|
||||||
|
When call answerQuestionsFromConfigOrAskUser
|
||||||
|
The output should eq ''
|
||||||
|
The variable 'questions' should eq ''
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'asks the user if the question is not in the config'
|
||||||
|
declare -A questions=([question-one]=$'What is your favorite color?\ninfo')
|
||||||
|
Data 'blue'
|
||||||
|
config() {}
|
||||||
|
When call answerQuestionsFromConfigOrAskUser
|
||||||
|
The output should eq "What is your favorite color? "
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'does not ask the user if the question is stored in the config'
|
||||||
|
declare -A questions=([question-one]=$'What is your favorite color?\ninfo')
|
||||||
|
config() { [ "${1}" = read ] && echo red; }
|
||||||
|
When call answerQuestionsFromConfigOrAskUser
|
||||||
|
The output should eq ''
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'stores the answer in the answers array if asking user'
|
||||||
|
declare -A answers
|
||||||
|
declare -A questions=([question-one]=$'What is your favorite color?\ninfo')
|
||||||
|
config() {}
|
||||||
|
Data 'blue'
|
||||||
|
When call answerQuestionsFromConfigOrAskUser
|
||||||
|
The output should eq "What is your favorite color? "
|
||||||
|
The variable "answers[${mod}_question-one]" should eq 'blue'
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'stores the answer in the answers array if retrieving from config'
|
||||||
|
declare -A answers
|
||||||
|
declare -A questions=([question-one]=$'What is your favorite color?\ninfo')
|
||||||
|
config() { [ "${1}" = read ] && echo red; }
|
||||||
|
When call answerQuestionsFromConfigOrAskUser
|
||||||
|
The output should eq ''
|
||||||
|
The variable "answers[${mod}_question-one]" should eq 'red'
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'stores the user answer to config'
|
||||||
|
declare -A answers
|
||||||
|
declare -A questions=([question-one]=$'What is your favorite color?\ninfo')
|
||||||
|
writtenValue=""
|
||||||
|
Data 'red'
|
||||||
|
config() { [ "${1}" = read ] && return; [ "${1}" = write ] && writtenValue="${2}" }
|
||||||
|
When call answerQuestionsFromConfigOrAskUser
|
||||||
|
The output should eq "What is your favorite color? "
|
||||||
|
The variable "answers[${mod}_question-one]" should eq 'red'
|
||||||
|
Assert test "${writtenValue}" = 'red'
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
End
|
||||||
52
spec/convertQuestionArgsToAskUserArgs_spec.sh
Normal file
52
spec/convertQuestionArgsToAskUserArgs_spec.sh
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
Describe 'convertQuestionArgsToAskUserArgs'
|
||||||
|
Include ./install.sh
|
||||||
|
|
||||||
|
It 'converts info to info'
|
||||||
|
args=()
|
||||||
|
choices=()
|
||||||
|
questionArgs='info'
|
||||||
|
When call convertQuestionArgsToAskUserArgs
|
||||||
|
The output should eq ''
|
||||||
|
The variable args should eq 'info'
|
||||||
|
The variable choices should eq ''
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'converts password to -p info'
|
||||||
|
args=() choices=() questionArgs='password'
|
||||||
|
When call convertQuestionArgsToAskUserArgs
|
||||||
|
The variable args should eq '-p info'
|
||||||
|
The variable choices should eq ''
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'converts confirm to confirm'
|
||||||
|
args=() choices=() questionArgs='confirm'
|
||||||
|
When call convertQuestionArgsToAskUserArgs
|
||||||
|
The variable args should eq 'confirm'
|
||||||
|
The variable choices should eq ''
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'returns if type is select but no choose from arg is provided'
|
||||||
|
args=() choices=() questionArgs='select'
|
||||||
|
When call convertQuestionArgsToAskUserArgs
|
||||||
|
The variable args should eq ''
|
||||||
|
The variable choices should eq ''
|
||||||
|
The status should eq 10
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'converts select to choose'
|
||||||
|
args=() choices=() questionArgs='select;choose from:blue,light green,red'
|
||||||
|
When call convertQuestionArgsToAskUserArgs
|
||||||
|
The variable args should eq 'choose'
|
||||||
|
The variable choices should eq 'blue light green red'
|
||||||
|
The variable '#choices' should eq 3
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'finds choose from arg even if many args are provided'
|
||||||
|
args=() choices=() questionArgs='select;first arg:red;choose from:blue,light green,red;after arg:nine;after arg:nine;'
|
||||||
|
When call convertQuestionArgsToAskUserArgs
|
||||||
|
The variable args should eq 'choose'
|
||||||
|
The variable choices should eq 'blue light green red'
|
||||||
|
The variable '#choices' should eq 3
|
||||||
|
End
|
||||||
|
End
|
||||||
59
spec/generateConfigKeysFromQuestionID_spec.sh
Normal file
59
spec/generateConfigKeysFromQuestionID_spec.sh
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
Describe 'generateConfigKeysFromQuestionID'
|
||||||
|
Include ./install.sh
|
||||||
|
|
||||||
|
It 'does nothing if given no arguments'
|
||||||
|
declare -A configkeys=()
|
||||||
|
When call generateConfigKeysFromQuestionID ''
|
||||||
|
The output should eq ''
|
||||||
|
The variable 'configkeys' should eq ''
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'does nothing if question id is empty'
|
||||||
|
declare configkeys=()
|
||||||
|
When call generateConfigKeysFromQuestionID 'somemod' ''
|
||||||
|
The output should eq ''
|
||||||
|
The variable 'configkeys' should eq ''
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'generates key when given module name and question id'
|
||||||
|
declare configkeys=()
|
||||||
|
When call generateConfigKeysFromQuestionID 'somemod' 'somekey'
|
||||||
|
The output should eq ''
|
||||||
|
The variable 'configkeys' should eq 'somemod questions somekey'
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'replaces minus with underscore'
|
||||||
|
declare configkeys=()
|
||||||
|
When call generateConfigKeysFromQuestionID 'some-mod' 'somekey'
|
||||||
|
The output should eq ''
|
||||||
|
The variable 'configkeys' should eq 'some_mod questions somekey'
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'replaces multiple minus with single underscore'
|
||||||
|
declare configkeys=()
|
||||||
|
When call generateConfigKeysFromQuestionID 'some---mod' 'so--mekey'
|
||||||
|
The output should eq ''
|
||||||
|
The variable 'configkeys' should eq 'some_mod questions so_mekey'
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'replaces underscores at the begin and end of string'
|
||||||
|
declare configkeys=()
|
||||||
|
When call generateConfigKeysFromQuestionID '--some-mod' '--somekey-'
|
||||||
|
The output should eq ''
|
||||||
|
The variable 'configkeys' should eq 'some_mod questions somekey'
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'removes all chars but [A-Za-z_]'
|
||||||
|
declare configkeys=()
|
||||||
|
When call generateConfigKeysFromQuestionID '*some≠{mod' '?`somekey'
|
||||||
|
The output should eq ''
|
||||||
|
The variable 'configkeys' should eq 'somemod questions somekey'
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
End
|
||||||
88
spec/parseQuestionLine_spec.sh
Normal file
88
spec/parseQuestionLine_spec.sh
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
Describe 'parseQuestionLine'
|
||||||
|
Include ./install.sh
|
||||||
|
|
||||||
|
It 'does nothing if the line is empty'
|
||||||
|
line=''
|
||||||
|
When call parseQuestionLine
|
||||||
|
The output should eq ''
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'does nothing if the line does not have a question type'
|
||||||
|
line='some value here'
|
||||||
|
When call parseQuestionLine
|
||||||
|
The output should eq ''
|
||||||
|
The status should eq 10
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'does nothing if the line does not have a valid question type'
|
||||||
|
line='z: some value here'
|
||||||
|
When call parseQuestionLine
|
||||||
|
The output should eq ''
|
||||||
|
The status should eq 11
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'does nothing if the line does not have a parameter name'
|
||||||
|
line='i: '
|
||||||
|
When call parseQuestionLine
|
||||||
|
The output should eq ''
|
||||||
|
The status should eq 12
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'does nothing if the parameter name starts with a dash'
|
||||||
|
line='i: -parameter-name=Is this my question?'
|
||||||
|
When call parseQuestionLine
|
||||||
|
The output should eq ''
|
||||||
|
The status should eq 13
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'does nothing if the line does not have a question'
|
||||||
|
line='i: parameter-name='
|
||||||
|
When call parseQuestionLine
|
||||||
|
The output should eq ''
|
||||||
|
The status should eq 14
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'extends outer questions associative array with question'
|
||||||
|
declare -A questions
|
||||||
|
line='i: parameter-name=What parameter do you like? #'
|
||||||
|
When call parseQuestionLine
|
||||||
|
The output should eq ''
|
||||||
|
The line 1 of variable 'questions[parameter-name]' should eq 'What parameter do you like?'
|
||||||
|
The line 2 of variable 'questions[parameter-name]' should eq info
|
||||||
|
The status should be success
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'does nothing if an argument does not contain a name'
|
||||||
|
declare -A questions
|
||||||
|
line='i: parameter-name=What parameter do you like? # some arg = some value;;'
|
||||||
|
When call parseQuestionLine
|
||||||
|
The output should eq ''
|
||||||
|
The variable 'questions' should eq ''
|
||||||
|
The status should eq 15
|
||||||
|
End
|
||||||
|
|
||||||
|
It 'writes question type to outer questions associative array'
|
||||||
|
declare -A questions
|
||||||
|
line='s: parameter-name=What parameter do you like? # choose from: blue,red,light green; default: blue'
|
||||||
|
When call parseQuestionLine
|
||||||
|
The line 2 of variable 'questions[parameter-name]' should eq 'select;choose from:blue,red,light green;default:blue'
|
||||||
|
End
|
||||||
|
End
|
||||||
|
|
||||||
|
Describe "parseQuestionLine type renaming"
|
||||||
|
Include ./install.sh
|
||||||
|
Parameters
|
||||||
|
i info
|
||||||
|
p password
|
||||||
|
c confirm
|
||||||
|
s select
|
||||||
|
End
|
||||||
|
|
||||||
|
It "converts $1 to $2"
|
||||||
|
declare -A questions
|
||||||
|
line="${1}: parameter-name=What parameter do you like? #"
|
||||||
|
When call parseQuestionLine
|
||||||
|
The line 2 of variable 'questions[parameter-name]' should eq "$2"
|
||||||
|
End
|
||||||
|
End
|
||||||
Reference in New Issue
Block a user