--- Mk/Uses/nodejs.mk 1969-12-31 16:00:00.000000000 -0800 +++ Mk/Uses/nodejs.mk 2015-12-27 22:37:30.418547000 -0800 @@ -0,0 +1,654 @@ +# $FreeBSD$ +# +# Provide support for NodeJS based projects +# +# Feature: nodejs +# Usage: USES=nodejs +# +# MAINTAINER: portmgr@FreeBSD.org + +# NODE_SUB_PROJECTS - additional projects to extract into individual +# directories. Distfile for the group with the name +# of the sub-project is extracted into the sub-folder +# with the same name. Build is also performed for +# sub-projects. +# NODE_USES - additional features enabled in nodejs module: +# grunt - run grunt tasks as a part of the build +# merge-pkg-deps - merge packageDependencies into dependencies in package.json +# rm-coffee - removes *.coffee files that have .js counterparts +# NODE_MODULES_ADD - add node module dependencies in the format: +# [[{dev|peer|bundle}@]directory@]module:version +# It is also used to upgrade outdated package dependencies. +# NODE_MODULES_DEL - delete node module dependencies in the format: +# [[{dev|peer|bundle}@]directory@]module +# NODE_FILES_TO_CLEAN - wildcards for files and directoroes that do not need to be installed +# NODE_SRCDIR - (rare) subdirectory where the source is +# NODE_SUBDIR - (rare) directory where NODE_SRCDIR is copied to +# NODE_RM_DIRS - directories to delete +# NODE_CMDS - commands to install in format src:dst, where src is based +# on NODE_INSTALL_BASE, and dst is based on LOCALBASE + +# Port workflow: +# * It starts in the DEBUG mode. In DEBUG mode port can be built and run but +# can't be committed. Developer can make changes to the port in the DEBUG mode. +# * 'make makerelease' - brings the port to RELEASE mode, when it can be committed +# * 'make makedebug' - brings the port back to DEBUG mode in order to make changes +# * 'make printmode' - prints the current mode of the port +# * 'make acceptplist' - rebuilds plist +# + +# NOTE: archivers/gtar is used to make the distfile because FreeBSD tar(1) has a bug +# that prevents it from producing the deterministic output in certain situations +# (https://github.com/libarchive/libarchive/pull/623) +# NOTE: some sections of package.json are deleted (ex. scripts/test) as a workaround +# for the npm bug that causes package.json volatility +# (https://github.com/npm/npm/issues/10406) +# NOTE: 'npm dedupe' operation is broken and is left disabled +# (https://github.com/npm/npm/issues/10783) + +.if !defined(_INCLUDE_USES_NODE_MK) +_INCLUDE_USES_NODE_MK= yes + +# dependencies +FETCH_DEPENDS+= npm:${PORTSDIR}/www/npm \ + jq:${PORTSDIR}/textproc/jq \ + gtar:${PORTSDIR}/archivers/gtar +BUILD_DEPENDS+= npm:${PORTSDIR}/www/npm \ + gmake:${PORTSDIR}/devel/gmake +RUN_DEPENDS+= node:${PORTSDIR}/www/node + +_NODE_DIR?= ${PORTNAME}-${PORTVERSION} + +PORTREVISION?= 0 +.if ${PORTREVISION} != 0 +_NODE_SUF1= _${PORTREVISION} +.endif + +# commands +NPM_CMD?= ${LOCALBASE}/bin/npm +NODE_CMD?= ${LOCALBASE}/bin/node +GMAKE_CMD?= ${LOCALBASE}/bin/gmake +JQ_CMD?= ${LOCALBASE}/bin/jq +GTAR_CMD?= ${LOCALBASE}/bin/gtar + +#_NODE_DISTRO_TAR_CMD= ${TAR} +_NODE_DISTRO_TAR_CMD= ${GTAR_CMD} +_NODE_DISTRO_GZIP_CMD= gzip + +# variables +_NODE_TMP_BASE_FETCH= ${DISTDIR}/${_NODE_DIR}.tmpdirs +_NODE_TMP_BASE_BUILD= ${WRKDIR}/.tmpdirs +_NODE_USERHOME_FETCH= ${_NODE_TMP_BASE_FETCH}/.userhome +_NODE_TMP_FETCH= ${_NODE_TMP_BASE_FETCH}/.tmp +_NODE_USERHOME_BUILD= ${_NODE_TMP_BASE_BUILD}/.userhome +_NODE_TMP_BUILD= ${_NODE_TMP_BASE_BUILD}/.tmp +_NODE_FAKE_GIT= ${_NODE_TMP_FETCH}/fake-git +_NODE_FAKE_GMAKE= ${_NODE_TMP_BUILD}/gmake +_NODE_NPMRC_FETCH= ${_NODE_USERHOME_FETCH}/.npmrc +_NODE_CR_TMP_DIR_FETCH= ${MKDIR} ${_NODE_USERHOME_FETCH} ${_NODE_TMP_FETCH} +_NODE_CR_TMP_DIR_BUILD= ${MKDIR} ${_NODE_USERHOME_BUILD} ${_NODE_TMP_BUILD} +_NODE_RM_TMP_DIR_FETCH= ${RM} -r ${_NODE_TMP_BASE_FETCH} +_NODE_RM_TMP_DIR_BUILD= ${RM} -r ${_NODE_TMP_BASE_BUILD} +_NODE_MK_TMP_DIR_FETCH= ${_NODE_RM_TMP_DIR_FETCH} && ${_NODE_CR_TMP_DIR_FETCH} +_NODE_MK_TMP_DIR_BUILD= ${_NODE_RM_TMP_DIR_BUILD} && ${_NODE_CR_TMP_DIR_BUILD} +# environment and arguments +CFLAGS+= -I${LOCALBASE}/include/node +CXXFLAGS+= -I${LOCALBASE}/include/node +NPM_ENV+= C=${CC} CXX=${CXX} +NPM_ENV_FETCH= ${NPM_ENV} HOME=${_NODE_USERHOME_FETCH} TMP=${_NODE_TMP_FETCH} PATH=${_NODE_TMP_FETCH}:${PATH} +NPM_ENV_BUILD= ${NPM_ENV} HOME=${_NODE_USERHOME_BUILD} TMP=${_NODE_TMP_BUILD} PATH=${_NODE_TMP_BUILD}:${PATH} +NPM_LOG_LEVEL?= warn +NPM_FETCH_ARGS= --loglevel ${NPM_LOG_LEVEL} --ignore-scripts +NPM_BUILD_ARGS= --loglevel ${NPM_LOG_LEVEL} --nodedir=${LOCALBASE} +NPM_PRUNE_ARGS= --loglevel ${NPM_LOG_LEVEL} --production=true +NPM_DEDUPE_ARGS= --loglevel ${NPM_LOG_LEVEL} --production=true +NPM_SHRINKWRAP_ARGS= --dev +# internal variables +_NODE_PACKAGE_JSON= package.json +_NODE_PACKAGE_EXISTS= [ -f ${_NODE_PACKAGE_JSON} ] +_NODE_IS_RELEASE_MODE= [ ${_NODE_DEBUG_MODE} = no ] +_NODE_IS_DEBUG_MODE= [ ${_NODE_DEBUG_MODE} = yes ] +_NODE_SHRINKWRAP_NAME:= npm-shrinkwrap.json +_NODE_SHRINKWRAP_FILE:= ${FILESDIR}/${_NODE_SHRINKWRAP_NAME} +_NODE_DO_FAIL= return 1 +_NODE_ORIG_DISTFILES:= ${DISTFILES} +_NODE_MASTER_SITE_BACKUP_URLS= ${MASTER_SITE_BACKUP}${NODE_DISTFILE} +_NODE_BUILD_DIR?= . +.if defined(NODE_SRCDIR) +_NODE_DO_CD= node_modules/${NODE_SUBDIR} +.else +_NODE_DO_CD= . +.endif +_NODE_FETCH_WORKDIR= ${DISTDIR} +# +NODE_INSTALL_BASE?= ${LOCALBASE}/share/node-projects +NODE_INSTALL_DIR:= ${NODE_INSTALL_BASE}/${PORTNAME} +NODE_DISTFILE:= ${PORTNAME}-${PORTVERSION}${_NODE_SUF1}-nodejs.tar.gz +# variables to be used by ports +NODE_FILES_TO_CLEAN+= .git* CVS .svn +NODE_FILES_TO_CLEAN+= .lock-wscript .wafpickle-N *.swp .DS_Store ._* .editorconfig .eslintrc .jshintignore npm-debug.log bower.json +NODE_FILES_TO_CLEAN+= *.bak *.log *.bat file .travis.yml man *.info .npmignore .jshintrc .jscsrc .bowerrc .dockerignore .mailmap +NODE_FILES_TO_CLEAN+= CHANGELOG CHANGELOG.md HISTORY.md README README.* AUTHORS AUTHORS.* CONTRIBUTORS CONTRIBUTING.md HISTORY HISTORY.* +NODE_FILES_TO_CLEAN+= Makefile *.mk *.cmake Dockerfile Vagrantfile Rakefile + +CKSUMFILES+= ${NODE_DISTFILE} +WRKSRC= ${WRKDIR}/${_NODE_DIR} + +.if ! exists(${_NODE_SHRINKWRAP_FILE}) +NO_CHECKSUM=yes +_NODE_DEBUG_MODE=yes +node-remind-debug-mode: + @${ECHO_CMD} "(!!!)" + @${ECHO_CMD} "(!!!) Port ${PORTNAME} is in the DEBUG mode, run 'make makerelease' to finalize it" + @${ECHO_CMD} "(!!!)" +node-assert-debug-mode: node-check-shrinkwrap-files +node-assert-release-mode: node-check-shrinkwrap-files + @${ECHO} "(!!!)" + @${ECHO} "(!!!) already in the DEBUG mode" + @${ECHO} "(!!!)" + @${FALSE} +node-print-mode: node-check-shrinkwrap-files + @${ECHO} "Port ${PORTNAME} is in the DEBUG mode" +node-check-shrinkwrap-files: + @for sp in ${NODE_SUB_PROJECTS}; do \ + if [ -f ${FILESDIR}/$${sp}/${_NODE_SHRINKWRAP_NAME} ]; then \ + ${ECHO} "(!!!) ERROR: shrinkwrap file for sub-project $${sp} exists in DEBUG mode!"; \ + ${FALSE}; \ + fi; \ + done +.else +_NODE_DEBUG_MODE=no +node-remind-debug-mode: +node-assert-debug-mode: node-check-shrinkwrap-files + @${ECHO} "(!!!)" + @${ECHO} "(!!!) already in RELEASE mode" + @${ECHO} "(!!!)" + @${FALSE} +node-assert-release-mode: node-check-shrinkwrap-files +node-print-mode: node-check-shrinkwrap-files + @${ECHO} "Port ${PORTNAME} is in the RELEASE mode" +node-check-shrinkwrap-files: + @for sp in ${NODE_SUB_PROJECTS}; do \ + if ! [ -f ${FILESDIR}/$${sp}/${_NODE_SHRINKWRAP_NAME} ]; then \ + ${ECHO} "(!!!) ERROR: shrinkwrap file for sub-project $${sp} is missing!"; \ + ${_NODE_DO_FAIL}; \ + fi; \ + done +.endif + +# uses +.for f in ${NODE_USES} +_f:= ${f:C/\:.*//} +.if ${_f}=="grunt" +FETCH_DEPENDS+= grunt:${PORTSDIR}/devel/grunt +GRUNT_CMD?= ${LOCALBASE}/bin/grunt +GRUNT_ENV+= HOME=${_NODE_USERHOME_BUILD} TMP=${_NODE_TMP_BUILD} PATH=${_NODE_TMP_BUILD}:${PATH} +GRUNT_BUILD_ARGS+= +NODE_GRUNT_TARGETS?= +_NODE_USES_GRUNT= yes +.elif ${_f}=="merge-pkg-deps" +_NODE_USES_MERGE_PKG_DEPS= yes +.elif ${_f}=="rm-coffee" +_NODE_USES_RM_COFFEE= yes +.else +. error Unknown NODE_USES value. +.endif +.endfor + +# exported development mode targets +makerelease: node-assert-debug-mode node-delete-distfile clean fetch node-make-shrinkwrap node-post-make-shrinkwrap +makedebug: node-assert-release-mode node-delete-shrinkwrap +printmode: node-print-mode +acceptplist: node-accept-plist + +# internal targets +node-accept-plist: stage + @${MAKE} makeplist | tail -n +2 > pkg-plist +node-delete-distfile: + @${RM} -f ${_NODE_FETCH_WORKDIR}/${NODE_DISTFILE} + +node-make-shrinkwrap: + @${ECHO} "===> Making npm-shrinkwrap set to freeze the component versions for ${PKGNAME}" + @createWithNpm() { \ + ${NPM_ENV_FETCH} ${NPM_CMD} shrinkwrap ${NPM_SHRINKWRAP_ARGS}; \ + }; \ + createOne() { \ + local dir=$$1; \ + (for subdir in $$([ -d $${dir}/node_modules ] && cd $${dir}/node_modules && ls | sort | grep -v "^\."); do \ + local deps=$$(createOne "$${dir}/node_modules/$${subdir}"); \ + ${JQ_CMD} -s 'map({(.name): ({version, from: "\(.name)@=\(.version)", resolved: ._resolved} \ + *({dependencies: '"$$deps"'}|select(.dependencies!=null)//{}))})[]' \ + "$${dir}/node_modules/$${subdir}/package.json"; \ + done) | ${JQ_CMD} -s 'add'; \ + }; \ + createWithJq() { \ + (${JQ_CMD} '{name,version}' package.json && (createOne . | ${JQ_CMD} -s 'add|{"dependencies":.}')) | ${JQ_CMD} -s 'add' > npm-shrinkwrap.json; \ + }; \ + ${_NODE_MK_TMP_DIR_FETCH} && \ + cd ${_NODE_FETCH_WORKDIR} && \ + ${RM} -rf ${_NODE_DIR} && \ + ${EXTRACT_CMD} ${EXTRACT_BEFORE_ARGS} ${NODE_DISTFILE} ${EXTRACT_AFTER_ARGS} && \ + cd ${_NODE_DIR}/${_NODE_DO_CD} && \ + (cd ${_NODE_BUILD_DIR} && \ + createWithJq && \ + ${MKDIR} ${FILESDIR} && \ + ${MV} ${_NODE_SHRINKWRAP_NAME} ${_NODE_SHRINKWRAP_FILE}) && \ + for sp in ${NODE_SUB_PROJECTS}; do \ + (cd $${sp} && \ + createWithJq && \ + ${MKDIR} ${FILESDIR}/$${sp} && \ + ${MV} ${_NODE_SHRINKWRAP_NAME} ${FILESDIR}/$${sp}/) || ${_NODE_DO_FAIL}; \ + done && \ + cd ${_NODE_FETCH_WORKDIR} && \ + ${_NODE_RM_TMP_DIR_FETCH} && \ + ${RM} -r ${_NODE_DIR} + +node-delete-dist-file: + @cd ${_NODE_FETCH_WORKDIR} && \ + ${RM} ${NODE_DISTFILE} + +node-post-make-shrinkwrap: node-delete-dist-file node-enter-release-mode-msg node-refetch-for-release-mode node-in-release-mode-msg + +node-enter-release-mode-msg: + @${ECHO} "%%%" + @${ECHO} "%%% shrinkwrap file(s) have been generated, entering RELEASE mode" + @${ECHO} "%%%" + +node-refetch-for-release-mode: + @${ECHO} "==> Re-fetching with shrinkwrap in RELEASE mode" && \ + _NODE_FETCH_DESCR="(re-fetch with shrinkwrap)" ${MAKE} fetch + +node-in-release-mode-msg: + @${ECHO} "%%%" + @${ECHO} "%%% in RELEASE mode now, run 'make makesum'" + @${ECHO} "%%%" + +node-delete-shrinkwrap: node-assert-release-mode + @${RM} -f `${FIND} ${FILESDIR} -name ${_NODE_SHRINKWRAP_NAME}` + @${ECHO} "%%%" + @${ECHO} "%%% shrinkwrap file(s) have been deleted, entering DEBUG mode" + @${ECHO} "%%%" + +node-fakegit: .EXEC .PHONY + @${_NODE_MK_TMP_DIR_FETCH} && \ + (${ECHO} '#!/bin/sh'; \ + ${ECHO} ''; \ + ${ECHO} 'name="nodejs-fetch"'; \ + ${ECHO} 'DISTDIR="${DISTDIR}"'; \ + ${ECHO} 'NODE_ORIG_DISTFILES="${_NODE_ORIG_DISTFILES:C@^([^:]+).*@\1@}"'; \ + ${ECHO} 'NODE_VERBOSE="${NODE_VERBOSE}"'; \ + ${ECHO} 'NODE_DEBUG="${NODE_DEBUG}"'; \ + ${ECHO} ''; \ + ${ECHO} 'msg() {'; \ + ${ECHO} ' [ "$$NODE_VERBOSE" = yes ] && echo "$${name}: $$1" >&2'; \ + ${ECHO} ' dbg_log "$${name}: $$1"'; \ + ${ECHO} '}'; \ + ${ECHO} 'err() {'; \ + ${ECHO} ' echo "$${name}: ERROR: $$1" >&2'; \ + ${ECHO} ' dbg_log "$${name}: ERROR: $$1"'; \ + ${ECHO} '}'; \ + ${ECHO} 'dbg_log() {'; \ + ${ECHO} ' [ "$$NODE_DEBUG" = yes ] && (echo "$$1" >>/tmp/nodejs-$$$$.log)'; \ + ${ECHO} '}'; \ + ${ECHO} ''; \ + ${ECHO} 'dbg_log "called with arguments: $$*"'; \ + ${ECHO} ''; \ + ${ECHO} 'cmd_clone_remote() {'; \ + ${ECHO} ' local mirror="$$1"'; \ + ${ECHO} ' local dir="$$2"'; \ + ${ECHO} ' msg "Git clone requested: mirror=$$mirror -> dir=$${dir}"'; \ + ${ECHO} ' local fname_regex=$$(echo $$mirror | sed -E "s/https:\/\/github\.com\/([^/]+)\/([^/]+)\.git$$/^\1-\2-[[:alnum:].]*_GH0.tar.gz$$/g")'; \ + ${ECHO} ' local fname=$$(find_file "$${fname_regex}")'; \ + ${ECHO} ' if [ -n "$${fname}" ]; then'; \ + ${ECHO} ' msg "Found distfile=$$fname for $$mirror"'; \ + ${ECHO} ' (cd $${dir} && tar xzf $${DISTDIR}/$${fname} --strip 1)'; \ + ${ECHO} ' return $$?'; \ + ${ECHO} ' else'; \ + ${ECHO} ' err "Failed to find distfile for $$mirror"'; \ + ${ECHO} ' return 1'; \ + ${ECHO} ' fi'; \ + ${ECHO} '}'; \ + ${ECHO} 'cmd_clone_local() {'; \ + ${ECHO} ' local src="$$1"'; \ + ${ECHO} ' local dst="$$2"'; \ + ${ECHO} ' msg "copy $$src -> $$dst"'; \ + ${ECHO} ' (cd $${src} && tar czf - .) | (cd $${dst} && tar xzf -)'; \ + ${ECHO} '}'; \ + ${ECHO} ''; \ + ${ECHO} 'cmd_checkout() {'; \ + ${ECHO} ' msg "do nothing for checkout of $$1 in `pwd`"'; \ + ${ECHO} '}'; \ + ${ECHO} ''; \ + ${ECHO} 'find_file() {'; \ + ${ECHO} ' for f in $${NODE_ORIG_DISTFILES}; do'; \ + ${ECHO} ' if expr "$${f}" : "$${fname_regex}" > /dev/null; then'; \ + ${ECHO} ' echo "$$f"'; \ + ${ECHO} ' return'; \ + ${ECHO} ' fi'; \ + ${ECHO} ' done'; \ + ${ECHO} '}'; \ + ${ECHO} ''; \ + ${ECHO} 'case $$1 in'; \ + ${ECHO} 'clone)'; \ + ${ECHO} ' shift'; \ + ${ECHO} ' while [ $$# -gt 0 ]; do'; \ + ${ECHO} ' key="$$1"'; \ + ${ECHO} ' case $$key in'; \ + ${ECHO} ' --template=*)'; \ + ${ECHO} ' ;;'; \ + ${ECHO} ' --mirror)'; \ + ${ECHO} ' MIRROR="$$2"'; \ + ${ECHO} ' shift'; \ + ${ECHO} ' ;;'; \ + ${ECHO} ' -*)'; \ + ${ECHO} ' err "Unknown argument: $$key" && exit 1'; \ + ${ECHO} ' ;;'; \ + ${ECHO} ' *)'; \ + ${ECHO} ' if [ $$# -eq 1 -a -n "$$MIRROR" ]; then'; \ + ${ECHO} ' cmd_clone_remote "$${MIRROR}" "$$key"'; \ + ${ECHO} ' exit $$?'; \ + ${ECHO} ' fi'; \ + ${ECHO} ' if [ $$# -eq 2 -a -z "$$MIRROR" ]; then'; \ + ${ECHO} ' cmd_clone_local "$$1" "$$2"'; \ + ${ECHO} ' exit $$?'; \ + ${ECHO} ' fi'; \ + ${ECHO} ' err "Unknown argument #=$$#: $$key"'; \ + ${ECHO} ' exit 1'; \ + ${ECHO} ' ;;'; \ + ${ECHO} ' esac'; \ + ${ECHO} ' shift'; \ + ${ECHO} ' done'; \ + ${ECHO} ' ;;'; \ + ${ECHO} 'rev-list)'; \ + ${ECHO} ' shift'; \ + ${ECHO} ' while [ $$# -gt 0 ]; do'; \ + ${ECHO} ' key="$$1"'; \ + ${ECHO} ' case $$key in'; \ + ${ECHO} ' -n1)'; \ + ${ECHO} ' shift'; \ + ${ECHO} ' [ $$# -eq 1 ] || ! err "Unknown argument: $$key" || exit 1'; \ + ${ECHO} ' msg "Returning same revision $$1"'; \ + ${ECHO} ' echo $$1'; \ + ${ECHO} ' exit 0'; \ + ${ECHO} ' ;;'; \ + ${ECHO} ' *)'; \ + ${ECHO} ' err "Unknown argument: $$key" && exit 1'; \ + ${ECHO} ' ;;'; \ + ${ECHO} ' esac'; \ + ${ECHO} ' shift'; \ + ${ECHO} ' done'; \ + ${ECHO} ' err "rev-list without arguments" && exit 1'; \ + ${ECHO} ' ;;'; \ + ${ECHO} 'checkout)'; \ + ${ECHO} ' shift'; \ + ${ECHO} ' if [ $$# -eq 1 ]; then'; \ + ${ECHO} ' cmd_checkout "$$1"'; \ + ${ECHO} ' exit 0'; \ + ${ECHO} ' fi'; \ + ${ECHO} ' ;;'; \ + ${ECHO} 'config)'; \ + ${ECHO} ' echo ""'; \ + ${ECHO} ' ;;'; \ + ${ECHO} '*)'; \ + ${ECHO} ' err "Unknown command: $$1" && exit 1'; \ + ${ECHO} ' ;;'; \ + ${ECHO} 'esac'; \ + ${ECHO} '') > ${_NODE_FAKE_GIT} + @${CHMOD} +x ${_NODE_FAKE_GIT} + @${ECHO} "git = ${_NODE_FAKE_GIT}" >> ${_NODE_NPMRC_FETCH} + +node-fakemake: .EXEC .PHONY + @${_NODE_MK_TMP_DIR_BUILD} && \ + (${ECHO} '#!/bin/sh'; \ + ${ECHO} ''; \ + ${ECHO} '${MAKE_ENV} PATH=$$PATH:${LOCALBASE}/bin ${GMAKE_CMD} ${MAKE_ARGS} $$@'; \ + ${ECHO} '') >> ${_NODE_FAKE_GMAKE} + @${CHMOD} +x ${_NODE_FAKE_GMAKE} + +# XXX need this? +.if !target(nodejs-patch-fetch) +nodejs-patch-fetch: +.endif + +_USES_fetch+= 750:node-npm-fetch +node-npm-fetch: node-fakegit + @${MKDIR} ${_NODE_FETCH_WORKDIR} + @cd ${_NODE_FETCH_WORKDIR}; \ + force_fetch=false; \ + for afile in ${FORCE_FETCH}; do \ + afile=$${afile##*/}; \ + if [ "x$$afile" = "x${NODE_DISTFILE}" ]; then \ + force_fetch=true; \ + fi; \ + done; \ + if [ ! -f ${NODE_DISTFILE} -o "$$force_fetch" = "true" ]; then \ + ${RM} -rf ${_NODE_DIR} ${NODE_DISTFILE}; \ + if ${_NODE_IS_RELEASE_MODE}; then \ + for url in ${_NODE_MASTER_SITE_BACKUP_URLS}; do \ + if ${ECHO_MSG} "===> Attempting to fetch ${PORTNAME} from the master backup site" && \ + ${SETENV} ${FETCH_ENV} ${FETCH_CMD} ${FETCH_BEFORE_ARGS} $${url} ${FETCH_AFTER_ARGS}; then \ + return 0; \ + fi; \ + done; \ + fi && \ + if ${ECHO_MSG} "===> Extracting node project source for ${PKGNAME} ${_NODE_FETCH_DESCR}" && \ + ${MKDIR} ${_NODE_DIR} && \ + for main_distfile in ${_NODE_ORIG_DISTFILES:N*\:*}; do \ + ${EXTRACT_CMD} ${EXTRACT_BEFORE_ARGS} $${main_distfile} ${EXTRACT_AFTER_ARGS} \ + -C ${_NODE_DIR} --strip 1 || ${_NODE_DO_FAIL}; \ + done && \ + for sp in ${NODE_SUB_PROJECTS}; do \ + for df in `${ECHO} ${_NODE_ORIG_DISTFILES} | tr ' ' '\n' | grep :$${sp}$$`; do \ + ${MKDIR} ${_NODE_DIR}/$${sp} && \ + ${EXTRACT_CMD} ${EXTRACT_BEFORE_ARGS} ${DISTDIR}/`${ECHO} $${df} | ${SED} -e 's/:[^:]*$$//g'` ${EXTRACT_AFTER_ARGS} \ + -C ${_NODE_DIR}/$${sp} --strip 1 || ${_NODE_DO_FAIL}; \ + done; \ + done && \ + (cd ${_NODE_DIR} && ${MAKE} -f ${MASTERDIR}/Makefile nodejs-patch-fetch) && \ + ${ECHO_MSG} "===> Preparing the node project for ${PKGNAME} ${_NODE_FETCH_DESCR}" && \ + cd ${_NODE_DIR} && \ + ([ -z "${NODE_SRCDIR}" ] || \ + (${MKDIR} node_modules && \ + ${MV} ${NODE_SRCDIR} node_modules/${NODE_SUBDIR} \ + ) \ + ) && cd ${_NODE_DO_CD} && \ + for m in ${NODE_MODULES_ADD}; do \ + if expr $$m : ".*@.*@.*" > /dev/null ; then \ + mloc=$${m%@*@*}; \ + mdir=$${m%@*}; \ + mdir=$${mdir#*@}; \ + mmod=$${m#*@*@}; \ + elif expr $$m : ".*@.*" > /dev/null ; then \ + mloc=dependencies; \ + mdir=$${m%@*}; \ + mmod=$${m#*@}; \ + else \ + mloc=dependencies; \ + mdir=.; \ + mmod=$$m; \ + fi && \ + mloc=$$(${ECHO} $$mloc | ${SED} -E 's/^(dev|peer|bundle)$$/\1Dependencies/') && \ + (cd $$mdir && ${JQ_CMD} -s ".[0] * `echo $$mmod | sed -E 's/^([[:alnum:]_-]+):(.+)$$/{"'$$mloc'":{"\\1":"\\2"}}/'`" \ + package.json > package.json.new && ${MV} package.json.new package.json) || ${_NODE_DO_FAIL}; \ + done && \ + for m in ${NODE_MODULES_DEL}; do \ + if expr $$m : ".*@.*@.*" > /dev/null ; then \ + mloc=$${m%@*@*}; \ + mdir=$${m%@*}; \ + mdir=$${mdir#*@}; \ + mmod=$${m#*@*@}; \ + elif expr $$m : ".*@.*" > /dev/null ; then \ + mloc=dependencies; \ + mdir=$${m%@*}; \ + mmod=$${m#*@}; \ + else \ + mloc=dependencies; \ + mdir=.; \ + mmod=$$m; \ + fi && \ + mloc=$$(${ECHO} $$mloc | ${SED} -E 's/^(dev|peer|bundle)$$/\1Dependencies/') && \ + (cd $$mdir && ${JQ_CMD} -s ".[0] | del(.[\"$$mloc\"][\"$$mmod\"])" \ + package.json > package.json.new && ${MV} package.json.new package.json) || ${_NODE_DO_FAIL}; \ + done && \ + ([ -z ${_NODE_USES_MERGE_PKG_DEPS} ] || \ + (${JQ_CMD} -s '(.[0] | del(.["packageDependencies"])) * (.[0]["packageDependencies"] | {"dependencies": .})' \ + package.json > package.json.new && ${MV} package.json.new package.json)) && \ + if ${_NODE_IS_RELEASE_MODE}; then \ + ${CP} ${_NODE_SHRINKWRAP_FILE} . && \ + for sp in ${NODE_SUB_PROJECTS}; do \ + (cd $${sp} && ${CP} ${FILESDIR}/$${sp}/${_NODE_SHRINKWRAP_NAME} .) || ${_NODE_DO_FAIL}; \ + done; \ + fi && \ + ${ECHO_MSG} "===> Downloading the nodejs dependencies for ${PKGNAME} ${_NODE_FETCH_DESCR}" && \ + (cd ${_NODE_BUILD_DIR} && ! ${_NODE_PACKAGE_EXISTS} || ${NPM_ENV_FETCH} ${NPM_CMD} install ${NPM_FETCH_ARGS}) && \ + for sp in ${NODE_SUB_PROJECTS}; do \ + ${ECHO_MSG} "===> Downloading the nodejs dependencies for ${PKGNAME}/$${sp} ${_NODE_FETCH_DESCR}" && \ + (cd $${sp} && ${NPM_ENV_FETCH} ${NPM_CMD} install ${NPM_FETCH_ARGS}) || ${_NODE_DO_FAIL}; \ + done && \ + for dir in ${NODE_RM_DIRS}; do \ + ${RM} -r ${_NODE_BUILD_DIR}/$${dir} || ${_NODE_DO_FAIL}; \ + done && \ + cd ${_NODE_FETCH_WORKDIR} && \ + ${_NODE_RM_TMP_DIR_FETCH} && \ + ${ECHO_MSG} "===> Removing redundant information from package.json for ${PKGNAME} ${_NODE_FETCH_DESCR}" && \ + ${FIND} ${_NODE_DIR} -name package.json -and -exec test -s {} \; -print0 | \ + ${XARGS} -0 -n1 -I @@ -S 10000 \ + ${SH} -c "${JQ_CMD} -s '.[0] | (del(.[\"scripts\"]) \ + * ((select(.scripts.preinstall) | {scripts:{preinstall: .scripts.preinstall}}) // { }) \ + * ((select(.scripts.install) | {scripts:{install: .scripts.install}}) // { }) \ + * ((select(.scripts.postinstall) | {scripts:{postinstall: .scripts.postinstall}}) // { })) \ + | del(.[\"scripts\"] | select(length==0)) \ + | del(.[\"man\"])' \ + @@ > @@.new && ${MV} @@.new @@" && \ + ${ECHO_MSG} "===> Packaging the final distfile for ${PKGNAME} ${_NODE_FETCH_DESCR}" && \ + ${FIND} -d ${_NODE_DIR} -and -exec ${TOUCH} -h -m -a -d 1970-01-01T00:00:00Z {} \; && \ + ${FIND} ${_NODE_DIR} -print0 | \ + LC_ALL=C sort -z | \ + ${_NODE_DISTRO_TAR_CMD} cf - \ + --no-recursion --null -T - | \ + ${_NODE_DISTRO_GZIP_CMD} -9n > ${NODE_DISTFILE} && \ + ${RM} -rf ${_NODE_DIR}; then \ + return 0; \ + fi; \ + ${_NODE_RM_TMP_DIR_FETCH} && \ + ${ECHO_MSG} "===> Fetch failed for ${PKGNAME}"; \ + ${FALSE}; \ + fi; + +do-extract: + @cd ${WRKDIR} && \ + ${TAR} xzf ${DISTDIR}/${NODE_DISTFILE} + +_USES_patch+= 750:patch-gyp-cflags +patch-gyp-cflags: + @${FIND} ${WRKSRC} -name "*.gyp" -and -exec ${REINPLACE_CMD} -i "" -e "s|cflags': \[|cflags': ['-I${LOCALBASE}/include/node',|g" {} \; + +node-npm-build: node-remind-debug-mode node-fakemake + @${ECHO} "===> NPM build for ${PKGNAME}" && \ + cd ${WRKSRC}/${_NODE_DO_CD} && \ + (cd ${_NODE_BUILD_DIR} && ! ${_NODE_PACKAGE_EXISTS} || ${NPM_ENV_BUILD} ${NPM_CMD} rebuild ${NPM_BUILD_ARGS}) && \ + for sp in ${NODE_SUB_PROJECTS}; do \ + ${ECHO} "===> NPM build for ${PKGNAME}/$${sp}" && \ + (cd $${sp} && ${NPM_ENV_BUILD} ${NPM_CMD} rebuild ${NPM_BUILD_ARGS}); \ + done && \ + ${_NODE_RM_TMP_DIR_BUILD} + +# uses-optional targets +.if defined(_NODE_USES_GRUNT) +node-grunt-build: + @${ECHO} "===> Grunt build for ${PKGNAME}" && \ + ${_NODE_MK_TMP_DIR_BUILD} && \ + cd ${WRKSRC}/${_NODE_DO_CD} && \ + ${GRUNT_ENV} ${GRUNT_CMD} ${NODE_GRUNT_TARGETS} ${GRUNT_BUILD_ARGS} && \ + ${_NODE_RM_TMP_DIR_BUILD} +node-opt-grunt-build: node-grunt-build +.else +node-opt-grunt-build: +.endif + +.if defined(_NODE_USES_RM_COFFEE) +node-rm-coffee: + @${ECHO} "===> Removing coffee from ${PKGNAME}" && \ + ${FIND} ${WRKSRC} -name "*.coffee" -and -exec test -f {} \; -and -exec ${SH} -c 'f="{}"; test -f $${f%%.coffee}.js && ${RM} $$f' \; + +node-opt-rm-coffee: node-rm-coffee +.else +node-opt-rm-coffee: +.endif + +.if !target(do-pre-build) +do-pre-build: +.endif +.if !target(do-post-build) +do-post-build: +.endif + +# TODO npm-clean ? +node-npm-prune: + @${ECHO} "===> Pruning for ${PKGNAME}" && \ + ${_NODE_MK_TMP_DIR_BUILD} && \ + cd ${WRKSRC}/${_NODE_DO_CD} && \ + (! ${_NODE_PACKAGE_EXISTS} || ${NPM_ENV_BUILD} ${NPM_CMD} prune ${NPM_PRUNE_ARGS}) && \ + for sp in ${NODE_SUB_PROJECTS}; do \ + (cd $${sp} && ${NPM_ENV_BUILD} ${NPM_CMD} prune ${NPM_PRUNE_ARGS}) || ${_NODE_DO_FAIL}; \ + done && \ + ${_NODE_RM_TMP_DIR_BUILD} + +node-npm-dedupe: + @${ECHO} "===> Deduping for ${PKGNAME}" && \ + ${_NODE_MK_TMP_DIR_BUILD} && \ + cd ${WRKSRC}/${_NODE_DO_CD} && \ + (! ${_NODE_PACKAGE_EXISTS} || ${NPM_ENV_BUILD} ${NPM_CMD} dedupe ${NPM_DEDUPE_ARGS}) && \ + for sp in ${NODE_SUB_PROJECTS}; do \ + (cd $${sp} && ${NPM_ENV_BUILD} ${NPM_CMD} dedupe ${NPM_DEDUPE_ARGS}) || ${_NODE_DO_FAIL}; \ + done && \ + ${_NODE_RM_TMP_DIR_BUILD} + +node-clean-files: + @${ECHO} "===> Cleaning files for ${PKGNAME}" && \ + cd ${WRKSRC}/${_NODE_DO_CD} && \ + for f in ${NODE_FILES_TO_CLEAN}; do \ + ${FIND} -d . -name "$${f}" -and -exec ${RM} -rf {} \;; \ + done && \ + ${FIND} -d . -type d -empty -exec rmdir {} \; + +node-do-build: do-pre-build node-npm-build node-opt-grunt-build do-post-build node-npm-prune node-clean-files node-opt-rm-coffee + +.if !target(do-build) +do-build: node-do-build +.endif + +_USES_build+= 751:delete-gyp-pyc +delete-gyp-pyc: + @${ECHO} "===> Deleting created .pyc files that npm should have installed" + @${RM} -rf `${FIND} ${LOCALBASE}/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp -name "*.pyc"` + +# we implement auto-plist feature +add-plist-post: + @${ECHO} "===> Generating plist for ${PKGNAME}" + @${FIND} ${STAGEDIR} -type f -or -type l | \ + ${SED} -e "s|^${STAGEDIR}${LOCALBASE}/||" | \ + ${SED} -e "s|^share/licenses/.*$$||" | \ + ${GREP} -v -e "^$$" \ + >> ${TMPPLIST} + +node-do-install: + @${ECHO} "===> Staging for ${PKGNAME}" + @${MKDIR} ${STAGEDIR}${NODE_INSTALL_BASE} + @${CP} -r ${WRKSRC} ${STAGEDIR}${NODE_INSTALL_DIR} + @${RM} `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name "*.orig"` + @${RM} `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name ${_NODE_SHRINKWRAP_NAME}` + @${RM} -rf `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name .deps` + @${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name "*.o" -and -exec ${STRIP_CMD} {} \; + @${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name "*.node" -and -exec ${STRIP_CMD} {} \; + @${FIND} -d ${STAGEDIR}${NODE_INSTALL_DIR} -type d -empty -delete +.for cmd in ${NODE_CMDS} + @${MKDIR} ${STAGEDIR}${PREFIX}/${cmd:C/.*\://:C/\/[a-zA-Z0-9_-]+$//} + @${LN} -s ${NODE_INSTALL_BASE}/${cmd:C/\:.*//} ${STAGEDIR}${PREFIX}/${cmd:C/.*\://} +.endfor + +.if !target(do-install) +do-install: node-do-install +.endif + +.endif