#!/usr/bin/env bash # Copyright 2019 Mycroft AI Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. SOURCE="${BASH_SOURCE[0]}" cd -P "$( dirname "$SOURCE" )" DIR="$( pwd )" script=${0} script=${script##*/} function help() { echo "${script}: Mycroft configuration manager" echo "usage: ${script} [COMMAND] [params]" echo echo "COMMANDs:" echo " edit (system|user) edit and validate config file" echo " reload instruct services to reload config" echo " show (default|remote|system|user) display the specified setting file" echo " set set the variable (under USER)" echo " get [var] display a particular variable" echo " or all if no 'var' specified" echo "Note: Use jq format for specifying " echo echo "Examples:" echo " ${script} edit user" echo " sudo ${script} edit system" echo " ${script} show remote" echo " ${script} get" echo " ${script} get enclosure.platform" echo " ${script} set test.subvalue \"foo\" " exit 1 } ################################################################ # Setup stuff based on the environment VIEWER="nano --syntax=json --view" if [ -z "$EDITOR" ] ; then if [ $( which sensible-editor ) ] ; then EDITOR="sensible-editor" else EDITOR="nano --syntax=json --tempfile" fi fi if [ -z "$TEMP" ] ; then TEMP="/tmp" fi function found_exe() { hash "$1" 2>/dev/null } if found_exe tput ; then GREEN="$(tput setaf 2)" BLUE="$(tput setaf 4)" CYAN="$(tput setaf 6)" YELLOW="$(tput setaf 3)" RESET="$(tput sgr0)" HIGHLIGHT=${YELLOW} fi ################################################################ # Utilities function validate_config_file() { if [ ! -f "$1" ] ; then # A missing config file is valid return 0 fi echo -n ${BLUE} # Remove any comments (lines starting with # or //) found in the file and # Use jq to validate and output errors sed 's/^\s*[#\/].*$//g' "$1" | sed '/^$/d' | jq -e "." > /dev/null result=$? echo -n ${RESET} #xxx echo "RESULT=$result for $1" return $result } _conf_file="~/.mycroft/mycroft.conf" function name_to_path() { case ${1} in "system") _conf_file="/etc/mycroft/mycroft.conf" ;; "user") _conf_file=$(readlink -f ~/.mycroft/mycroft.conf) ;; "default") _conf_file="$DIR/../mycroft/configuration/mycroft.conf" ;; "remote") _conf_file="/var/tmp/mycroft_web_cache.json" ;; *) echo "ERROR: Unknown name '${1}'." echo " Must be one of: default, remote, system, or user" exit 1 esac } ################################################################ function edit_config() { name_to_path $1 validate_config_file $_conf_file rc=$? if [ $rc -ne 0 ] ; then echo "${YELLOW}WARNING: ${RESET}Configuration file did not pass validation before edits." read -p "Review errors above and press ENTER to continue with editing." fi if [ -f "${_conf_file}" ] ; then cp "${_conf_file}" "${TEMP}/mycroft.json" else echo "{" > "${TEMP}/mycroft.json" echo "}" >> "${TEMP}/mycroft.json" fi while [ 1 ] ; do case $1 in system | user) # Allow user to edit $EDITOR $TEMP/mycroft.json ;; default | remote) # View-only echo "The default config shouldn't be changed, opening in View mode" sleep 2 $VIEWER $TEMP/mycroft.json ;; esac cmp --quiet "${_conf_file}" "${TEMP}/mycroft.json" rc=$? if [ $rc -eq 0 ] ; then echo "Configuration unchanged." break fi # file was changed, validate changes validate_config_file $TEMP/mycroft.json if [ $? -ne 0 ] ; then echo "${YELLOW}WARNING: ${RESET}Configuration file does not pass validation, see errors above." echo "Press X to abandon changes, S to force save, any other key to edit again." read -N1 -s key else key="S" fi case $key in [Ss]) echo "Saving..." mv $TEMP/mycroft.json $_conf_file signal_reload_config break ;; [Xx]) # abandoning break ;; esac done } function signal_reload_config() { # Enter the Mycroft venv source "$DIR/../venv-activate.sh" -q # Post a messagebus notification to reload the config file output=$(python -m mycroft.messagebus.send "configuration.updated" "{}") } function show_config() { name_to_path $1 # Use jq to display formatted nicely (after stripping out comments) sed 's/^\s*[#\/].*$//g' "${_conf_file}" | sed '/^$/d' | jq "." } function get_config() { value=$1 if [[ ! $value =~ ^\..* ]] ; then # Add the leading period if not included value=".${value}" fi # Load all the configuration(s) json_config=$( source "$DIR/../venv-activate.sh" -q && python -c "import json; from mycroft.configuration import Configuration; print(json.dumps(Configuration.get()))" ) # Read the given variable from the mix echo ${json_config} | jq -r "${value}" } function set_config() { # Set all overrides under the user configuration value=$1 if [[ ! $value =~ ^\..* ]] ; then # Add the leading period if not included value=".${value}" fi jq "${value} = \"$2\"" ~/.mycroft/mycroft.conf > "${TEMP}/~mycroft.conf" if [ $? -eq 0 ] ; then # Successful update, replace the config file mv "${TEMP}/~mycroft.conf" ~/.mycroft/mycroft.conf signal_reload_config fi } _opt=$1 case ${_opt} in "edit") edit_config $2 ;; "reload") signal_reload_config ;; "show") show_config $2 ;; "get") get_config $2 ;; "set") set_config "$2" "$3" ;; *) help ;; esac