spiegel-keyman/web/source/build.sh
2019-06-19 09:31:57 -06:00

437 lines
13 KiB
Bash
Executable file

#! /bin/bash
#
# Compile keymanweb and copy compiled javascript and resources to output/embedded folder
#
display_usage ( ) {
echo "build.sh [-ui | -test | -embed | -web | -debug_embedded] [-no_minify] [-clean]"
echo
echo " -ui to compile desktop user interface modules to output folder"
echo " -test to compile for testing without copying resources or"
echo " updating the saved version number."
echo " -embed to compile only the KMEA/KMEI embedded engine."
echo " -web to compile only the KeymanWeb engine."
echo " -debug_embedded to compile a readable version of the embedded KMEA/KMEI code"
echo " -no_minify to disable the minification '/release/' build sections -"
echo " the '/release/unminified' subfolders will still be built."
echo " -clean to erase pre-existing build products before the build."
echo ""
echo " If more than one target is specified, the last one will take precedence."
exit 1
}
# Fails the build if a specified file does not exist.
assert ( ) {
if ! [ -f $1 ]; then
fail "Build failed."
exit 1
fi
}
fail() {
FAILURE_MSG="$1"
if [[ "$FAILURE_MSG" == "" ]]; then
FAILURE_MSG="Unknown failure"
fi
echo "${ERROR_RED}$FAILURE_MSG${NORMAL}"
exit 1
}
# Build products for each main target.
WEB_TARGET=( "keymanweb.js" )
UI_TARGET=( "kmwuibutton.js" "kmwuifloat.js" "kmwuitoggle.js" "kmwuitoolbar.js" )
EMBED_TARGET=( "keyman.js" )
# Ensure the dependencies are downloaded. --no-optional should help block fsevents warnings.
echo "Node.js + dependencies check"
npm install --no-optional
# Variables for the LMLayer
PREDICTIVE_TEXT_SOURCE="../../common/predictive-text/unit_tests/in_browser/resources/models/simple-trie.js"
PREDICTIVE_TEXT_OUTPUT="../testing/prediction-ui/simple-en-trie.js"
# Ensure that the LMLayer compiles properly, readying the build product for comsumption by KMW.
cd ../../common/predictive-text/
echo ""
echo "Compiling the Language Modeling layer module..."
./build.sh || fail "Failed to compile the language modeling layer module."
cd ../../web/source
echo "Copying ${PREDICTIVE_TEXT_SOURCE} to ${PREDICTIVE_TEXT_OUTPUT}"
cp "${PREDICTIVE_TEXT_SOURCE}" "${PREDICTIVE_TEXT_OUTPUT}" || fail "Failed to copy predictive text model"
echo "Language Modeling layer compilation successful."
echo ""
if [ $? -ne 0 ]; then
fail "Build environment setup error detected! Please ensure Node.js is installed!"
fi
: ${CLOSURECOMPILERPATH:=../node_modules/google-closure-compiler}
: ${JAVA:=java}
minifier="$CLOSURECOMPILERPATH/compiler.jar"
# We'd love to add the argument --source_map_include_content for distribution in the future,
# but Closure doesn't include the TS sources properly at this time.
#
# `checkTypes` is blocked b/c TypeScript can perform our type checking... and it causes an error
# with TypeScript's `extend` implementation (it doesn't recognize a constructor without manual edits).
# We also get a global `this` warning from the same.
#
# `checkVars` is blocked b/c Closure will otherwise fail on TypeScript namespacing, as each original TS
# source file will redeclare the namespace variable, despite being merged into a single file post-compilation.
#
# `jsDocMissingType` prevents errors on type documentation Closure thinks is missing. TypeScript may not
# have the same requirements, and we trust TypeScript over Closure.
minifier_warnings="--jscomp_error=* --jscomp_off=lintChecks --jscomp_off=unusedLocalVariables --jscomp_off=globalThis --jscomp_off=checkTypes --jscomp_off=checkVars --jscomp_off=jsdocMissingType"
minifycmd="$JAVA -jar $minifier --compilation_level WHITESPACE_ONLY $minifier_warnings --generate_exports"
if ! [ -f $minifier ];
then
echo File $minifier does not exist: have you set the environment variable \$CLOSURECOMPILERPATH?
exit 1
fi
readonly minifier
readonly minifycmd
# $1 - base file name
# $2 - output path
# $3 - optimization level
# $4 - defines
# $5 - additional output wrapper
minify ( ) {
if [ "$4" ]; then
defines="--define $4"
else
defines=
fi
if [ "$5" ]; then
wrapper=$5
else
wrapper="%output%"
fi
$minifycmd $defines --source_map_input "$INTERMEDIATE/$1|$INTERMEDIATE/$1.map" \
--create_source_map $2/$1.map --js $INTERMEDIATE/$1 --compilation_level $3 \
--js_output_file $2/$1 --warning_level VERBOSE --output_wrapper "$wrapper
//# sourceMappingURL=$1.map"
}
# $1 - target (WEB, EMBEDDED)
# $2+ - build target array (one of WEB_TARGET, FULL_WEB_TARGET, or EMBED_TARGET)
finish_nominify ( ) {
args=("$@")
if [ $1 = $WEB ] || [ $1 = $UI ]; then
dest=$WEB_OUTPUT_NO_MINI
resourceDest=$dest
else
dest=$EMBED_OUTPUT_NO_MINI
resourceDest=$dest/resources
fi
# Create our entire embedded compilation results path.
if ! [ -d $dest ]; then
mkdir -p "$dest" # Includes base folder, is recursive.
fi
echo "Copying unminified $1 build products to $dest."
for (( n=1; n<$#; n++ )) # Apparently, args ends up zero-based, meaning $2 => n=1.
do
target=${args[$n]}
cp -f $INTERMEDIATE/$target $dest/$target
cp -f $INTERMEDIATE/$target.map $dest/$target.map
done
copy_resources $resourceDest
}
copy_resources ( ) {
echo
echo Copy resources to $1/ui, .../osk
# Create our entire compilation results path. Can't one-line them due to shell-script parsing errors.
if ! [ -d $1/ui ]; then
mkdir -p "$1/ui"
fi
if ! [ -d $1/osk ]; then
mkdir -p "$1/osk"
fi
if ! [ -d $1/src/ui ]; then
mkdir -p "$1/src/ui"
fi
if ! [ -d $1/src/osk ]; then
mkdir -p "$1/src/osk"
fi
cp -Rf $SOURCE/resources/ui $1/ >/dev/null
cp -Rf $SOURCE/resources/osk $1/ >/dev/null
echo Copy source to $1/src
cp -Rf $SOURCE/*.js $1/src
cp -Rf $SOURCE/*.ts $1/src
echo $BUILD > $1/src/version.txt
# Remove KMW Recorder source.
rm -f $1/src/recorder_*.ts
rm -f $1/src/recorder_*.js
cp -Rf $SOURCE/resources/ui $1/src/ >/dev/null
cp -Rf $SOURCE/resources/osk $1/src/ >/dev/null
# Update build number if successful
echo
echo KeymanWeb resources saved under $1
echo
}
clean ( ) {
rm -rf "../release"
rm -rf "../intermediate"
}
# Definition of global compile constants
UI="ui"
WEB="web"
EMBEDDED="embedded"
WEB_OUTPUT="../release/web"
EMBED_OUTPUT="../release/embedded"
WEB_OUTPUT_NO_MINI="../release/unminified/web"
EMBED_OUTPUT_NO_MINI="../release/unminified/embedded"
INTERMEDIATE="../intermediate"
SOURCE="."
NODE_SOURCE="source"
ENVIRONMENT_FILE="environment.inc.ts"
VERSION=`cat ../../resources/VERSION.md`
readonly WEB_OUTPUT
readonly EMBED_OUTPUT
readonly SOURCE
# Get build version -- if not building in TeamCity, then always use 300
: ${BUILD_COUNTER:=300}
BUILD=$BUILD_COUNTER
readonly BUILD
# Ensures that we rely first upon the local npm-based install of Typescript.
# (Facilitates automated setup for build agents.)
PATH="../node_modules/.bin:$PATH"
compiler="npm run tsc --"
compilecmd="$compiler"
# Establish default build parameters
set_default_vars ( ) {
BUILD_UI=true
BUILD_EMBED=true
BUILD_FULLWEB=true
BUILD_DEBUG_EMBED=false
BUILD_COREWEB=true
DO_MINIFY=true
}
if [[ $# = 0 ]]; then
FULL_BUILD=true
else
FULL_BUILD=false
fi
set_default_vars
# Parse args
while [[ $# -gt 0 ]] ; do
key="$1"
case $key in
-ui)
set_default_vars
BUILD_EMBED=false
BUILD_FULLWEB=false
BUILD_COREWEB=false
;;
-test)
set_default_vars
BUILD_TEST=true
BUILD_UI=false
BUILD_EMBED=false
BUILD_FULLWEB=false
;;
-embed)
set_default_vars
BUILD_FULLWEB=false
BUILD_UI=false
BUILD_COREWEB=false
;;
-web)
set_default_vars
BUILD_EMBED=false
;;
-debug_embedded)
set_default_vars
BUILD_EMBED=true
BUILD_UI=false
BUILD_COREWEB=false
BUILD_FULLWEB=false
BUILD_DEBUG_EMBED=true
;;
-h|-?)
display_usage
;;
-no_minify)
DO_MINIFY=false
;;
-clean)
clean
;;
esac
shift # past argument
done
readonly BUILD_UI
readonly BUILD_EMBED
readonly BUILD_FULLWEB
readonly BUILD_DEBUG_EMBED
readonly BUILD_COREWEB
readonly DO_MINIFY
generate_environment_ts_file ( ) {
if [ -f $ENVIRONMENT_FILE ];
then
rm $ENVIRONMENT_FILE
fi
echo "//Autogenerated file - do not modify!
namespace com.keyman.environment {
export var VERSION = \"$VERSION\";
}
" >> $ENVIRONMENT_FILE
}
generate_environment_ts_file
if [ $FULL_BUILD = true ]; then
echo Compiling build $BUILD
echo ""
fi
if [ $BUILD_EMBED = true ]; then
echo Compile KMEI/KMEA build $BUILD
$compilecmd -p $NODE_SOURCE/tsconfig.embedded.json
if [ $? -ne 0 ]; then
fail "Typescript compilation failed."
fi
assert $INTERMEDIATE/keyman.js
echo Embedded TypeScript compiled as $INTERMEDIATE/keyman.js
copy_resources "$INTERMEDIATE" # Very useful for local testing.
finish_nominify $EMBEDDED $EMBED_TARGET
if [ $DO_MINIFY = true ]; then
# Create our entire embedded compilation results path.
if ! [ -d $EMBED_OUTPUT/resources ]; then
mkdir -p "$EMBED_OUTPUT/resources" # Includes base folder, is recursive.
fi
rm $EMBED_OUTPUT/keyman.js 2>/dev/null
minify keyman.js $EMBED_OUTPUT SIMPLE_OPTIMIZATIONS "KeymanBase.__BUILD__=$BUILD"
assert $EMBED_OUTPUT/keyman.js
echo Compiled embedded application saved as $EMBED_OUTPUT/keyman.js
# Update any changed resources
# echo Copy or update resources
copy_resources "$EMBED_OUTPUT/resources"
# Update build number if successful
echo
echo KMEA/KMEI build $BUILD compiled and saved under $EMBED_OUTPUT
echo
fi
fi
if [ $BUILD_COREWEB = true ]; then
# Compile KeymanWeb code modules for native keymanweb use, stubbing out and removing references to debug functions
echo Compile Keymanweb...
$compilecmd -p $NODE_SOURCE/tsconfig.web.json
if [ $? -ne 0 ]; then
fail "Typescript compilation failed."
fi
assert $INTERMEDIATE/keymanweb.js
echo Native TypeScript compiled as $INTERMEDIATE/keymanweb.js
copy_resources "$INTERMEDIATE"
finish_nominify $WEB $WEB_TARGET
if [ $DO_MINIFY = true ]; then
rm $WEB_OUTPUT/keymanweb.js 2>/dev/null
echo Minifying KeymanWeb...
minify keymanweb.js $WEB_OUTPUT SIMPLE_OPTIMIZATIONS "KeymanBase.__BUILD__=$BUILD"
assert $WEB_OUTPUT/keymanweb.js
echo Compiled KeymanWeb application saved as $WEB_OUTPUT/keymanweb.js
fi
fi
if [ $BUILD_FULLWEB = true ] && [ $DO_MINIFY = true ]; then
copy_resources "$WEB_OUTPUT"
# Update build number if successful
echo
echo KeymanWeb $VERSION build $BUILD compiled and saved under $WEB_OUTPUT
echo
fi
if [ $BUILD_UI = true ]; then
echo Compile UI Modules...
$compilecmd -p $NODE_SOURCE/tsconfig.ui.json
assert $INTERMEDIATE/kmwuitoolbar.js
assert $INTERMEDIATE/kmwuitoggle.js
assert $INTERMEDIATE/kmwuifloat.js
assert $INTERMEDIATE/kmwuibutton.js
finish_nominify $UI "${UI_TARGET[@]}"
echo \'Native\' UI TypeScript has been compiled into the $INTERMEDIATE/ folder
if [ $DO_MINIFY = true ]; then
echo Minify ToolBar UI
del $WEB_OUTPUT/kmuitoolbar.js 2>/dev/null
minify kmwuitoolbar.js $WEB_OUTPUT ADVANCED_OPTIMIZATIONS "" "(function() {%output%}());"
assert $WEB_OUTPUT/kmwuitoolbar.js
echo Minify Toggle UI
del $WEB_OUTPUT/kmuitoggle.js 2>/dev/null
minify kmwuitoggle.js $WEB_OUTPUT SIMPLE_OPTIMIZATIONS "" "(function() {%output%}());"
assert $WEB_OUTPUT/kmwuitoggle.js
echo Minify Float UI
del $WEB_OUTPUT/kmuifloat.js 2>/dev/null
minify kmwuifloat.js $WEB_OUTPUT ADVANCED_OPTIMIZATIONS "" "(function() {%output%}());"
assert $WEB_OUTPUT/kmwuifloat.js
echo Minify Button UI
del $WEB_OUTPUT/kmuibutton.js 2>/dev/null
minify kmwuibutton.js $WEB_OUTPUT SIMPLE_OPTIMIZATIONS "" "(function() {%output%}());"
assert $WEB_OUTPUT/kmwuibutton.js
echo "User interface modules compiled and saved under $WEB_OUTPUT"
fi
fi
if [ $BUILD_DEBUG_EMBED = true ]; then
# We currently have an issue with sourcemaps for minified versions.
# We should use the unminified one instead for now.
cp $EMBED_OUTPUT_NO_MINI/keyman.js $EMBED_OUTPUT/keyman.js
# Copy the sourcemap.
cp $EMBED_OUTPUT_NO_MINI/keyman.js.map $EMBED_OUTPUT/keyman.js.map
echo Uncompiled embedded application saved as keyman.js
fi