HMS

Home Media Server for Roku Players
git clone https://www.brianlane.com/git/HMS
Log | Files | Refs | README | LICENSE

commit b13b5c7793b548b60bddb4cf3e95c066bd23d22b
parent 00966fe22de633e2c1410548ede1bb70c32e5744
Author: Brian C. Lane <bcl@brianlane.com>
Date:   Sat, 12 Nov 2022 11:02:28 -0800

Makefile: Update to newest upstream and add FreeBSD tweaks

Diffstat:
MHMS/Makefile | 4++--
MHMS/app.mk | 674++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 634 insertions(+), 44 deletions(-)

diff --git a/HMS/Makefile b/HMS/Makefile @@ -22,7 +22,7 @@ # Set in your this variable in your shell startup (e.g. .bashrc) ########################################################################## APPNAME = HMS -VERSION = 3.0 -ZIP_EXCLUDE = -x .git\* +VERSION = 4.0 +ZIP_EXCLUDE = -x .git\* -x \*.pkg -x storeassets\* -x keys\* -x \*/.\* include ./app.mk diff --git a/HMS/app.mk b/HMS/app.mk @@ -1,89 +1,679 @@ ######################################################################### # common include file for application Makefiles # -# Makefile Usage: +# Makefile common usage: # > make +# > make run # > make install # > make remove # -# to exclude certain files from being added to the zipfile during packaging +# Makefile less common usage: +# > make art-opt +# > make pkg +# > make install_native +# > make remove_native +# > make tr +# +# By default, ZIP_EXCLUDE will exclude -x \*.pkg -x storeassets\* -x keys\* -x .\* +# If you define ZIP_EXCLUDE in your Makefile, it will override the default setting. +# +# To exclude different files from being added to the zipfile during packaging # include a line like this:ZIP_EXCLUDE= -x keys\* # that will exclude any file who's name begins with 'keys' # to exclude using more than one pattern use additional '-x <pattern>' arguments # ZIP_EXCLUDE= -x \*.pkg -x storeassets\* # -# Important Notes: -# To use the "install" and "remove" targets to install your +# If you want to add additional files to the default ZIP_EXCLUDE use +# ZIP_EXCLUDE_LOCAL +# +# Important Notes: +# To use the "run", "install" and "remove" targets to install your # application directly from the shell, you must do the following: # # 1) Make sure that you have the curl command line executable in your path -# 2) Set the variable ROKU_DEV_TARGET in your environment to the IP +# 2) Set the variable ROKU_DEV_TARGET in your environment to the IP # address of your Roku box. (e.g. export ROKU_DEV_TARGET=192.168.1.1. -# Set in your this variable in your shell startup (e.g. .bashrc) -########################################################################## -PKGREL = ../../packages -ZIPREL = ../../zips -SOURCEREL = .. +########################################################################## + +# improve performance and simplify Makefile debugging by omitting +# default language rules that don't apply to this environment. +MAKEFLAGS += --no-builtin-rules +.SUFFIXES: + +HOST_OS := unknown +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Darwin) + HOST_OS := macos +else ifeq ($(UNAME_S),Linux) + HOST_OS := linux +else ifneq (,$(findstring CYGWIN,$(UNAME_S))) + HOST_OS := cygwin +else ifeq ($(UNAME_S),FreeBSD) + HOST_OS := freebsd +endif + +IS_TEAMCITY_BUILD ?= +ifneq ($(TEAMCITY_BUILDCONF_NAME),) +IS_TEAMCITY_BUILD := true +endif + +# get the root directory in absolute form, so that current directory +# can be changed during the make if needed. +APPS_ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) + +# the current directory is the app root directory +SOURCEDIR := . + +DISTREL := $(APPS_ROOT_DIR)/dist +COMMONREL := $(APPS_ROOT_DIR)/common + +ZIPREL := $(DISTREL)/apps +PKGREL := $(DISTREL)/packages +CHECK_TMP_DIR := $(DISTREL)/tmp-check + +DATE_TIME := $(shell date +%F-%T) + +APP_ZIP_FILE := $(ZIPREL)/$(APPNAME).zip +APP_PKG_FILE := $(PKGREL)/$(APPNAME)_$(DATE_TIME).pkg + +# these variables are only used for the .pkg file version tagging. +APP_NAME := $(APPNAME) +APP_VERSION := $(VERSION) +ifeq ($(IS_TEAMCITY_BUILD),true) +APP_NAME := $(subst /,-,$(TEAMCITY_BUILDCONF_NAME)) +APP_VERSION := $(BUILD_NUMBER) +endif -.PHONY: all $(APPNAME) +APPSOURCEDIR := $(SOURCEDIR)/source +IMPORTFILES := $(foreach f,$(IMPORTS),$(COMMONREL)/$f.brs) +IMPORTCLEANUP := $(foreach f,$(IMPORTS),$(APPSOURCEDIR)/$f.brs) -$(APPNAME): +# ROKU_NATIVE_DEV must be set in the calling environment to +# the firmware native-build src directory +NATIVE_DIST_DIR := $(ROKU_NATIVE_DEV)/dist +# +NATIVE_DEV_REL := $(NATIVE_DIST_DIR)/rootfs/Linux86_dev.OBJ/root/nvram/incoming +NATIVE_DEV_PKG := $(NATIVE_DEV_REL)/dev.zip +NATIVE_PLETHORA := $(NATIVE_DIST_DIR)/application/Linux86_dev.OBJ/root/bin/plethora +NATIVE_TICKLER := $(NATIVE_PLETHORA) tickle-plugin-installer + +# only Linux host is supported for these tools currently +APPS_TOOLS_DIR := $(APPS_ROOT_DIR)/tools/$(HOST_OS)/bin + +APP_PACKAGE_TOOL := $(APPS_TOOLS_DIR)/app-package +MAKE_TR_TOOL := $(APPS_TOOLS_DIR)/maketr +BRIGHTSCRIPT_TOOL := $(APPS_TOOLS_DIR)/brightscript + +# if building from a firmware tree, use the BrightScript libraries from there +ifneq (,$(wildcard $(APPS_ROOT_DIR)/../3rdParty/brightscript/Scripts/LibCore/.)) +BRIGHTSCRIPT_LIBS_DIR ?= $(APPS_ROOT_DIR)/../3rdParty/brightscript/Scripts/LibCore +endif +# else use the reference libraries from the tools directory. +BRIGHTSCRIPT_LIBS_DIR ?= $(APPS_ROOT_DIR)/tools/brightscript/Scripts/LibCore + +APP_KEY_PASS_TMP := /tmp/app_key_pass +DEV_SERVER_TMP_FILE := /tmp/dev_server_out + +# The developer password that was set on the player is required for +# plugin_install operations on modern versions of firmware. +# It may be pre-specified in the DEVPASSWORD environment variable on entry, +# otherwise the make will stop and prompt the user to enter it when needed. +ifdef DEVPASSWORD + USERPASS := rokudev:$(DEVPASSWORD) +else + USERPASS := rokudev +endif + +ifeq ($(HOST_OS),macos) + # Mac doesn't support these args + CP_ARGS = +else + CP_ARGS = --preserve=ownership,timestamps --no-preserve=mode +endif + +# For a quick ping, we want the command to return success as soon as possible, +# and a timeout failure in no more than a second or two. +ifeq ($(HOST_OS),cygwin) + # This assumes that the Windows ping command is used, not cygwin's. + QUICK_PING_ARGS = -n 1 -w 1000 +else ifeq ($(HOST_OS),freebsd) + QUICK_PING_ARGS = -c 1 -t 1 +else # Linux + QUICK_PING_ARGS = -c 1 -w 1 +endif + +ifndef ZIP_EXCLUDE + ZIP_EXCLUDE= -x \*.pkg -x storeassets\* -x keys\* -x \*/.\* $(ZIP_EXCLUDE_LOCAL) +endif + +# ------------------------------------------------------------------------- +# $(APPNAME): the default target is to create the zip file for the app. +# This contains the set of files that are to be deployed on a Roku. +# ------------------------------------------------------------------------- +.PHONY: $(APPNAME) +$(APPNAME): manifest @echo "*** Creating $(APPNAME).zip ***" - @echo " >> removing old application zip $(ZIPREL)/$(APPNAME).zip" - @if [ -e "$(ZIPREL)/$(APPNAME).zip" ]; \ - then \ - rm $(ZIPREL)/$(APPNAME).zip; \ + @echo " >> removing old application zip $(APP_ZIP_FILE)" + @if [ -e "$(APP_ZIP_FILE)" ]; then \ + rm -f $(APP_ZIP_FILE); \ fi - @echo " >> creating destination directory $(ZIPREL)" - @if [ ! -d $(ZIPREL) ]; \ - then \ + @echo " >> creating destination directory $(ZIPREL)" + @if [ ! -d $(ZIPREL) ]; then \ mkdir -p $(ZIPREL); \ fi @echo " >> setting directory permissions for $(ZIPREL)" - @if [ ! -w $(ZIPREL) ]; \ - then \ + @if [ ! -w $(ZIPREL) ]; then \ chmod 755 $(ZIPREL); \ fi + @echo " >> copying imports" + @if [ "$(IMPORTFILES)" ]; then \ + mkdir $(APPSOURCEDIR)/common; \ + cp -f $(CP_ARGS) -v $(IMPORTFILES) $(APPSOURCEDIR)/common/; \ + fi \ + # zip .png files without compression # do not zip up Makefiles, or any files ending with '~' - @echo " >> creating application zip $(ZIPREL)/$(APPNAME).zip" - @if [ -d $(SOURCEREL)/$(APPNAME) ]; \ - then \ - (zip -0 -r "$(ZIPREL)/$(APPNAME).zip" . -i \*.png $(ZIP_EXCLUDE)); \ - (zip -9 -r "$(ZIPREL)/$(APPNAME).zip" . -x Makefile $(ZIP_EXCLUDE)); \ + @echo " >> creating application zip $(APP_ZIP_FILE)" + @if [ -d $(SOURCEDIR) ]; then \ + (zip -0 -r "$(APP_ZIP_FILE)" . -i \*.png $(ZIP_EXCLUDE)); \ + (zip -9 -r "$(APP_ZIP_FILE)" . -x \*~ -x \*.png -x Makefile $(ZIP_EXCLUDE)); \ else \ - echo "Source for $(APPNAME) not found at $(SOURCEREL)/$(APPNAME)"; \ + echo "Source for $(APPNAME) not found at $(SOURCEDIR)"; \ fi - @echo "*** developer zip $(APPNAME) complete ***" + @if [ "$(IMPORTCLEANUP)" ]; then \ + echo " >> deleting imports";\ + rm -r -f $(APPSOURCEDIR)/common; \ + fi \ + + @echo "*** packaging $(APPNAME) complete ***" + +# If DISTDIR is not empty then copy the zip package to the DISTDIR. +# Note that this is used by the firmware build, to build applications that are +# embedded in the firmware software image, such as the built-in screensaver. +# For those cases, the Netflix/Makefile calls this makefile for each app +# with DISTDIR and DISTZIP set to the target directory and base filename +# respectively. + @if [ $(DISTDIR) ]; then \ + rm -f $(DISTDIR)/$(DISTZIP).zip; \ + mkdir -p $(DISTDIR); \ + cp -f --preserve=ownership,timestamps --no-preserve=mode \ + $(APP_ZIP_FILE) $(DISTDIR)/$(DISTZIP).zip; \ + fi + +# ------------------------------------------------------------------------- +# clean: remove any build output for the app. +# ------------------------------------------------------------------------- +.PHONY: clean +clean: + rm -f $(APP_ZIP_FILE) +# FIXME: we should use a canonical output file name, rather than having +# the date-time stamp in the output file name. +# rm -f $(APP_PKG_FILE) + rm -f $(PKGREL)/$(APPNAME)_*.pkg + +# ------------------------------------------------------------------------- +# clobber: remove any build output for the app. +# ------------------------------------------------------------------------- +.PHONY: clobber +clobber: clean + +# ------------------------------------------------------------------------- +# dist-clean: remove the dist directory for the sandbox. +# ------------------------------------------------------------------------- +.PHONY: dist-clean +dist-clean: + rm -rf $(DISTREL)/* + +# ------------------------------------------------------------------------- +# CHECK_OPTIONS: this is used to specify configurable options, such +# as which version of the BrightScript library sources should be used +# to compile the app. +# ------------------------------------------------------------------------- +CHECK_OPTIONS = +ifneq (,$(wildcard $(BRIGHTSCRIPT_LIBS_DIR)/.)) +CHECK_OPTIONS += -lib $(BRIGHTSCRIPT_LIBS_DIR) +endif + +# ------------------------------------------------------------------------- +# check: run the desktop BrightScript compiler/check tool on the +# application. +# You can bypass checking on the application by setting +# APP_CHECK_DISABLED=true in the app's Makefile or in the environment. +# ------------------------------------------------------------------------- +.PHONY: check +check: $(APPNAME) +ifeq ($(APP_CHECK_DISABLED),true) +ifeq ($(IS_TEAMCITY_BUILD),true) + @echo "*** Warning: application check skipped ***" +endif +else +ifeq ($(wildcard $(BRIGHTSCRIPT_TOOL)),) + @echo "*** Note: application check not available ***" +else + @echo "*** Checking application ***" + rm -rf $(CHECK_TMP_DIR) + mkdir -p $(CHECK_TMP_DIR) + unzip -q $(APP_ZIP_FILE) -d $(CHECK_TMP_DIR) + $(BRIGHTSCRIPT_TOOL) check \ + $(CHECK_OPTIONS) \ + $(CHECK_TMP_DIR) + rm -rf $(CHECK_TMP_DIR) +endif +endif + +# ------------------------------------------------------------------------- +# check-strict: run the desktop BrightScript compiler/check tool on the +# application using strict mode. +# ------------------------------------------------------------------------- +.PHONY: check-strict +check-strict: $(APPNAME) + @echo "*** Checking application (strict) ***" + rm -rf $(CHECK_TMP_DIR) + mkdir -p $(CHECK_TMP_DIR) + unzip -q $(APP_ZIP_FILE) -d $(CHECK_TMP_DIR) + $(BRIGHTSCRIPT_TOOL) check -strict \ + $(CHECK_OPTIONS) \ + $(CHECK_TMP_DIR) + rm -rf $(CHECK_TMP_DIR) + +# ------------------------------------------------------------------------- +# GET_FRIENDLY_NAME_FROM_DD is used to extract the Roku device ID +# from the ECP device description XML response. +# ------------------------------------------------------------------------- +define GET_FRIENDLY_NAME_FROM_DD + cat $(DEV_SERVER_TMP_FILE) | \ + grep -o "<friendlyName>.*</friendlyName>" | \ + sed "s|<friendlyName>||" | \ + sed "s|</friendlyName>||" +endef + +# ------------------------------------------------------------------------- +# CHECK_ROKU_DEV_TARGET is used to check if ROKU_DEV_TARGET refers a +# Roku device on the network that has an enabled developer web server. +# If the target doesn't exist or doesn't have an enabled web server +# the connection should fail. +# ------------------------------------------------------------------------- +define CHECK_ROKU_DEV_TARGET + if [ -z "$(ROKU_DEV_TARGET)" ]; then \ + echo "ERROR: ROKU_DEV_TARGET is not set."; \ + exit 1; \ + fi + echo "Checking dev server at $(ROKU_DEV_TARGET)..." + + # first check if the device is on the network via a quick ping + ping $(QUICK_PING_ARGS) $(ROKU_DEV_TARGET) &> $(DEV_SERVER_TMP_FILE) || \ + ( \ + echo "ERROR: Device is not responding to ping."; \ + exit 1 \ + ) + + # second check ECP, to verify we are talking to a Roku + rm -f $(DEV_SERVER_TMP_FILE) + curl --connect-timeout 2 --silent --output $(DEV_SERVER_TMP_FILE) \ + http://$(ROKU_DEV_TARGET):8060 || \ + ( \ + echo "ERROR: Device is not responding to ECP...is it a Roku?"; \ + exit 1 \ + ) + + # echo the device friendly name to let us know what we are talking to + ROKU_DEV_NAME=`$(GET_FRIENDLY_NAME_FROM_DD)`; \ + echo "Device reports as \"$$ROKU_DEV_NAME\"." + + # third check dev web server. + # Note, it should return 401 Unauthorized since we aren't passing the password. + rm -f $(DEV_SERVER_TMP_FILE) + HTTP_STATUS=`curl --connect-timeout 2 --silent --output $(DEV_SERVER_TMP_FILE) \ + http://$(ROKU_DEV_TARGET)` || \ + ( \ + echo "ERROR: Device server is not responding...is the developer installer enabled?"; \ + exit 1 \ + ) + + echo "Dev server is ready." +endef + +# ------------------------------------------------------------------------- +# CHECK_DEVICE_HTTP_STATUS is used to that the last curl command +# to the dev web server returned HTTP 200 OK. +# ------------------------------------------------------------------------- +define CHECK_DEVICE_HTTP_STATUS + if [ "$$HTTP_STATUS" != "200" ]; then \ + echo "ERROR: Device returned HTTP $$HTTP_STATUS"; \ + exit 1; \ + fi +endef + +# ------------------------------------------------------------------------- +# GET_PLUGIN_PAGE_RESULT_STATUS is used to extract the status message +# (e.g. Success/Failed) from the dev server plugin_* web page response. +# (Note that the plugin_install web page has two fields, whereas the +# plugin_package web page just has one). +# ------------------------------------------------------------------------- +define GET_PLUGIN_PAGE_RESULT_STATUS + cat $(DEV_SERVER_TMP_FILE) | \ + grep -o "<font color=\"red\">.*" | \ + sed "s|<font color=\"red\">||" | \ + sed "s|</font>||" +endef + +# ------------------------------------------------------------------------- +# GET_PLUGIN_PAGE_PACKAGE_LINK is used to extract the installed package +# URL from the dev server plugin_package web page response. +# ------------------------------------------------------------------------- +define GET_PLUGIN_PAGE_PACKAGE_LINK = + cat $(DEV_SERVER_TMP_FILE) | \ + grep -o "<a href=\"pkgs//[^\"]*\"" | \ + sed "s|<a href=\"pkgs//||" | \ + sed "s|\"||" +endef + +# ------------------------------------------------------------------------- +# install: install the app as the dev channel on the Roku target device. +# ------------------------------------------------------------------------- +.PHONY: install +install: $(APPNAME) check + @$(CHECK_ROKU_DEV_TARGET) + + @echo "Installing $(APPNAME)..." + @rm -f $(DEV_SERVER_TMP_FILE) + @HTTP_STATUS=`curl --user $(USERPASS) --digest --silent --show-error \ + -F "mysubmit=Install" -F "archive=@$(APP_ZIP_FILE)" \ + --output $(DEV_SERVER_TMP_FILE) \ + --write-out "%{http_code}" \ + http://$(ROKU_DEV_TARGET)/plugin_install`; \ + $(CHECK_DEVICE_HTTP_STATUS) + + @MSG=`$(GET_PLUGIN_PAGE_RESULT_STATUS)`; \ + echo "Result: $$MSG" + +# ------------------------------------------------------------------------- +# remove: uninstall the dev channel from the Roku target device. +# ------------------------------------------------------------------------- +.PHONY: remove +remove: + @$(CHECK_ROKU_DEV_TARGET) + + @echo "Removing dev app..." + @rm -f $(DEV_SERVER_TMP_FILE) + @HTTP_STATUS=`curl --user $(USERPASS) --digest --silent --show-error \ + -F "mysubmit=Delete" -F "archive=" \ + --output $(DEV_SERVER_TMP_FILE) \ + --write-out "%{http_code}" \ + http://$(ROKU_DEV_TARGET)/plugin_install`; \ + $(CHECK_DEVICE_HTTP_STATUS) + + @MSG=`$(GET_PLUGIN_PAGE_RESULT_STATUS)`; \ + echo "Result: $$MSG" + +# ------------------------------------------------------------------------- +# check-roku-dev-target: check the status of the Roku target device. +# ------------------------------------------------------------------------- +.PHONY: check-roku-dev-target +check-roku-dev-target: + @$(CHECK_ROKU_DEV_TARGET) -install: $(APPNAME) - @echo "Installing $(APPNAME) to host $(ROKU_DEV_TARGET)" - @curl -s -S -F "mysubmit=Install" -F "archive=@$(ZIPREL)/$(APPNAME).zip" -F "password=" -u $(ROKU_DEV_USER):$(ROKU_DEV_PASSWORD) --anyauth http://$(ROKU_DEV_TARGET)/plugin_install | grep "<font color" | sed "s/<font color=\"red\">//" +# ------------------------------------------------------------------------- +# run: the install target is 'smart' and doesn't do anything if the package +# didn't change. +# But usually I want to run it even if it didn't change, so force a fresh +# install by doing a remove first. +# Some day we should look at doing the force run via a plugin_install flag, +# but for now just brute force it. +# ------------------------------------------------------------------------- +.PHONY: run +run: remove install +# ------------------------------------------------------------------------- +# pkg: use to create a pkg file from the application sources. +# +# Usage: +# The application name should be specified via $APPNAME. +# The application version should be specified via $VERSION. +# The developer's signing password (from genkey) should be passed via +# $APP_KEY_PASS, or via stdin, otherwise the script will prompt for it. +# ------------------------------------------------------------------------- +.PHONY: pkg pkg: install @echo "*** Creating Package ***" - @echo " >> creating destination directory $(PKGREL)" - @if [ ! -d $(PKGREL) ]; \ - then \ + @echo " >> creating destination directory $(PKGREL)" + @if [ ! -d $(PKGREL) ]; then \ mkdir -p $(PKGREL); \ fi @echo " >> setting directory permissions for $(PKGREL)" - @if [ ! -w $(PKGREL) ]; \ - then \ + @if [ ! -w $(PKGREL) ]; then \ chmod 755 $(PKGREL); \ fi - @echo "Packaging $(APPNAME) on host $(ROKU_DEV_TARGET)" - @read -p "Password: " REPLY ; echo $$REPLY | xargs -i curl -s -S -Fmysubmit=Package -Fapp_name=$(APPNAME)/$(VERSION) -Fpasswd={} -Fpkg_time=`expr \`date +%s\` \* 1000` "http://$(ROKU_DEV_TARGET)/plugin_package" | grep '^<font face=' | sed 's/.*href=\"\([^\"]*\)\".*/\1/' | sed 's#pkgs/##' | xargs -i curl -s -S -o $(PKGREL)/$(APPNAME)_{} http://$(ROKU_DEV_TARGET)/pkgs/{} + @$(CHECK_ROKU_DEV_TARGET) - @echo "*** Package $(APPNAME) complete ***" -remove: - @echo "Removing $(APPNAME) from host $(ROKU_DEV_TARGET)" - @curl -s -S -F "mysubmit=Delete" -F "archive=" -F "passwd=" http://$(ROKU_DEV_TARGET)/plugin_install | grep "<font color" | sed "s/<font color=\"red\">//" + @echo "Packaging $(APP_NAME)/$(APP_VERSION) to $(APP_PKG_FILE)" + + @if [ -z "$(APP_KEY_PASS)" ]; then \ + read -r -p "Password: " REPLY; \ + echo "$$REPLY" > $(APP_KEY_PASS_TMP); \ + else \ + echo "$(APP_KEY_PASS)" > $(APP_KEY_PASS_TMP); \ + fi + + @rm -f $(DEV_SERVER_TMP_FILE) + @PASSWD=`cat $(APP_KEY_PASS_TMP)`; \ + PKG_TIME=`expr \`date +%s\` \* 1000`; \ + HTTP_STATUS=`curl --user $(USERPASS) --digest --silent --show-error \ + -F "mysubmit=Package" -F "app_name=$(APP_NAME)/$(APP_VERSION)" \ + -F "passwd=$$PASSWD" -F "pkg_time=$$PKG_TIME" \ + --output $(DEV_SERVER_TMP_FILE) \ + --write-out "%{http_code}" \ + http://$(ROKU_DEV_TARGET)/plugin_package`; \ + $(CHECK_DEVICE_HTTP_STATUS) + + @MSG=`$(GET_PLUGIN_PAGE_RESULT_STATUS)`; \ + case "$$MSG" in \ + *Success*) \ + ;; \ + *) echo "Result: $$MSG"; \ + exit 1 \ + ;; \ + esac + + @PKG_LINK=`$(GET_PLUGIN_PAGE_PACKAGE_LINK)`; \ + HTTP_STATUS=`curl --user $(USERPASS) --digest --silent --show-error \ + --output $(APP_PKG_FILE) \ + --write-out "%{http_code}" \ + http://$(ROKU_DEV_TARGET)/pkgs/$$PKG_LINK`; \ + $(CHECK_DEVICE_HTTP_STATUS) + + @echo "*** Package $(APPNAME) complete ***" + +# ------------------------------------------------------------------------- +# app-pkg: use to create a pkg file from the application sources. +# Similar to the pkg target, but does not require a player to do the signing. +# Instead it requires the developer key file and signing password to be +# specified, which are then passed to the app-package desktop tool to create +# the package file. +# +# Usage: +# The application name should be specified via $APPNAME. +# The application version should be specified via $VERSION. +# The developer's key file (.pkg file) should be specified via $APP_KEY_FILE. +# The developer's signing password (from genkey) should be passed via +# $APP_KEY_PASS, or via stdin, otherwise the script will prompt for it. +# ------------------------------------------------------------------------- +.PHONY: app-pkg +app-pkg: $(APPNAME) check + @echo "*** Creating package ***" + + @echo " >> creating destination directory $(PKGREL)" + @mkdir -p $(PKGREL) && chmod 755 $(PKGREL) + + @if [ -z "$(APP_KEY_FILE)" ]; then \ + echo "ERROR: APP_KEY_FILE not defined"; \ + exit 1; \ + fi + @if [ ! -f "$(APP_KEY_FILE)" ]; then \ + echo "ERROR: key file not found: $(APP_KEY_FILE)"; \ + exit 1; \ + fi + + @if [ -z "$(APP_KEY_PASS)" ]; then \ + read -r -p "Password: " REPLY; \ + echo "$$REPLY" > $(APP_KEY_PASS_TMP); \ + else \ + echo "$(APP_KEY_PASS)" > $(APP_KEY_PASS_TMP); \ + fi + + @echo "Packaging $(APP_NAME)/$(APP_VERSION) to $(APP_PKG_FILE)" + + @if [ -z "$(APP_VERSION)" ]; then \ + echo "WARNING: VERSION is not set."; \ + fi + + @PASSWD=`cat $(APP_KEY_PASS_TMP)`; \ + $(APP_PACKAGE_TOOL) package $(APP_ZIP_FILE) \ + -n $(APP_NAME)/$(APP_VERSION) \ + -k $(APP_KEY_FILE) \ + -p "$$PASSWD" \ + -o $(APP_PKG_FILE) + + @rm $(APP_KEY_PASS_TMP) + + @echo "*** Package $(APPNAME) complete ***" + +# ------------------------------------------------------------------------- +# teamcity: used to build .zip and .pkg file on TeamCity. +# See app-pkg target for info on options for specifying the signing password. +# ------------------------------------------------------------------------- +.PHONY: teamcity +teamcity: app-pkg +ifeq ($(IS_TEAMCITY_BUILD),true) + @echo "Adding TeamCity artifacts..." + + sudo rm -f /tmp/artifacts + sudo mkdir -p /tmp/artifacts + + cp $(APP_ZIP_FILE) /tmp/artifacts/$(APP_NAME)-$(APP_VERSION).zip + @echo "##teamcity[publishArtifacts '/tmp/artifacts/$(APP_NAME)-$(APP_VERSION).zip']" + + cp $(APP_PKG_FILE) /tmp/artifacts/$(APP_NAME)-$(APP_VERSION).pkg + @echo "##teamcity[publishArtifacts '/tmp/artifacts/$(APP_NAME)-$(APP_VERSION).pkg']" + + @echo "TeamCity artifacts complete." +else + @echo "Not running on TeamCity, skipping artifacts." +endif + +########################################################################## + +# ------------------------------------------------------------------------- +# CHECK_NATIVE_TARGET is used to check if the Roku simulator is +# configured. +# ------------------------------------------------------------------------- +define CHECK_NATIVE_TARGET + if [ -z "$(ROKU_NATIVE_DEV)" ]; then \ + echo "ERROR: ROKU_NATIVE_DEV not defined"; \ + exit 1; \ + i + if [ ! -d "$(ROKU_NATIVE_DEV)" ]; then \ + echo "ERROR: native dev dir not found: $(ROKU_NATIVE_DEV)"; \ + exit 1; \ + fi + if [ ! -d "$(NATIVE_DIST_DIR)" ]; then \ + echo "ERROR: native build dir not found: $(NATIVE_DIST_DIR)"; \ + exit 1; \ + fi +endef + +# ------------------------------------------------------------------------- +# install-native: install the app as the dev channel on the Roku simulator. +# ------------------------------------------------------------------------- +.PHONY: install-native +install-native: $(APPNAME) check + @$(CHECK_NATIVE_TARGET) + @echo "Installing $(APPNAME) to native." + @if [ ! -d "$(NATIVE_DEV_REL)" ]; then \ + mkdir "$(NATIVE_DEV_REL)"; \ + fi + @echo "Source is $(APP_ZIP_FILE)" + @echo "Target is $(NATIVE_DEV_PKG)" + @cp $(APP_ZIP_FILE) $(NATIVE_DEV_PKG) + @$(NATIVE_TICKLER) + +# ------------------------------------------------------------------------- +# remove-native: uninstall the dev channel from the Roku simulator. +# ------------------------------------------------------------------------- +.PHONY: remove-native +remove-native: + @$(CHECK_NATIVE_TARGET) + @echo "Removing $(APPNAME) from native." + @rm $(NATIVE_DEV_PKG) + @$(NATIVE_TICKLER) + +########################################################################## + +# ------------------------------------------------------------------------- +# art-jpg-opt: compress any jpg files in the source tree. +# Used by the art-opt target. +# ------------------------------------------------------------------------- +APPS_JPG_ART=`\find . -name "*.jpg"` + +.PHONY: art-jpg-opt +art-jpg-opt: + p4 edit $(APPS_JPG_ART) + for i in $(APPS_JPG_ART); \ + do \ + TMPJ=`mktemp` || return 1; \ + echo "optimizing $$i"; \ + (jpegtran -copy none -optimize -outfile $$TMPJ $$i && mv -f $$TMPJ $$i &); \ + done + wait + p4 revert -a $(APPS_JPG_ART) + +# ------------------------------------------------------------------------- +# art-png-opt: compress any png files in the source tree. +# Used by the art-opt target. +# ------------------------------------------------------------------------- +APPS_PNG_ART=`\find . -name "*.png"` + +.PHONY: art-png-opt +art-png-opt: + p4 edit $(APPS_PNG_ART) + for i in $(APPS_PNG_ART); \ + do \ + (optipng -o7 $$i &); \ + done + wait + p4 revert -a $(APPS_PNG_ART) + +# ------------------------------------------------------------------------- +# art-opt: compress any png and jpg files in the source tree using +# lossless compression options. +# This assumes a Perforce client/workspace is configured. +# Modified files are opened for edit in the default changelist. +# ------------------------------------------------------------------------- +.PHONY: art-opt +art-opt: art-png-opt art-jpg-opt + +########################################################################## + +# ------------------------------------------------------------------------- +# tr: this target is used to update translation files for an application +# MAKE_TR_OPTIONS may be set to [-t] [-d] etc. in the external environment, +# if needed. +# ------------------------------------------------------------------------- +.PHONY: tr +tr: + p4 opened -c default + p4 edit locale/.../translations.xml + $(MAKE_TR_TOOL) $(MAKE_TR_OPTIONS) + rm locale/en_US/translations.xml + p4 revert -a locale/.../translations.xml + p4 opened -c default + +##########################################################################