blob: 33e6b777d574e696dfc2290ff39da8aeca95d26d [file] [log] [blame]
SHELL := /bin/bash -euo pipefail
PATH := node_modules/.bin:$(PATH)
MDRIP ?= $(JIRI_ROOT)/third_party/go/bin/mdrip
.DELETE_ON_ERROR:
.DEFAULT_GOAL := all
#############################################################################
# A note about debugging this Makefile
#
# Due to the way testing is managed there is a somewhat complex set of tasks
# and dependencies which can be hard to get a sense of by looking at the
# definitions in this Makefile. Additionally, targets for creating and testing
# shell scripts from tutorial content can take a while to run. Some tips are
# below to help anyone who might need to make edits or additions.
#
# Run a task with make's debug output. This will show information about the
# target being run as well as it's prerequisites and whether make will rebuild
# the target.
#
# make <target> --debug
#
# Force the target and all prerequisites to build regardless of mtimes:
#
# make <target> --always-make
#
# Do a dry run, this will spit out what will happen without actually building
# the targets. This is probably helpful for creating new targets with
# complex and/or slow prerequisites.
#
# make <target> --dry-run
#
#############################################################################
# Tooling and infrastructure
# Add node and npm to PATH. Note, we run npm using 'node npm' to avoid relying
# on the shebang line in the npm script, which can exceed the Linux shebang
# length limit on Jenkins.
NODE_DIR := $(shell jiri v23-profile list --info Target.InstallationDir nodejs)
# Once the JS tutorials stop running npm, we can simplify this to setting
# npm := node $(NODE_DIR)/bin/npm and using $(npm) in place of npm elsewhere
# in this file.
NPM_DIR := $(shell mktemp -d "/tmp/XXXXXX")
export PATH := $(NPM_DIR):$(NODE_DIR)/bin:$(PATH)
# SEE: https://www.gnu.org/software/make/manual/html_node/Chained-Rules.html
npm = $(NPM_DIR)/npm
.INTERMEDIATE: $(npm)
$(npm):
echo 'node $(NODE_DIR)/bin/npm "$$@"' > $(npm)
chmod +x $(npm)
# mdrip is a tool for extracting shell scripts from any markdown content which
# might have code blocks in it (like the tutorials). The mdrip tool is also
# capable of running the extracted code in a subshell, simulating a user
# stepping through the tutorials in a step by step fashion.
$(MDRIP):
jiri go install github.com/monopole/mdrip
#############################################################################
# Variables, functions, and helpers
TMPDIR := $(shell mktemp -d "/tmp/XXXXXX")
HEAD := $(shell git rev-parse HEAD)
bundles := public/css/bundle.css public/js/bundle.js
haiku_inputs := $(shell find public/* content/* templates/*)
# A list of case-sensitive banned words.
BANNED_WORDS := Javascript node.js Oauth
.PHONY: banned_words
banned_words:
@for WORD in $(BANNED_WORDS); do \
if [ -n '`grep -rn "$$WORD" content templates`' ]; then \
echo '`grep -rn "$$WORD" content templates`'; \
echo "Found banned word (case-sensitive): $$WORD"; \
exit 1; \
fi \
done
define BROWSERIFY
@mkdir -p $(dir $2)
browserify $1 -d -o $2
endef
#############################################################################
# Variables, functions, and helpers
#
# It's important these are defined above any targets that may depend on them.
install_md = installation/step-by-step.md
install_sh = public/sh/vanadium-install.sh
tutSetup = tutorials/setup
tutCheckup = tutorials/checkup
tutCleanup = tutorials/cleanup
tutWipeSlate = tutorials/wipe-slate
tutHello = tutorials/hello-world
tutBasics = tutorials/basics
tutPrincipals = tutorials/security/principals-and-blessings
tutPermsAuth = tutorials/security/permissions-authorizer
tutCaveats1st = tutorials/security/first-party-caveats
tutCaveats3rd = tutorials/security/third-party-caveats
tutAgent = tutorials/security/agent
tutCustomAuth = tutorials/security/custom-authorizer
tutMountTable = tutorials/naming/mount-table
tutNamespace = tutorials/naming/namespace
tutSuffixPart1 = tutorials/naming/suffix-part1
tutSuffixPart2 = tutorials/naming/suffix-part2
tutGlobber = tutorials/naming/globber
tutJSHello = tutorials/javascript/hellopeer
tutJSFortune = tutorials/javascript/fortune
tutJavaAndroid = tutorials/java/android
tutJavaFortune = tutorials/java/fortune
# Scripts that 'complete' the named tutorials, creating all relevant files
# (code, credentials, etc.) but skipping ephemeral steps like starting servers,
# running clients, etc. Such scripts need exist only for tutorials that create
# such files.
completer = public/sh/tut-completer
completerScripts = \
$(completer)-hello-world.sh \
$(completer)-basics.sh \
$(completer)-permissions-authorizer.sh \
$(completer)-custom-authorizer.sh \
$(completer)-suffix-part1.sh \
$(completer)-suffix-part2.sh \
$(completer)-globber.sh \
$(completer)-js-hellopeer.sh \
$(completer)-js-fortune.sh
# Opaquely named copies of particular completer scripts, used to set up
# conditions for later tutorials. See individual targets for more explanation.
scenario = public/sh/scenario
setupScripts = \
$(install_sh) \
$(scenario)-a-setup.sh \
$(scenario)-b-setup.sh \
$(scenario)-c-setup.sh \
$(scenario)-d-setup.sh \
$(scenario)-e-setup.sh \
$(scenario)-f-setup.sh
depsCommon = \
content/$(tutSetup).md \
content/$(tutCheckup).md \
content/$(tutWipeSlate).md
# This target builds the hosted web assets for the JavaScript tutorials.
jsTutorialResults := public/tutorials/javascript/results
scripts := $(completerScripts) $(setupScripts) $(jsTutorialResults)
#############################################################################
# Target definitions
# Silence error output "make: `build' is up to date." for tools like watch by
# adding @true.
.PHONY: all
all: build
@true
node_modules: package.json | $(npm)
npm prune
npm install
touch $@
# NOTE(sadovsky): Some files under public/{css,js} were copied over from the
# node_modules directory as follows:
# cp node_modules/highlight.js/styles/github.css public/css
# cp node_modules/material-design-lite/material*css* public/css
# cp node_modules/material-design-lite/material*js* public/js
# NOTE(sadovsky): Newer versions of postcss-cli and autoprefixer use JavaScript
# Promises, which doesn't work with Vanadium's old version of node, 0.10.24.
public/css/bundle.css: $(shell find stylesheets/*) node_modules
lessc -sm=on stylesheets/index.less | postcss -u autoprefixer > $@
public/js/bundle.js: browser/index.js $(shell find browser) node_modules
$(call BROWSERIFY,$<,$@)
build: $(bundles) $(scripts) $(haiku_inputs) node_modules | $(MDRIP)
haiku build --helpers helpers.js --build-dir $@
@touch $@
################################################################################
# Task definitions, targets without build artifacts.
.PHONY: serve
serve: build
@static build -H '{"Cache-Control": "no-cache, must-revalidate"}'
# 'entr' can be installed on Debian/Ubuntu using 'apt-get install entr', and on
# OS X using 'brew install entr'.
.PHONY: watch
watch: browser/ content/ public/ stylesheets/ templates/
@echo "Watching for changes in $^"
@find $^ | entr $(MAKE) build
# TODO(sadovsky): Check that we're in a clean master branch. Also, automate
# deployment so that changes are picked up automatically.
.PHONY: deploy
deploy: clean build
git clone git@github.com:vanadium/vanadium.github.io.git $(TMPDIR)
rm -rf $(TMPDIR)/*
rsync -r build/* $(TMPDIR)
cd $(TMPDIR) && git add -A && git commit -m "pull $(HEAD)" && git push
.PHONY: clean
clean:
rm -rf build node_modules public/**/bundle.* public/sh public/tutorials
.PHONY: lint banned_words
lint: banned_words node_modules
jshint .
################################################################################
# Tutorial script generation and tests
# Vanadium install script.
# This can be run as a prerequisite for tutorial setup.
$(install_sh): content/$(install_md) | $(MDRIP)
mkdir -p $(@D)
$(MDRIP) --preambled 3 test $^ > $@
# Targets of the form $(scenario)-{x}-setup.sh create scripts that are meant to
# be run by a user as an argument to 'source', so that they modify the user's
# active environment. They are prerequisite to particular tutorials.
#
# Each script has two sections: a preamble that should run error-free, setting
# env vars and defining shell functions, and a general section that runs as a
# subshell, capable of exiting on error. Error exits from a subshell won't close
# the terminal that issued the 'source' command.
#
# The preamble section is generated from the contents of the first filename
# argument to "$(MDRIP) --preambled". The remaining arguments define the
# subshell code. Code to verify setup and exit if something went wrong should
# appear in the subshell, not in the preamble.
$(scenario)-a-setup.sh: \
content/$(tutSetup).md \
content/$(tutCheckup).md | $(MDRIP)
mkdir -p $(@D)
$(MDRIP) --preambled 0 completer $^ > $@
# Targets of the from test-{tutorial-name} are meant for interactive use to test
# an individual tutorial and/or extract the code associated with said tutorial.
# The code winds up in $V_TUT/src, where $V_TUT is defined in tutSetup.
depsHello = $(depsCommon) content/$(tutHello).md
.PHONY: test-hello-world
test-hello-world: $(depsHello) | $(MDRIP)
$(MDRIP) --subshell test $^
$(completer)-hello-world.sh: $(depsHello) | $(MDRIP)
mkdir -p $(@D)
$(MDRIP) --preambled 0 completer $^ > $@
depsBasics = $(depsCommon) content/$(tutBasics).md
.PHONY: test-basics
test-basics: $(depsBasics) | $(MDRIP)
$(MDRIP) --subshell test $^
$(completer)-basics.sh: $(depsBasics) | $(MDRIP)
mkdir -p $(@D)
$(MDRIP) --preambled 0 completer $^ > $@
$(scenario)-b-setup.sh: $(completer)-basics.sh
cp $^ $@
depsPrincipals = $(depsBasics) content/$(tutPrincipals).md
.PHONY: test-principals
test-principals: $(depsPrincipals) | $(MDRIP)
$(MDRIP) --subshell test $^
$(scenario)-c-setup.sh: $(depsPrincipals) | $(MDRIP)
mkdir -p $(@D)
$(MDRIP) --preambled 0 completer $^ > $@
depsPermsAuth = $(depsPrincipals) content/$(tutPermsAuth).md
.PHONY: test-permissions-authorizer
test-permissions-authorizer: $(depsPermsAuth) | $(MDRIP)
$(MDRIP) --subshell test $^
$(completer)-permissions-authorizer.sh: $(depsPermsAuth) | $(MDRIP)
mkdir -p $(@D)
$(MDRIP) --preambled 0 completer $^ > $@
$(scenario)-d-setup.sh: $(completer)-permissions-authorizer.sh
cp $^ $@
depsMultiDisp = $(depsPermsAuth) content/$(tutSuffixPart1).md
.PHONY: test-multiservice-dispatcher
test-multiservice-dispatcher: $(depsMultiDisp) | $(MDRIP)
$(MDRIP) --subshell test $^
$(completer)-multiservice-dispatcher.sh: $(depsMultiDisp) | $(MDRIP)
mkdir -p $(@D)
$(MDRIP) --preambled 0 completer $^ > $@
$(scenario)-f-setup.sh: $(completer)-multiservice-dispatcher.sh
cp $^ $@
depsCaveats1st = $(depsPermsAuth) content/$(tutCaveats1st).md
.PHONY: test-caveats-1st
test-caveats-1st: $(depsCaveats1st) | $(MDRIP)
$(MDRIP) --subshell test $^
depsCaveats3rd = $(depsPermsAuth) content/$(tutCaveats3rd).md
.PHONY: test-caveats-3rd
test-caveats-3rd: $(depsCaveats3rd) | $(MDRIP)
$(MDRIP) --subshell test $^
depsAgent = $(depsPermsAuth) content/$(tutAgent).md
.PHONY: test-agent
test-agent: $(depsAgent) | $(MDRIP)
$(MDRIP) --subshell test $^
depsCustomAuth = $(depsPermsAuth) content/$(tutCustomAuth).md
.PHONY: test-custom-auth
test-custom-auth: $(depsCustomAuth) | $(MDRIP)
$(MDRIP) --subshell test $^
$(completer)-custom-authorizer.sh: $(depsCustomAuth) | $(MDRIP)
mkdir -p $(@D)
$(MDRIP) --preambled 0 completer $^ > $@
depsMountTable = $(depsBasics) content/$(tutMountTable).md
.PHONY: test-mount-table
test-mount-table: $(depsMountTable) | $(MDRIP)
$(MDRIP) --subshell test $^
depsNamespace = $(depsBasics) content/$(tutNamespace).md
.PHONY: test-namespace
test-namespace: $(depsNamespace) | $(MDRIP)
$(MDRIP) --subshell test $^
depsSuffixPart1 = $(depsBasics) content/$(tutSuffixPart1).md
.PHONY: test-suffix-part1
test-suffix-part1: $(depsSuffixPart1) | $(MDRIP)
$(MDRIP) --subshell test $^
$(completer)-suffix-part1.sh: $(depsSuffixPart1) | $(MDRIP)
mkdir -p $(@D)
$(MDRIP) --preambled 0 completer $^ > $@
depsSuffixPart2 = $(depsMultiDisp) content/$(tutSuffixPart2).md
.PHONY: test-suffix-part2
test-suffix-part2: $(depsSuffixPart2) | $(MDRIP)
$(MDRIP) --subshell test $^
$(completer)-suffix-part2.sh: $(depsSuffixPart2) | $(MDRIP)
mkdir -p $(@D)
$(MDRIP) --preambled 0 completer $^ > $@
depsGlobber = $(depsMultiDisp) content/$(tutGlobber).md
.PHONY: test-globber
test-globber: $(depsGlobber) | $(MDRIP)
$(MDRIP) --subshell test $^
$(completer)-globber.sh: $(depsGlobber) | $(MDRIP)
mkdir -p $(@D)
$(MDRIP) --preambled 0 completer $^ > $@
depsJsHello = $(depsBasics) content/$(tutJSHello).md
.PHONY: test-js-hello
test-js-hellopeer: $(depsJsHello) | $(MDRIP)
$(MDRIP) --subshell test $^
$(completer)-js-hellopeer.sh: $(depsJsHello) | $(MDRIP)
mkdir -p $(@D)
$(MDRIP) --preambled 0 completer $^ > $@
$(scenario)-e-setup.sh: $(completer)-js-hellopeer.sh
cp $^ $@
depsJsFortune = $(depsBasics) content/$(tutJSFortune).md
.PHONY: test-js-fortune
test-js-fortune: $(depsJsFortune) | $(MDRIP)
$(MDRIP) --subshell test $^
$(completer)-js-fortune.sh: $(depsJsFortune) | $(MDRIP)
mkdir -p $(@D)
$(MDRIP) --preambled 0 completer $^ > $@
# An ordering that lets us test all the tutorials faster than running the
# individual tests in sequence. This exploits the knowledge that, for example,
# tutCaveats3rd can be tested right after tutCaveats1st without reseting to a
# clean slate. WipeSlate and Basics are done where needed to reset state.
depsOneBigCoreTutorialTest = \
content/$(tutSetup).md \
content/$(tutCheckup).md \
content/$(tutWipeSlate).md \
content/$(tutHello).md \
content/$(tutBasics).md \
content/$(tutPrincipals).md \
content/$(tutPermsAuth).md \
content/$(tutCaveats1st).md \
content/$(tutCaveats3rd).md \
content/$(tutAgent).md \
content/$(tutCustomAuth).md \
content/$(tutWipeSlate).md \
content/$(tutBasics).md \
content/$(tutMountTable).md \
content/$(tutNamespace).md \
content/$(tutWipeSlate).md \
content/$(tutBasics).md \
content/$(tutPrincipals).md \
content/$(tutPermsAuth).md \
content/$(tutSuffixPart1).md \
content/$(tutSuffixPart2).md
# An ordering that lets us test all the JS tutorials faster than running the
# individual tests in sequence.
depsOneBigJsTutorialTest = \
content/$(tutSetup).md \
content/$(tutCheckup).md \
content/$(tutWipeSlate).md \
content/$(tutBasics).md \
content/$(tutJSHello).md \
content/$(tutJSFortune).md
# An ordering that lets us test all the Java tutorials faster than running the
# individual tests in sequence.
depsOneBigJavaTutorialTest = \
content/$(tutJavaFortune).md \
content/$(tutJavaAndroid).md
.PHONY: test
test: test-site test-tutorials-core test-tutorials-js-node test-tutorials-java
.PHONY: test-site
test-site: build node_modules
tape test/test-*.js
# Test core tutorials against an existing development install.
#
# This is the target to run to see if the tutorials work against Vanadium
# changes that have not been checked in.
#
# Called from v.io/x/devtools/jiri-test/internal/test/website.go.
# This test fails if JIRI_ROOT isn't defined.
# This test defines V_TUT (a tutorial variable) appropriately in terms of
# JIRI_ROOT.
.PHONY: test-tutorials-core
test-tutorials-core: build
jiri go install v.io/v23/... v.io/x/ref/...
$(MDRIP) --subshell --blockTimeOut 1m test content/testing.md $(depsOneBigCoreTutorialTest)
# Test Java tutorials.
.PHONY: test-tutorials-java
test-tutorials-java: build
$(MDRIP) --blockTimeOut 5m --subshell test $(depsOneBigJavaTutorialTest)
# Test JS tutorials against an existing development install.
#
# This is the target to run to see if the tutorials work against Vanadium
# changes that have not been checked in.
#
# Note: Unlike test-tutorials-js-web, this test is intended to skip the UI
# portion of the test in order to achieve some amount of test coverage without
# having to introduce additional dependencies.
#
# Called from v.io/x/devtools/jiri-test/internal/test/website.go.
# This test fails if JIRI_ROOT isn't defined.
# This test defines V_TUT (a tutorial variable) appropriately in terms of
# JIRI_ROOT.
.PHONY: test-tutorials-js-node
test-tutorials-js-node: build
jiri go install v.io/v23/... v.io/x/ref/...
$(MDRIP) --blockTimeOut 2m --subshell test content/testing.md $(depsOneBigJsTutorialTest)
# Test JS tutorials (web version) against an existing development install.
#
# This is the target to run to see if the tutorials work against Vanadium
# changes that have not been checked in.
#
# However, it uses the live version of the Vanadium extension.
#
# Used to be called from v.io/x/devtools/jiri-test/internal/test/website.go.
# This test fails if JIRI_ROOT isn't defined.
#
# This test also takes additional env vars (typically temporary):
# - GOOGLE_BOT_USERNAME and GOOGLE_BOT_PASSWORD (to sign into Google/Chrome)
# - CHROME_WEBDRIVER (the path to the Chrome WebDriver)
# - WORKSPACE (optional, defaults to $JIRI_ROOT/website)
#
# In addition, this test requires Maven and Xvfb and xvfb-run to be installed.
# An HTML report is written to $JIRI_ROOT/website/htmlReports.
#
# NOTE(sadovsky): This test does not currently work, is omitted from continuous
# integration testing, and will likely be decommissioned soon.
.PHONY: test-tutorials-js-web
test-tutorials-js-web: build
jiri go install v.io/v23/... v.io/x/ref/...
$(MDRIP) --subshell --blockTimeOut 3m testui content/testing.md $(depsOneBigJsTutorialTest)
# Test tutorials against fresh external install.
#
# This runs an install from v.io, then runs the tutorials against that install,
# exactly as an external user would run them. Local changes of Vanadium have no
# impact on this test. This test does not require definition of JIRI_ROOT; it
# uses V23_RELEASE instead, per the installation instructions on the external
# site.
.PHONY: test-tutorials-external
test-tutorials-external: build
$(MDRIP) --subshell --blockTimeOut 10m test content/$(install_md) $(depsOneBigCoreTutorialTest)
# Test tutorials without install. Assumes JIRI_ROOT and V23_RELEASE are defined.
#
# This runs tests without first doing any installation step, and assumes
# JIRI_ROOT and V23_RELEASE are properly defined. It's a time saver if you are
# happy with your installation and are just debugging tutorial code.
.PHONY: test-tutorials-no-install
test-tutorials-no-install: build
$(MDRIP) --subshell test $(depsOneBigCoreTutorialTest)
# The files needed to build JS tutorial output.
depsJSTutorialResults = \
content/testing.md \
content/$(tutSetup).md \
content/$(tutBasics).md \
content/$(tutJSHello).md \
content/$(tutJSFortune).md
# There are two steps to this build target:
# 1. Build any dependencies like the VDL tool.
# 2. Run mdrip to create artifacts from running $(jsDeps) code blocks.
#
# NOTE: Jenkins nodes may use the $JIRI_ROOT installation rather than "go get".
# The "jiri go install" line below ensures all required tools (e.g. vdl) are
# installed.
$(jsTutorialResults): $(depsJSTutorialResults) | $(MDRIP)
jiri go install v.io/v23/... v.io/x/ref/...
V_TUT=$(abspath $@) $(MDRIP) --subshell --blockTimeOut 1m buildjs $^
rm -rf $(abspath $@)/node_modules