From 032566548aedee6709cd2b1ad6f2cafa00b070a9 Mon Sep 17 00:00:00 2001 From: Peter Steenbergen Date: Mon, 4 Feb 2019 12:55:48 +0100 Subject: [PATCH] MycroftOS: Mycroft A.I. service package - Systemd support for Mycroft A.I. - Remove old init.d system files - Update start/stop-mycroft.sh files --- buildroot-external/Config.in | 5 +- .../configs/mycroftos_rpi3_defconfig | 3 +- .../package/mycroft-service/Config.in | 6 + .../mycroft-service/mycroft-service.mk | 27 +++++ .../package/mycroft-service/mycroft.service | 15 +++ .../mycroft-service}/start-mycroft.sh | 109 +++++++++++++++--- .../mycroft-service}/stop-mycroft.sh | 25 ++-- .../package/python-mycroft/python-mycroft.mk | 2 +- .../etc/init.d/S90mycroft_prepare | 41 ------- .../etc/init.d/S91mycroft_services | 37 ------ 10 files changed, 157 insertions(+), 113 deletions(-) create mode 100644 buildroot-external/package/mycroft-service/Config.in create mode 100644 buildroot-external/package/mycroft-service/mycroft-service.mk create mode 100644 buildroot-external/package/mycroft-service/mycroft.service rename buildroot-external/{rootfs-overlay/usr/bin => package/mycroft-service}/start-mycroft.sh (65%) rename buildroot-external/{rootfs-overlay/usr/bin => package/mycroft-service}/stop-mycroft.sh (83%) delete mode 100755 buildroot-external/rootfs-overlay/etc/init.d/S90mycroft_prepare delete mode 100755 buildroot-external/rootfs-overlay/etc/init.d/S91mycroft_services diff --git a/buildroot-external/Config.in b/buildroot-external/Config.in index 5623193e..cc35e69a 100644 --- a/buildroot-external/Config.in +++ b/buildroot-external/Config.in @@ -1,3 +1,6 @@ +menu "Mycroft A.I. Personal Assistant" + source "$BR2_EXTERNAL_MYCROFTOS_PATH/package/python-mycroft/Config.in" + source "$BR2_EXTERNAL_MYCROFTOS_PATH/package/mycroft-service/Config.in" menu "Additional drivers, libraries and/or applications" source "$BR2_EXTERNAL_MYCROFTOS_PATH/package/fann/Config.in" source "$BR2_EXTERNAL_MYCROFTOS_PATH/package/respeaker/Config.in" @@ -28,7 +31,6 @@ menu "Additional external python modules" source "$BR2_EXTERNAL_MYCROFTOS_PATH/package/python-monotonic/Config.in" source "$BR2_EXTERNAL_MYCROFTOS_PATH/package/python-msk/Config.in" source "$BR2_EXTERNAL_MYCROFTOS_PATH/package/python-msm/Config.in" - source "$BR2_EXTERNAL_MYCROFTOS_PATH/package/python-mycroft/Config.in" source "$BR2_EXTERNAL_MYCROFTOS_PATH/package/python-oauth2client/Config.in" source "$BR2_EXTERNAL_MYCROFTOS_PATH/package/python-olefile/Config.in" source "$BR2_EXTERNAL_MYCROFTOS_PATH/package/python-padaos/Config.in" @@ -54,3 +56,4 @@ menu "Additional external python modules" source "$BR2_EXTERNAL_MYCROFTOS_PATH/package/python-xmlrunner/Config.in" source "$BR2_EXTERNAL_MYCROFTOS_PATH/package/python-xxhash/Config.in" endmenu +endmenu diff --git a/buildroot-external/configs/mycroftos_rpi3_defconfig b/buildroot-external/configs/mycroftos_rpi3_defconfig index 116465e9..c1b360dd 100644 --- a/buildroot-external/configs/mycroftos_rpi3_defconfig +++ b/buildroot-external/configs/mycroftos_rpi3_defconfig @@ -184,6 +184,8 @@ BR2_PACKAGE_HOST_PYTHON_CYTHON=y BR2_PACKAGE_HOST_PYTHON_LXML=y BR2_PACKAGE_HOST_PYTHON_SIX=y BR2_PACKAGE_HOST_PYTHON_XLRD=y +BR2_PACKAGE_PYTHON_MYCROFT=y +BR2_PACKAGE_MYCROFT_SERVICE=y BR2_PACKAGE_FANN=y BR2_PACKAGE_RESPEAKER=y BR2_PACKAGE_PYTHON_ADAPT_PARSER=y @@ -198,7 +200,6 @@ BR2_PACKAGE_PYTHON_GTTS=y BR2_PACKAGE_PYTHON_HUMANHASH3=y BR2_PACKAGE_PYTHON_INFLECTION=y BR2_PACKAGE_PYTHON_MSK=y -BR2_PACKAGE_PYTHON_MYCROFT=y BR2_PACKAGE_PYTHON_OAUTH2CLIENT=y BR2_PACKAGE_PYTHON_OLEFILE=y BR2_PACKAGE_PYTHON_PADATIOUS=y diff --git a/buildroot-external/package/mycroft-service/Config.in b/buildroot-external/package/mycroft-service/Config.in new file mode 100644 index 00000000..f5a8e8c9 --- /dev/null +++ b/buildroot-external/package/mycroft-service/Config.in @@ -0,0 +1,6 @@ +config BR2_PACKAGE_MYCROFT_SERVICE + bool "mycroft-service" + help + Start the Mycroft A.I. software as service. + + https://mycroft.ai/ diff --git a/buildroot-external/package/mycroft-service/mycroft-service.mk b/buildroot-external/package/mycroft-service/mycroft-service.mk new file mode 100644 index 00000000..ecaf25fa --- /dev/null +++ b/buildroot-external/package/mycroft-service/mycroft-service.mk @@ -0,0 +1,27 @@ +################################################################################ +# +# mycroft-service +# +################################################################################ + +MYCROFT_SERVICE_VERSION = 0.1.0 +MYCROFT_SERVICE_SITE = $(BR2_EXTERNAL_MYCROFTOS_PATH)/package/mycroft-service +MYCROFT_SERVICE_SITE_METHOD = local +MYCROFT_SERVICE_LICENSE = Apache License 2.0 +MYCROFT_SERVICE_LICENSE_FILES = LICENSE + +define MYCROFT_SERVICE_USERS + mycroft -1 mycroft -1 mycroft /home/mycroft /bin/bash audio,pulse,pulse-access +endef + +define MYCROFT_SERVICE_INSTALL_TARGET_CMDS + $(INSTALL) -m 0755 $(@D)/start-mycroft.sh $(TARGET_DIR)/usr/bin/ + $(INSTALL) -m 0755 $(@D)/stop-mycroft.sh $(TARGET_DIR)/usr/bin/ + $(INSTALL) -D -m 644 $(@D)/mycroft.service \ + $(TARGET_DIR)/usr/lib/systemd/system/mycroft.service + mkdir -p $(TARGET_DIR)/etc/systemd/system/multi-user.target.wants + ln -fs ../../../../usr/lib/systemd/system/mycroft.service \ + $(TARGET_DIR)/etc/systemd/system/multi-user.target.wants/mycroft.service +endef + +$(eval $(generic-package)) diff --git a/buildroot-external/package/mycroft-service/mycroft.service b/buildroot-external/package/mycroft-service/mycroft.service new file mode 100644 index 00000000..9f079730 --- /dev/null +++ b/buildroot-external/package/mycroft-service/mycroft.service @@ -0,0 +1,15 @@ +[Unit] +Description=Mycroft AI +After=pulseaudio.service + +[Service] +User=mycroft +WorkingDirectory=/home/mycroft +ExecStart=start-mycroft.sh all +ExecStop=stop-mycroft.sh all +Type=forking +Restart=always +RestartSec=3 + +[Install] +WantedBy=multi-user.target diff --git a/buildroot-external/rootfs-overlay/usr/bin/start-mycroft.sh b/buildroot-external/package/mycroft-service/start-mycroft.sh similarity index 65% rename from buildroot-external/rootfs-overlay/usr/bin/start-mycroft.sh rename to buildroot-external/package/mycroft-service/start-mycroft.sh index 61c71a1c..efe3c2ea 100755 --- a/buildroot-external/rootfs-overlay/usr/bin/start-mycroft.sh +++ b/buildroot-external/package/mycroft-service/start-mycroft.sh @@ -23,31 +23,34 @@ DIR="$( pwd )" function help() { echo "${script}: Mycroft command/service launcher" - echo "usage: ${script} [command] [params]" + echo "usage: ${script} [COMMAND] [restart] [params]" echo - echo "Services:" + echo "Services COMMANDs:" echo " all runs core services: bus, audio, skills, voice" echo " debug runs core services, then starts the CLI" - echo - echo "Services:" echo " audio the audio playback service" echo " bus the messagebus service" echo " skills the skill service" echo " voice voice capture service" + # echo " wifi wifi setup service" echo " enclosure mark_1 enclosure service" echo - echo "Tools:" + echo "Tool COMMANDs:" echo " cli the Command Line Interface" echo " unittest run mycroft-core unit tests (requires pytest)" echo " skillstest run the skill autotests for all skills (requires pytest)" echo - echo "Utils:" + echo "Util COMMANDs:" echo " audiotest attempt simple audio validation" echo " audioaccuracytest more complex audio validation" echo " sdkdoc generate sdk documentation" echo + echo "Options:" + echo " restart (optional) Force the service to restart if running" + echo echo "Examples:" echo " ${script} all" + echo " ${script} all restart" echo " ${script} cli" echo " ${script} unittest" @@ -72,7 +75,32 @@ function name-to-script-path() { esac } +first_time=true + +# set the right locale / language settings +export LC_ALL=en_US.UTF-8 +export LANG=en_US.UTF-8 +export LANGUAGE=en_US.UTF-8 + +function init-once() { + if ($first_time) ; then + echo "Initializing..." + # Check if Mycroft log folders are present and if not + # create those logging folders + if [[ ! -w /var/log/mycroft/ ]] ; then + # Creating needed folders + printf "Creating /var/log/mycroft/ directory" + if [[ ! -d /var/log/mycroft/ ]] ; then + mkdir /var/log/mycroft/ + fi + fi + first_time=false + fi +} + function launch-process() { + init-once + name-to-script-path ${1} # Launch process in foreground @@ -80,12 +108,28 @@ function launch-process() { python3 -m ${_module} $_params } +function require-process() { + # Launch process if not found + name-to-script-path ${1} + if ! pgrep -f "python3 -m ${_module}" > /dev/null ; then + # Start required process + launch-background ${1} + fi +} + function launch-background() { + init-once + # Check if given module is running and start (or restart if running) name-to-script-path ${1} if pgrep -f "python3 -m ${_module}" > /dev/null ; then - echo "Restarting: ${1}" - "${DIR}/stop-mycroft.sh" ${1} + if ($_force_restart) ; then + echo "Restarting: ${1}" + "${DIR}/stop-mycroft.sh" ${1} + else + # Already running, no need to restart + return + fi else echo "Starting background service $1" fi @@ -107,25 +151,27 @@ function launch-all() { launch-background skills launch-background audio launch-background voice - - # Determine platform type - if [[ -r /etc/mycroft/mycroft.conf ]] ; then - mycroft_platform=$( jq -r ".enclosure.platform" < /etc/mycroft/mycroft.conf ) - if [[ $mycroft_platform = "mycroft_mark_1" ]] ; then - # running on a Mark 1, start enclosure service - launch-background enclosure - fi - fi + launch-background enclosure } _opt=$1 +_force_restart=false shift +if [[ "${1}" == "restart" ]] || [[ "${_opt}" == "restart" ]] ; then + _force_restart=true + if [[ "${_opt}" == "restart" ]] ; then + # Support "start-mycroft.sh restart all" as well as "start-mycroft.sh all restart" + _opt=$1 + fi + shift +fi _params=$@ case ${_opt} in "all") launch-all ;; + "bus") launch-background ${_opt} ;; @@ -138,24 +184,51 @@ case ${_opt} in "voice") launch-background ${_opt} ;; + "debug") launch-all launch-process cli ;; + "cli") + require-process bus + require-process skills launch-process ${_opt} ;; + + # TODO: Restore support for Wifi Setup on a Picroft, etc. + # "wifi") + # launch-background ${_opt} + # ;; + "unittest") + source-venv + pytest test/unittests/ --cov=mycroft "$@" + ;; + "singleunittest") + source-venv + pytest "$@" + ;; + "skillstest") + source-venv + pytest test/integrationtests/skills/discover_tests.py "$@" + ;; "audiotest") launch-process ${_opt} ;; "audioaccuracytest") launch-process ${_opt} ;; + "sdkdoc") + source-venv + cd doc + make ${opt} + cd .. + ;; "enclosure") launch-background ${_opt} ;; + *) help ;; esac - diff --git a/buildroot-external/rootfs-overlay/usr/bin/stop-mycroft.sh b/buildroot-external/package/mycroft-service/stop-mycroft.sh similarity index 83% rename from buildroot-external/rootfs-overlay/usr/bin/stop-mycroft.sh rename to buildroot-external/package/mycroft-service/stop-mycroft.sh index a71ccac7..3c5a5862 100755 --- a/buildroot-external/rootfs-overlay/usr/bin/stop-mycroft.sh +++ b/buildroot-external/package/mycroft-service/stop-mycroft.sh @@ -31,7 +31,7 @@ function help() { echo " audio stop the audio playback service" echo " skills stop the skill service" echo " voice stop voice capture service" - echo " enclosure stop mark_1 enclosure service" + echo " enclosure stop enclosure (hardware/gui interface) service" echo echo "Examples:" echo " ${script}" @@ -50,8 +50,9 @@ function process-running() { function end-process() { if process-running $1 ; then - echo -n "Stopping $1..." - pid=$( pgrep -f "python3 -m mycroft.*${1}" ) + # Find the process by name, only returning the oldest if it has children + pid=$( pgrep -o -f "python3 -m mycroft.*${1}" ) + echo -n "Stopping $1 (${pid})..." kill -SIGINT ${pid} # Wait up to 5 seconds (50 * 0.1) for process to stop @@ -67,7 +68,8 @@ function end-process() { if process-running $1 ; then echo "failed to stop." - echo -n " Killing $1..." + pid=$( pgrep -o -f "python3 -m mycroft.*${1}" ) + echo -n " Killing $1 (${pid})..." kill -9 ${pid} echo "killed." result=120 @@ -80,8 +82,10 @@ function end-process() { fi } + result=0 # default, no change + OPT=$1 shift @@ -94,15 +98,7 @@ case ${OPT} in end-process skills end-process audio end-process speech - - # determine platform type - if [[ -r /etc/mycroft/mycroft.conf ]] ; then - mycroft_platform=$( jq -r ".enclosure.platform" < /etc/mycroft/mycroft.conf ) - if [[ $mycroft_platform == "mycroft_mark_1" ]] ; then - # running on a Mark 1, stop enclosure service - end-process enclosure - fi - fi + end-process enclosure ;; "bus") end-process messagebus.service @@ -119,6 +115,7 @@ case ${OPT} in "enclosure") end-process enclosure ;; + *) help ;; @@ -128,4 +125,4 @@ esac # 0 if nothing changed (e.g. --help or no process was running) # 100 at least one process was stopped # 120 if any process had to be killed -exit $result +exit $result \ No newline at end of file diff --git a/buildroot-external/package/python-mycroft/python-mycroft.mk b/buildroot-external/package/python-mycroft/python-mycroft.mk index be32aed0..ed4583eb 100644 --- a/buildroot-external/package/python-mycroft/python-mycroft.mk +++ b/buildroot-external/package/python-mycroft/python-mycroft.mk @@ -7,6 +7,6 @@ PYTHON_MYCROFT_VERSION = v18.8.12 PYTHON_MYCROFT_SITE = $(call github,MycroftAI,mycroft-core,release/$(PYTHON_MYCROFT_VERSION)) PYTHON_MYCROFT_SETUP_TYPE = setuptools -PYTHON_MYCROFT_LICENSE_FILES = +PYTHON_MYCROFT_LICENSE_FILES = LICENSE $(eval $(python-package)) diff --git a/buildroot-external/rootfs-overlay/etc/init.d/S90mycroft_prepare b/buildroot-external/rootfs-overlay/etc/init.d/S90mycroft_prepare deleted file mode 100755 index 0553ae9a..00000000 --- a/buildroot-external/rootfs-overlay/etc/init.d/S90mycroft_prepare +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh -# -# Prepare Mycroft software stack. -# - -start() { - # set the right locale / language settings - export LC_ALL=en_US.UTF-8 - export LANG=en_US.UTF-8 - export LANGUAGE=en_US.UTF-8 - - # Check if Mycroft log folders are present and if not - # create those logging folders - if [[ ! -w /var/log/mycroft/ ]] ; then - # Creating needed folders - printf "Creating /var/log/mycroft/ directory" - if [[ ! -d /var/log/mycroft/ ]] ; then - mkdir /var/log/mycroft/ - fi - fi - - # Check if /.mycroft exist already and if not - # create a symbolic link to /root/.mycroft - if [[ ! -w /.mycroft/ ]] ; then - # Creating .mycroft symlink - printf "Creating /.mycroft/ symlink" - if [[ ! -d /.mycroft/ ]] ; then - ln -s /root/.mycroft /.mycroft - fi - fi -} -case "$1" in - start) - start - ;; - *) - echo "Usage: $0 {start}" - exit 1 -esac - -exit $? diff --git a/buildroot-external/rootfs-overlay/etc/init.d/S91mycroft_services b/buildroot-external/rootfs-overlay/etc/init.d/S91mycroft_services deleted file mode 100755 index 00a8dfc6..00000000 --- a/buildroot-external/rootfs-overlay/etc/init.d/S91mycroft_services +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh -# -# Starts Mycroft services. -# - -start() { - printf "Starting Mycroft services: " - umask 077 - bash /usr/bin/start-mycroft.sh all - echo "OK" -} -stop() { - printf "Stopping Mycroft services: " - bash /usr/bin/stop-mycroft.sh all - echo "OK" -} -restart() { - stop - start -} - -case "$1" in - start) - start - ;; - stop) - stop - ;; - restart|reload) - restart - ;; - *) - echo "Usage: $0 {start|stop|restart}" - exit 1 -esac - -exit $?