--- Mk2/Uses/nodejs.mk 1969-12-31 16:00:00.000000000 -0800 +++ Mk2/Uses/nodejs.mk 2015-11-29 23:27:39.250851000 -0800 @@ -0,0 +1,303 @@ +# $FreeBSD$ +# +# Provide support for NodeJS based projects +# +# Feature: node +# Usage: USES=nodejs +# +# MAINTAINER: portmgr@FreeBSD.org + +.if !defined(_INCLUDE_USES_NODE_MK) +_INCLUDE_USES_NODE_MK= yes + +FETCH_DEPENDS= npm:${PORTSDIR}/www/npm +BUILD_DEPENDS= npm:${PORTSDIR}/www/npm \ + gmake:${PORTSDIR}/devel/gmake +RUN_DEPENDS= node:${PORTSDIR}/www/node + +.if defined(NODE_MODULES) +FETCH_DEPENDS+= jq:${PORTSDIR}/textproc/jq +JQ_CMD= ${LOCALBASE}/bin/jq +.endif + +_NODE_DIR?= ${PORTNAME}-${PORTVERSION} + +# commands +NPM_CMD= ${LOCALBASE}/bin/npm +NODE_CMD= ${LOCALBASE}/bin/node + +# variables +_NODE_PROFILE_DIR= ${WRKDIR}/.userprofile +_NODE_TMP_DIR= ${WRKDIR}/.tmp +_NODE_FAKE_GIT= ${_NODE_TMP_DIR}/fake-git +_NODE_FAKE_MAKE= ${_NODE_TMP_DIR}/gmake +_NODE_NPMRC= ${_NODE_PROFILE_DIR}/.npmrc +CFLAGS+= -I${LOCALBASE}/include/node +CXXFLAGS+= -I${LOCALBASE}/include/node +NPM_ENV+= HOME=${_NODE_PROFILE_DIR} TMP=${_NODE_TMP_DIR} +NPM_ENV+= PATH=${_NODE_TMP_DIR}:${PATH} +NPM_ENV+= C=${CC} CXX=${CXX} +NPM_FETCH_ARGS= --loglevel warn --ignore-scripts +NPM_BUILD_ARGS= --loglevel warn --nodedir=${LOCALBASE} +NPM_PRUNE_ARGS= --loglevel warn --production=true +NPM_SHRINKWRAP_ARGS= --dev +REINPLACE_ARGS= -i "" +SHRINKWRAP_FILE= ${FILESDIR}/npm-shrinkwrap.json +NODE_INSTALL_BASE:= ${LOCALBASE}/share/node-projects +NODE_INSTALL_DIR:= ${NODE_INSTALL_BASE}/${PORTNAME} +NODE_ORIG_DISTFILES:= ${DISTFILES} +NODE_DISTFILE:= ${PORTNAME}-${PORTVERSION}-nodejs.tar.gz +CKSUMFILES+= ${NODE_DISTFILE} +_NODE_MASTER_SITE_BACKUP_URLS= ${MASTER_SITE_BACKUP}${NODE_DISTFILE} + +.if defined(NODE_SRCDIR) +_NODE_DO_CD=node_modules/${NODE_SUBDIR} +.else +_NODE_DO_CD=. +.endif +_NODE_FETCH_WORKDIR=${DISTDIR} + +makeshrinkwrap: do-fetch + @cd ${_NODE_FETCH_WORKDIR}; \ + for distfile in ${NODE_DISTFILE}; do \ + break; \ + done; \ + ${TAR} xzf $$distfile && \ + cd ${_NODE_DIR} && \ + cd ${_NODE_DO_CD} && \ + ${NPM_ENV} ${NPM_CMD} shrinkwrap ${NPM_SHRINKWRAP_ARGS} && \ + ${MKDIR} ${FILESDIR} && \ + ${MV} npm-shrinkwrap.json ${SHRINKWRAP_FILE} && \ + cd ${_NODE_FETCH_WORKDIR} && \ + ${RM} -r ${_NODE_DIR} + +userprofile_fetch: .EXEC .PHONY + @${RM} -rf ${_NODE_PROFILE_DIR} ${_NODE_TMP_DIR} + @${MKDIR} ${_NODE_PROFILE_DIR} ${_NODE_TMP_DIR} + +userprofile_build: .EXEC .PHONY + @${RM} -rf ${_NODE_PROFILE_DIR} ${_NODE_TMP_DIR} + @${MKDIR} ${_NODE_PROFILE_DIR} ${_NODE_TMP_DIR} + +fakegit: .EXEC .PHONY + @(${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} '*)'; \ + ${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} + +fakemake: .EXEC .PHONY + @(${ECHO} '#!/bin/sh'; \ + ${ECHO} ''; \ + ${ECHO} '${MAKE_ENV} PATH=$$PATH:${LOCALBASE}/bin ${LOCALBASE}/bin/gmake ${MAKE_ARGS} $$@'; \ + ${ECHO} '') >> ${_NODE_FAKE_MAKE} + @${CHMOD} +x ${_NODE_FAKE_MAKE} + +post-fetch: userprofile_fetch fakegit + @${MKDIR} ${_NODE_FETCH_WORKDIR} + @cd ${_NODE_FETCH_WORKDIR}; \ + for main_distfile in ${NODE_ORIG_DISTFILES}; do \ + break; \ + done; \ + 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_PROJECT_FILE} ${_NODE_DIR} ${NODE_DISTFILE}; \ + 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; \ + if ${ECHO_MSG} "=> Extracting node project source (in `pwd`)" && \ + ${EXTRACT_CMD} ${EXTRACT_BEFORE_ARGS} $${main_distfile} ${EXTRACT_AFTER_ARGS} && \ + ${ECHO_MSG} "=> Preparing the node project (in `pwd`)" && \ + 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}; do \ + ${JQ_CMD} -s ".[0] * `${ECHO} $${m} | ${SED} -E 's/([[:alnum:]]+):([[:digit:].]+)/{"dependencies":{"\1":"\2"}}/'`" \ + package.json > package-new.json && ${MV} package-new.json package.json; \ + done && \ + ([ -f "${SHRINKWRAP_FILE}" ] || \ + ${ECHO} "Warning: no shrinkwrap file, you need to run 'make makeshrinkwrap'" >&2) && \ + ([ ! -f "${SHRINKWRAP_FILE}" ] || \ + ${CP} ${SHRINKWRAP_FILE} npm-shrinkwrap.json) && \ + ${ECHO_MSG} "=> Downloading the project dependencies (in `pwd`)" && \ + ${NPM_ENV} ${NPM_CMD} install ${NPM_FETCH_ARGS} && \ + cd ${_NODE_FETCH_WORKDIR} && \ + ${FIND} ${_NODE_DIR} -and -exec ${TOUCH} -h -d 1970-01-01T00:00:00Z {} + && \ + ${FIND} ${_NODE_DIR} -print0 | sort -z | \ + ${TAR} czf ${NODE_DISTFILE} --options gzip:!timestamp --no-recursion --null -T - && \ + ${RM} -rf ${_NODE_DIR}; then \ + return 0; \ + fi; \ + ${ECHO_MSG} "=> Fetch failed for ${PORTNAME}"; \ + exit 1; \ + fi; + +do-extract: + @cd ${WRKDIR} && \ + tar xzf ${DISTDIR}/${NODE_DISTFILE} + +post-patch: + @${FIND} ${WRKSRC} -name "*.gyp" -and -exec ${REINPLACE_CMD} -e "s|cflags': \[|cflags': ['-I${LOCALBASE}/include/node',|g" {} \; + +npm-build: userprofile_build fakemake + @cd ${WRKSRC} && \ + cd ${_NODE_DO_CD} && \ + ${NPM_ENV} ${NPM_CMD} rebuild ${NPM_BUILD_ARGS} + +npm-prune: + @cd ${WRKSRC} && \ + cd ${_NODE_DO_CD} && \ + ${NPM_ENV} ${NPM_CMD} prune ${NPM_PRUNE_ARGS} + +do-build: npm-build npm-prune + +post-build: + @${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"` + +do-install: + @${ECHO} "=> Staging ${PKGNAME}" + @${MKDIR} ${STAGEDIR}${NODE_INSTALL_BASE} + @${CP} -r ${WRKSRC} ${STAGEDIR}${NODE_INSTALL_DIR} + @${RM} `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name Makefile` + @${RM} `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name "*.bat"` + @${RM} `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name "*.log"` + @${RM} `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name "*.orig"` + @${RM} `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name "*.bak"` + @${RM} `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name ".git*"` + @${RM} `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name npm-shrinkwrap.json` + @${RM} -rf `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name Release` + @${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} {} \; + +.endif