HMS

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

app.mk (23832B)


      1 #########################################################################
      2 # common include file for application Makefiles
      3 #
      4 # Makefile common usage:
      5 # > make
      6 # > make run
      7 # > make install
      8 # > make remove
      9 #
     10 # Makefile less common usage:
     11 # > make art-opt
     12 # > make pkg
     13 # > make install_native
     14 # > make remove_native
     15 # > make tr
     16 #
     17 # By default, ZIP_EXCLUDE will exclude -x \*.pkg -x storeassets\* -x keys\* -x .\*
     18 # If you define ZIP_EXCLUDE in your Makefile, it will override the default setting.
     19 #
     20 # To exclude different files from being added to the zipfile during packaging
     21 # include a line like this:ZIP_EXCLUDE= -x keys\*
     22 # that will exclude any file who's name begins with 'keys'
     23 # to exclude using more than one pattern use additional '-x <pattern>' arguments
     24 # ZIP_EXCLUDE= -x \*.pkg -x storeassets\*
     25 #
     26 # If you want to add additional files to the default ZIP_EXCLUDE use
     27 # ZIP_EXCLUDE_LOCAL
     28 #
     29 # Important Notes:
     30 # To use the "run", "install" and "remove" targets to install your
     31 # application directly from the shell, you must do the following:
     32 #
     33 # 1) Make sure that you have the curl command line executable in your path
     34 # 2) Set the variable ROKU_DEV_TARGET in your environment to the IP
     35 #    address of your Roku box. (e.g. export ROKU_DEV_TARGET=192.168.1.1.
     36 ##########################################################################
     37 
     38 # improve performance and simplify Makefile debugging by omitting
     39 # default language rules that don't apply to this environment.
     40 MAKEFLAGS += --no-builtin-rules
     41 .SUFFIXES:
     42 
     43 HOST_OS := unknown
     44 UNAME_S := $(shell uname -s)
     45 ifeq ($(UNAME_S),Darwin)
     46 	HOST_OS := macos
     47 else ifeq ($(UNAME_S),Linux)
     48 	HOST_OS := linux
     49 else ifneq (,$(findstring CYGWIN,$(UNAME_S)))
     50 	HOST_OS := cygwin
     51 else ifeq ($(UNAME_S),FreeBSD)
     52 	HOST_OS := freebsd
     53 endif
     54 
     55 IS_TEAMCITY_BUILD ?=
     56 ifneq ($(TEAMCITY_BUILDCONF_NAME),)
     57 IS_TEAMCITY_BUILD := true
     58 endif
     59 
     60 # get the root directory in absolute form, so that current directory
     61 # can be changed during the make if needed.
     62 APPS_ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
     63 
     64 # the current directory is the app root directory
     65 SOURCEDIR := .
     66 
     67 DISTREL := $(APPS_ROOT_DIR)/dist
     68 COMMONREL := $(APPS_ROOT_DIR)/common
     69 
     70 ZIPREL := $(DISTREL)/apps
     71 PKGREL := $(DISTREL)/packages
     72 CHECK_TMP_DIR := $(DISTREL)/tmp-check
     73 
     74 DATE_TIME := $(shell date +%F-%T)
     75 
     76 APP_ZIP_FILE := $(ZIPREL)/$(APPNAME).zip
     77 APP_PKG_FILE := $(PKGREL)/$(APPNAME)_$(DATE_TIME).pkg
     78 
     79 # these variables are only used for the .pkg file version tagging.
     80 APP_NAME := $(APPNAME)
     81 APP_VERSION := $(VERSION)
     82 ifeq ($(IS_TEAMCITY_BUILD),true)
     83 APP_NAME    := $(subst /,-,$(TEAMCITY_BUILDCONF_NAME))
     84 APP_VERSION := $(BUILD_NUMBER)
     85 endif
     86 
     87 APPSOURCEDIR := $(SOURCEDIR)/source
     88 IMPORTFILES := $(foreach f,$(IMPORTS),$(COMMONREL)/$f.brs)
     89 IMPORTCLEANUP := $(foreach f,$(IMPORTS),$(APPSOURCEDIR)/$f.brs)
     90 
     91 # ROKU_NATIVE_DEV must be set in the calling environment to
     92 # the firmware native-build src directory
     93 NATIVE_DIST_DIR := $(ROKU_NATIVE_DEV)/dist
     94 #
     95 NATIVE_DEV_REL  := $(NATIVE_DIST_DIR)/rootfs/Linux86_dev.OBJ/root/nvram/incoming
     96 NATIVE_DEV_PKG  := $(NATIVE_DEV_REL)/dev.zip
     97 NATIVE_PLETHORA := $(NATIVE_DIST_DIR)/application/Linux86_dev.OBJ/root/bin/plethora
     98 NATIVE_TICKLER  := $(NATIVE_PLETHORA) tickle-plugin-installer
     99 
    100 # only Linux host is supported for these tools currently
    101 APPS_TOOLS_DIR    := $(APPS_ROOT_DIR)/tools/$(HOST_OS)/bin
    102 
    103 APP_PACKAGE_TOOL  := $(APPS_TOOLS_DIR)/app-package
    104 MAKE_TR_TOOL      := $(APPS_TOOLS_DIR)/maketr
    105 BRIGHTSCRIPT_TOOL := $(APPS_TOOLS_DIR)/brightscript
    106 
    107 # if building from a firmware tree, use the BrightScript libraries from there
    108 ifneq (,$(wildcard $(APPS_ROOT_DIR)/../3rdParty/brightscript/Scripts/LibCore/.))
    109 BRIGHTSCRIPT_LIBS_DIR ?= $(APPS_ROOT_DIR)/../3rdParty/brightscript/Scripts/LibCore
    110 endif
    111 # else use the reference libraries from the tools directory.
    112 BRIGHTSCRIPT_LIBS_DIR ?= $(APPS_ROOT_DIR)/tools/brightscript/Scripts/LibCore
    113 
    114 APP_KEY_PASS_TMP := /tmp/app_key_pass
    115 DEV_SERVER_TMP_FILE := /tmp/dev_server_out
    116 
    117 # The developer password that was set on the player is required for
    118 # plugin_install operations on modern versions of firmware.
    119 # It may be pre-specified in the DEVPASSWORD environment variable on entry,
    120 # otherwise the make will stop and prompt the user to enter it when needed.
    121 ifdef DEVPASSWORD
    122 	USERPASS := rokudev:$(DEVPASSWORD)
    123 else
    124 	USERPASS := rokudev
    125 endif
    126 
    127 ifeq ($(HOST_OS),macos)
    128 	# Mac doesn't support these args
    129 	CP_ARGS =
    130 else
    131 	CP_ARGS = --preserve=ownership,timestamps --no-preserve=mode
    132 endif
    133 
    134 # For a quick ping, we want the command to return success as soon as possible,
    135 # and a timeout failure in no more than a second or two.
    136 ifeq ($(HOST_OS),cygwin)
    137 	# This assumes that the Windows ping command is used, not cygwin's.
    138 	QUICK_PING_ARGS = -n 1 -w 1000
    139 else ifeq ($(HOST_OS),freebsd)
    140 	QUICK_PING_ARGS = -c 1 -t 1
    141 else # Linux
    142 	QUICK_PING_ARGS = -c 1 -w 1
    143 endif
    144 
    145 ifndef ZIP_EXCLUDE
    146 	ZIP_EXCLUDE= -x \*.pkg -x storeassets\* -x keys\* -x \*/.\* $(ZIP_EXCLUDE_LOCAL)
    147 endif
    148 
    149 # -------------------------------------------------------------------------
    150 # $(APPNAME): the default target is to create the zip file for the app.
    151 # This contains the set of files that are to be deployed on a Roku.
    152 # -------------------------------------------------------------------------
    153 .PHONY: $(APPNAME)
    154 $(APPNAME): manifest
    155 	@echo "*** Creating $(APPNAME).zip ***"
    156 
    157 	@echo "  >> removing old application zip $(APP_ZIP_FILE)"
    158 	@if [ -e "$(APP_ZIP_FILE)" ]; then \
    159 		rm -f $(APP_ZIP_FILE); \
    160 	fi
    161 
    162 	@echo "  >> creating destination directory $(ZIPREL)"
    163 	@if [ ! -d $(ZIPREL) ]; then \
    164 		mkdir -p $(ZIPREL); \
    165 	fi
    166 
    167 	@echo "  >> setting directory permissions for $(ZIPREL)"
    168 	@if [ ! -w $(ZIPREL) ]; then \
    169 		chmod 755 $(ZIPREL); \
    170 	fi
    171 
    172 	@echo "  >> copying imports"
    173 	@if [ "$(IMPORTFILES)" ]; then \
    174 		mkdir $(APPSOURCEDIR)/common; \
    175 		cp -f $(CP_ARGS) -v $(IMPORTFILES) $(APPSOURCEDIR)/common/; \
    176 	fi \
    177 
    178 # zip .png files without compression
    179 # do not zip up Makefiles, or any files ending with '~'
    180 	@echo "  >> creating application zip $(APP_ZIP_FILE)"
    181 	@if [ -d $(SOURCEDIR) ]; then \
    182 		(zip -0 -r "$(APP_ZIP_FILE)" . -i \*.png $(ZIP_EXCLUDE)); \
    183 		(zip -9 -r "$(APP_ZIP_FILE)" . -x \*~ -x \*.png -x Makefile $(ZIP_EXCLUDE)); \
    184 	else \
    185 		echo "Source for $(APPNAME) not found at $(SOURCEDIR)"; \
    186 	fi
    187 
    188 	@if [ "$(IMPORTCLEANUP)" ]; then \
    189 		echo "  >> deleting imports";\
    190 		rm -r -f $(APPSOURCEDIR)/common; \
    191 	fi \
    192 
    193 	@echo "*** packaging $(APPNAME) complete ***"
    194 
    195 # If DISTDIR is not empty then copy the zip package to the DISTDIR.
    196 # Note that this is used by the firmware build, to build applications that are
    197 # embedded in the firmware software image, such as the built-in screensaver.
    198 # For those cases, the Netflix/Makefile calls this makefile for each app
    199 # with DISTDIR and DISTZIP set to the target directory and base filename
    200 # respectively.
    201 	@if [ $(DISTDIR) ]; then \
    202 		rm -f $(DISTDIR)/$(DISTZIP).zip; \
    203 		mkdir -p $(DISTDIR); \
    204 		cp -f --preserve=ownership,timestamps --no-preserve=mode \
    205 			$(APP_ZIP_FILE) $(DISTDIR)/$(DISTZIP).zip; \
    206 	fi
    207 
    208 # -------------------------------------------------------------------------
    209 # clean: remove any build output for the app.
    210 # -------------------------------------------------------------------------
    211 .PHONY: clean
    212 clean:
    213 	rm -f $(APP_ZIP_FILE)
    214 # FIXME: we should use a canonical output file name, rather than having
    215 # the date-time stamp in the output file name.
    216 #	rm -f $(APP_PKG_FILE)
    217 	rm -f $(PKGREL)/$(APPNAME)_*.pkg
    218 
    219 # -------------------------------------------------------------------------
    220 # clobber: remove any build output for the app.
    221 # -------------------------------------------------------------------------
    222 .PHONY: clobber
    223 clobber: clean
    224 
    225 # -------------------------------------------------------------------------
    226 # dist-clean: remove the dist directory for the sandbox.
    227 # -------------------------------------------------------------------------
    228 .PHONY: dist-clean
    229 dist-clean:
    230 	rm -rf $(DISTREL)/*
    231 
    232 # -------------------------------------------------------------------------
    233 # CHECK_OPTIONS: this is used to specify configurable options, such
    234 # as which version of the BrightScript library sources should be used
    235 # to compile the app.
    236 # -------------------------------------------------------------------------
    237 CHECK_OPTIONS =
    238 ifneq (,$(wildcard $(BRIGHTSCRIPT_LIBS_DIR)/.))
    239 CHECK_OPTIONS += -lib $(BRIGHTSCRIPT_LIBS_DIR)
    240 endif
    241 
    242 # -------------------------------------------------------------------------
    243 # check: run the desktop BrightScript compiler/check tool on the
    244 # application.
    245 # You can bypass checking on the application by setting
    246 # APP_CHECK_DISABLED=true in the app's Makefile or in the environment.
    247 # -------------------------------------------------------------------------
    248 .PHONY: check
    249 check: $(APPNAME)
    250 ifeq ($(APP_CHECK_DISABLED),true)
    251 ifeq ($(IS_TEAMCITY_BUILD),true)
    252 	@echo "*** Warning: application check skipped ***"
    253 endif
    254 else
    255 ifeq ($(wildcard $(BRIGHTSCRIPT_TOOL)),)
    256 	@echo "*** Note: application check not available ***"
    257 else
    258 	@echo "*** Checking application ***"
    259 	rm -rf $(CHECK_TMP_DIR)
    260 	mkdir -p $(CHECK_TMP_DIR)
    261 	unzip -q $(APP_ZIP_FILE) -d $(CHECK_TMP_DIR)
    262 	$(BRIGHTSCRIPT_TOOL) check \
    263 		$(CHECK_OPTIONS) \
    264 		$(CHECK_TMP_DIR)
    265 	rm -rf $(CHECK_TMP_DIR)
    266 endif
    267 endif
    268 
    269 # -------------------------------------------------------------------------
    270 # check-strict: run the desktop BrightScript compiler/check tool on the
    271 # application using strict mode.
    272 # -------------------------------------------------------------------------
    273 .PHONY: check-strict
    274 check-strict: $(APPNAME)
    275 	@echo "*** Checking application (strict) ***"
    276 	rm -rf $(CHECK_TMP_DIR)
    277 	mkdir -p $(CHECK_TMP_DIR)
    278 	unzip -q $(APP_ZIP_FILE) -d $(CHECK_TMP_DIR)
    279 	$(BRIGHTSCRIPT_TOOL) check -strict \
    280 		$(CHECK_OPTIONS) \
    281 		$(CHECK_TMP_DIR)
    282 	rm -rf $(CHECK_TMP_DIR)
    283 
    284 # -------------------------------------------------------------------------
    285 # GET_FRIENDLY_NAME_FROM_DD is used to extract the Roku device ID
    286 # from the ECP device description XML response.
    287 # -------------------------------------------------------------------------
    288 define GET_FRIENDLY_NAME_FROM_DD
    289 	cat $(DEV_SERVER_TMP_FILE) | \
    290 		grep -o "<friendlyName>.*</friendlyName>" | \
    291 		sed "s|<friendlyName>||" | \
    292 		sed "s|</friendlyName>||"
    293 endef
    294 
    295 # -------------------------------------------------------------------------
    296 # CHECK_ROKU_DEV_TARGET is used to check if ROKU_DEV_TARGET refers a
    297 # Roku device on the network that has an enabled developer web server.
    298 # If the target doesn't exist or doesn't have an enabled web server
    299 # the connection should fail.
    300 # -------------------------------------------------------------------------
    301 define CHECK_ROKU_DEV_TARGET
    302 	if [ -z "$(ROKU_DEV_TARGET)" ]; then \
    303 		echo "ERROR: ROKU_DEV_TARGET is not set."; \
    304 		exit 1; \
    305 	fi
    306 	echo "Checking dev server at $(ROKU_DEV_TARGET)..."
    307 
    308 	# first check if the device is on the network via a quick ping
    309 	ping $(QUICK_PING_ARGS) $(ROKU_DEV_TARGET) &> $(DEV_SERVER_TMP_FILE) || \
    310 		( \
    311 			echo "ERROR: Device is not responding to ping."; \
    312 			exit 1 \
    313 		)
    314 
    315 	# second check ECP, to verify we are talking to a Roku
    316 	rm -f $(DEV_SERVER_TMP_FILE)
    317 	curl --connect-timeout 2 --silent --output $(DEV_SERVER_TMP_FILE) \
    318 		http://$(ROKU_DEV_TARGET):8060 || \
    319 		( \
    320 			echo "ERROR: Device is not responding to ECP...is it a Roku?"; \
    321 			exit 1 \
    322 		)
    323 
    324 	# echo the device friendly name to let us know what we are talking to
    325 	ROKU_DEV_NAME=`$(GET_FRIENDLY_NAME_FROM_DD)`; \
    326 	echo "Device reports as \"$$ROKU_DEV_NAME\"."
    327 
    328 	# third check dev web server.
    329 	# Note, it should return 401 Unauthorized since we aren't passing the password.
    330 	rm -f $(DEV_SERVER_TMP_FILE)
    331 	HTTP_STATUS=`curl --connect-timeout 2 --silent --output $(DEV_SERVER_TMP_FILE) \
    332 		http://$(ROKU_DEV_TARGET)` || \
    333 		( \
    334 			echo "ERROR: Device server is not responding...is the developer installer enabled?"; \
    335 			exit 1 \
    336 		)
    337 
    338 	echo "Dev server is ready."
    339 endef
    340 
    341 # -------------------------------------------------------------------------
    342 # CHECK_DEVICE_HTTP_STATUS is used to that the last curl command
    343 # to the dev web server returned HTTP 200 OK.
    344 # -------------------------------------------------------------------------
    345 define CHECK_DEVICE_HTTP_STATUS
    346 	if [ "$$HTTP_STATUS" != "200" ]; then \
    347 		echo "ERROR: Device returned HTTP $$HTTP_STATUS"; \
    348 		exit 1; \
    349 	fi
    350 endef
    351 
    352 # -------------------------------------------------------------------------
    353 # GET_PLUGIN_PAGE_RESULT_STATUS is used to extract the status message
    354 # (e.g. Success/Failed) from the dev server plugin_* web page response.
    355 # (Note that the plugin_install web page has two fields, whereas the
    356 # plugin_package web page just has one).
    357 # -------------------------------------------------------------------------
    358 define GET_PLUGIN_PAGE_RESULT_STATUS
    359 	cat $(DEV_SERVER_TMP_FILE) | \
    360 		grep -o "<font color=\"red\">.*" | \
    361 		sed "s|<font color=\"red\">||" | \
    362 		sed "s|</font>||"
    363 endef
    364 
    365 # -------------------------------------------------------------------------
    366 # GET_PLUGIN_PAGE_PACKAGE_LINK is used to extract the installed package
    367 # URL from the dev server plugin_package web page response.
    368 # -------------------------------------------------------------------------
    369 define GET_PLUGIN_PAGE_PACKAGE_LINK =
    370 	cat $(DEV_SERVER_TMP_FILE) | \
    371 		grep -o "<a href=\"pkgs//[^\"]*\"" | \
    372 		sed "s|<a href=\"pkgs//||" | \
    373 		sed "s|\"||"
    374 endef
    375 
    376 # -------------------------------------------------------------------------
    377 # install: install the app as the dev channel on the Roku target device.
    378 # -------------------------------------------------------------------------
    379 .PHONY: install
    380 install: $(APPNAME) check
    381 	@$(CHECK_ROKU_DEV_TARGET)
    382 
    383 	@echo "Installing $(APPNAME)..."
    384 	@rm -f $(DEV_SERVER_TMP_FILE)
    385 	@HTTP_STATUS=`curl --user $(USERPASS) --digest --silent --show-error \
    386 		-F "mysubmit=Install" -F "archive=@$(APP_ZIP_FILE)" \
    387 		--output $(DEV_SERVER_TMP_FILE) \
    388 		--write-out "%{http_code}" \
    389 		http://$(ROKU_DEV_TARGET)/plugin_install`; \
    390 	$(CHECK_DEVICE_HTTP_STATUS)
    391 
    392 	@MSG=`$(GET_PLUGIN_PAGE_RESULT_STATUS)`; \
    393 	echo "Result: $$MSG"
    394 
    395 # -------------------------------------------------------------------------
    396 # remove: uninstall the dev channel from the Roku target device.
    397 # -------------------------------------------------------------------------
    398 .PHONY: remove
    399 remove:
    400 	@$(CHECK_ROKU_DEV_TARGET)
    401 
    402 	@echo "Removing dev app..."
    403 	@rm -f $(DEV_SERVER_TMP_FILE)
    404 	@HTTP_STATUS=`curl --user $(USERPASS) --digest --silent --show-error \
    405 		-F "mysubmit=Delete" -F "archive=" \
    406 		--output $(DEV_SERVER_TMP_FILE) \
    407 		--write-out "%{http_code}" \
    408 		http://$(ROKU_DEV_TARGET)/plugin_install`; \
    409 	$(CHECK_DEVICE_HTTP_STATUS)
    410 
    411 	@MSG=`$(GET_PLUGIN_PAGE_RESULT_STATUS)`; \
    412 	echo "Result: $$MSG"
    413 
    414 # -------------------------------------------------------------------------
    415 # check-roku-dev-target: check the status of the Roku target device.
    416 # -------------------------------------------------------------------------
    417 .PHONY: check-roku-dev-target
    418 check-roku-dev-target:
    419 	@$(CHECK_ROKU_DEV_TARGET)
    420 
    421 # -------------------------------------------------------------------------
    422 # run: the install target is 'smart' and doesn't do anything if the package
    423 # didn't change.
    424 # But usually I want to run it even if it didn't change, so force a fresh
    425 # install by doing a remove first.
    426 # Some day we should look at doing the force run via a plugin_install flag,
    427 # but for now just brute force it.
    428 # -------------------------------------------------------------------------
    429 .PHONY: run
    430 run: remove install
    431 
    432 # -------------------------------------------------------------------------
    433 # pkg: use to create a pkg file from the application sources.
    434 #
    435 # Usage:
    436 # The application name should be specified via $APPNAME.
    437 # The application version should be specified via $VERSION.
    438 # The developer's signing password (from genkey) should be passed via
    439 # $APP_KEY_PASS, or via stdin, otherwise the script will prompt for it.
    440 # -------------------------------------------------------------------------
    441 .PHONY: pkg
    442 pkg: install
    443 	@echo "*** Creating Package ***"
    444 
    445 	@echo "  >> creating destination directory $(PKGREL)"
    446 	@if [ ! -d $(PKGREL) ]; then \
    447 		mkdir -p $(PKGREL); \
    448 	fi
    449 
    450 	@echo "  >> setting directory permissions for $(PKGREL)"
    451 	@if [ ! -w $(PKGREL) ]; then \
    452 		chmod 755 $(PKGREL); \
    453 	fi
    454 
    455 	@$(CHECK_ROKU_DEV_TARGET)
    456 
    457 	@echo "Packaging $(APP_NAME)/$(APP_VERSION) to $(APP_PKG_FILE)"
    458 
    459 	@if [ -z "$(APP_KEY_PASS)" ]; then \
    460 		read -r -p "Password: " REPLY; \
    461 		echo "$$REPLY" > $(APP_KEY_PASS_TMP); \
    462 	else \
    463 		echo "$(APP_KEY_PASS)" > $(APP_KEY_PASS_TMP); \
    464 	fi
    465 
    466 	@rm -f $(DEV_SERVER_TMP_FILE)
    467 	@PASSWD=`cat $(APP_KEY_PASS_TMP)`; \
    468 	PKG_TIME=`expr \`date +%s\` \* 1000`; \
    469 	HTTP_STATUS=`curl --user $(USERPASS) --digest --silent --show-error \
    470 		-F "mysubmit=Package" -F "app_name=$(APP_NAME)/$(APP_VERSION)" \
    471 		-F "passwd=$$PASSWD" -F "pkg_time=$$PKG_TIME" \
    472 		--output $(DEV_SERVER_TMP_FILE) \
    473 		--write-out "%{http_code}" \
    474 		http://$(ROKU_DEV_TARGET)/plugin_package`; \
    475 	$(CHECK_DEVICE_HTTP_STATUS)
    476 
    477 	@MSG=`$(GET_PLUGIN_PAGE_RESULT_STATUS)`; \
    478 	case "$$MSG" in \
    479 		*Success*) \
    480 			;; \
    481 		*)	echo "Result: $$MSG"; \
    482 			exit 1 \
    483 			;; \
    484 	esac
    485 
    486 	@PKG_LINK=`$(GET_PLUGIN_PAGE_PACKAGE_LINK)`; \
    487 	HTTP_STATUS=`curl --user $(USERPASS) --digest --silent --show-error \
    488 		--output $(APP_PKG_FILE) \
    489 		--write-out "%{http_code}" \
    490 		http://$(ROKU_DEV_TARGET)/pkgs/$$PKG_LINK`; \
    491 	$(CHECK_DEVICE_HTTP_STATUS)
    492 
    493 	@echo "*** Package $(APPNAME) complete ***"
    494 
    495 # -------------------------------------------------------------------------
    496 # app-pkg: use to create a pkg file from the application sources.
    497 # Similar to the pkg target, but does not require a player to do the signing.
    498 # Instead it requires the developer key file and signing password to be
    499 # specified, which are then passed to the app-package desktop tool to create
    500 # the package file.
    501 #
    502 # Usage:
    503 # The application name should be specified via $APPNAME.
    504 # The application version should be specified via $VERSION.
    505 # The developer's key file (.pkg file) should be specified via $APP_KEY_FILE.
    506 # The developer's signing password (from genkey) should be passed via
    507 # $APP_KEY_PASS, or via stdin, otherwise the script will prompt for it.
    508 # -------------------------------------------------------------------------
    509 .PHONY: app-pkg
    510 app-pkg: $(APPNAME) check
    511 	@echo "*** Creating package ***"
    512 
    513 	@echo "  >> creating destination directory $(PKGREL)"
    514 	@mkdir -p $(PKGREL) && chmod 755 $(PKGREL)
    515 
    516 	@if [ -z "$(APP_KEY_FILE)" ]; then \
    517 		echo "ERROR: APP_KEY_FILE not defined"; \
    518 		exit 1; \
    519 	fi
    520 	@if [ ! -f "$(APP_KEY_FILE)" ]; then \
    521 		echo "ERROR: key file not found: $(APP_KEY_FILE)"; \
    522 		exit 1; \
    523 	fi
    524 
    525 	@if [ -z "$(APP_KEY_PASS)" ]; then \
    526 		read -r -p "Password: " REPLY; \
    527 		echo "$$REPLY" > $(APP_KEY_PASS_TMP); \
    528 	else \
    529 		echo "$(APP_KEY_PASS)" > $(APP_KEY_PASS_TMP); \
    530 	fi
    531 
    532 	@echo "Packaging $(APP_NAME)/$(APP_VERSION) to $(APP_PKG_FILE)"
    533 
    534 	@if [ -z "$(APP_VERSION)" ]; then \
    535 		echo "WARNING: VERSION is not set."; \
    536 	fi
    537 
    538 	@PASSWD=`cat $(APP_KEY_PASS_TMP)`; \
    539 	$(APP_PACKAGE_TOOL) package $(APP_ZIP_FILE) \
    540 		-n $(APP_NAME)/$(APP_VERSION) \
    541 		-k $(APP_KEY_FILE) \
    542 		-p "$$PASSWD" \
    543 		-o $(APP_PKG_FILE)
    544 
    545 	@rm $(APP_KEY_PASS_TMP)
    546 
    547 	@echo "*** Package $(APPNAME) complete ***"
    548 
    549 # -------------------------------------------------------------------------
    550 # teamcity: used to build .zip and .pkg file on TeamCity.
    551 # See app-pkg target for info on options for specifying the signing password.
    552 # -------------------------------------------------------------------------
    553 .PHONY: teamcity
    554 teamcity: app-pkg
    555 ifeq ($(IS_TEAMCITY_BUILD),true)
    556 	@echo "Adding TeamCity artifacts..."
    557 
    558 	sudo rm -f /tmp/artifacts
    559 	sudo mkdir -p /tmp/artifacts
    560 
    561 	cp $(APP_ZIP_FILE) /tmp/artifacts/$(APP_NAME)-$(APP_VERSION).zip
    562 	@echo "##teamcity[publishArtifacts '/tmp/artifacts/$(APP_NAME)-$(APP_VERSION).zip']"
    563 
    564 	cp $(APP_PKG_FILE) /tmp/artifacts/$(APP_NAME)-$(APP_VERSION).pkg
    565 	@echo "##teamcity[publishArtifacts '/tmp/artifacts/$(APP_NAME)-$(APP_VERSION).pkg']"
    566 
    567 	@echo "TeamCity artifacts complete."
    568 else
    569 	@echo "Not running on TeamCity, skipping artifacts."
    570 endif
    571 
    572 ##########################################################################
    573 
    574 # -------------------------------------------------------------------------
    575 # CHECK_NATIVE_TARGET is used to check if the Roku simulator is
    576 # configured.
    577 # -------------------------------------------------------------------------
    578 define CHECK_NATIVE_TARGET
    579 	if [ -z "$(ROKU_NATIVE_DEV)" ]; then \
    580 		echo "ERROR: ROKU_NATIVE_DEV not defined"; \
    581 		exit 1; \
    582 	i
    583 	if [ ! -d "$(ROKU_NATIVE_DEV)" ]; then \
    584 		echo "ERROR: native dev dir not found: $(ROKU_NATIVE_DEV)"; \
    585 		exit 1; \
    586 	fi
    587 	if [ ! -d "$(NATIVE_DIST_DIR)" ]; then \
    588 		echo "ERROR: native build dir not found: $(NATIVE_DIST_DIR)"; \
    589 		exit 1; \
    590 	fi
    591 endef
    592 
    593 # -------------------------------------------------------------------------
    594 # install-native: install the app as the dev channel on the Roku simulator.
    595 # -------------------------------------------------------------------------
    596 .PHONY: install-native
    597 install-native: $(APPNAME) check
    598 	@$(CHECK_NATIVE_TARGET)
    599 	@echo "Installing $(APPNAME) to native."
    600 	@if [ ! -d "$(NATIVE_DEV_REL)" ]; then \
    601 		mkdir "$(NATIVE_DEV_REL)"; \
    602 	fi
    603 	@echo "Source is $(APP_ZIP_FILE)"
    604 	@echo "Target is $(NATIVE_DEV_PKG)"
    605 	@cp $(APP_ZIP_FILE) $(NATIVE_DEV_PKG)
    606 	@$(NATIVE_TICKLER)
    607 
    608 # -------------------------------------------------------------------------
    609 # remove-native: uninstall the dev channel from the Roku simulator.
    610 # -------------------------------------------------------------------------
    611 .PHONY: remove-native
    612 remove-native:
    613 	@$(CHECK_NATIVE_TARGET)
    614 	@echo "Removing $(APPNAME) from native."
    615 	@rm $(NATIVE_DEV_PKG)
    616 	@$(NATIVE_TICKLER)
    617 
    618 ##########################################################################
    619 
    620 # -------------------------------------------------------------------------
    621 # art-jpg-opt: compress any jpg files in the source tree.
    622 # Used by the art-opt target.
    623 # -------------------------------------------------------------------------
    624 APPS_JPG_ART=`\find . -name "*.jpg"`
    625 
    626 .PHONY: art-jpg-opt
    627 art-jpg-opt:
    628 	p4 edit $(APPS_JPG_ART)
    629 	for i in $(APPS_JPG_ART); \
    630 	do \
    631 		TMPJ=`mktemp` || return 1; \
    632 		echo "optimizing $$i"; \
    633 		(jpegtran -copy none -optimize -outfile $$TMPJ $$i && mv -f $$TMPJ $$i &); \
    634 	done
    635 	wait
    636 	p4 revert -a $(APPS_JPG_ART)
    637 
    638 # -------------------------------------------------------------------------
    639 # art-png-opt: compress any png files in the source tree.
    640 # Used by the art-opt target.
    641 # -------------------------------------------------------------------------
    642 APPS_PNG_ART=`\find . -name "*.png"`
    643 
    644 .PHONY: art-png-opt
    645 art-png-opt:
    646 	p4 edit $(APPS_PNG_ART)
    647 	for i in $(APPS_PNG_ART); \
    648 	do \
    649 		(optipng -o7 $$i &); \
    650 	done
    651 	wait
    652 	p4 revert -a $(APPS_PNG_ART)
    653 
    654 # -------------------------------------------------------------------------
    655 # art-opt: compress any png and jpg files in the source tree using
    656 # lossless compression options.
    657 # This assumes a Perforce client/workspace is configured.
    658 # Modified files are opened for edit in the default changelist.
    659 # -------------------------------------------------------------------------
    660 .PHONY: art-opt
    661 art-opt: art-png-opt art-jpg-opt
    662 
    663 ##########################################################################
    664 
    665 # -------------------------------------------------------------------------
    666 # tr: this target is used to update translation files for an application
    667 # MAKE_TR_OPTIONS may be set to [-t] [-d] etc. in the external environment,
    668 # if needed.
    669 # -------------------------------------------------------------------------
    670 .PHONY: tr
    671 tr:
    672 	p4 opened -c default
    673 	p4 edit locale/.../translations.xml
    674 	$(MAKE_TR_TOOL) $(MAKE_TR_OPTIONS)
    675 	rm locale/en_US/translations.xml
    676 	p4 revert -a locale/.../translations.xml
    677 	p4 opened -c default
    678 
    679 ##########################################################################