View | Details | Raw Unified | Return to bug 204577 | Differences between
and this patch

Collapse All | Expand All

(-)Mk/Uses/nodejs.mk (+654 lines)
Line 0 Link Here
1
# $FreeBSD$
2
#
3
# Provide support for NodeJS based projects
4
#
5
# Feature:	nodejs
6
# Usage:	USES=nodejs
7
#
8
# MAINTAINER: portmgr@FreeBSD.org
9
10
# NODE_SUB_PROJECTS   - additional projects to extract into individual
11
#                       directories. Distfile for the group with the name
12
#                       of the sub-project is extracted into the sub-folder
13
#                       with the same name. Build is also performed for
14
#                       sub-projects.
15
# NODE_USES           - additional features enabled in nodejs module:
16
#               grunt   - run grunt tasks as a part of the build
17
#      merge-pkg-deps   - merge packageDependencies into dependencies in package.json
18
#           rm-coffee   - removes *.coffee files that have .js counterparts
19
# NODE_MODULES_ADD    - add node module dependencies in the format:
20
#                       [[{dev|peer|bundle}@]directory@]module:version
21
#                       It is also used to upgrade outdated package dependencies.
22
# NODE_MODULES_DEL    - delete node module dependencies in the format:
23
#                       [[{dev|peer|bundle}@]directory@]module
24
# NODE_FILES_TO_CLEAN - wildcards for files and directoroes that do not need to be installed
25
# NODE_SRCDIR         - (rare) subdirectory where the source is
26
# NODE_SUBDIR         - (rare) directory where NODE_SRCDIR is copied to
27
# NODE_RM_DIRS        - directories to delete
28
# NODE_CMDS           - commands to install in format src:dst, where src is based
29
#                       on NODE_INSTALL_BASE, and dst is based on LOCALBASE
30
31
# Port workflow:
32
# * It starts in the DEBUG mode. In DEBUG mode port can be built and run but
33
#   can't be committed. Developer can make changes to the port in the DEBUG mode.
34
# * 'make makerelease' - brings the port to RELEASE mode, when it can be committed
35
# * 'make makedebug'   - brings the port back to DEBUG mode in order to make changes
36
# * 'make printmode'   - prints the current mode of the port
37
# * 'make acceptplist' - rebuilds plist
38
# 
39
40
# NOTE: archivers/gtar is used to make the distfile because FreeBSD tar(1) has a bug
41
#       that prevents it from producing the deterministic output in certain situations
42
#       (https://github.com/libarchive/libarchive/pull/623)
43
# NOTE: some sections of package.json are deleted (ex. scripts/test) as a workaround
44
#       for the npm bug that causes package.json volatility
45
#       (https://github.com/npm/npm/issues/10406)
46
# NOTE: 'npm dedupe' operation is broken and is left disabled
47
#       (https://github.com/npm/npm/issues/10783)
48
49
.if !defined(_INCLUDE_USES_NODE_MK)
50
_INCLUDE_USES_NODE_MK=	yes
51
52
# dependencies
53
FETCH_DEPENDS+=		npm:${PORTSDIR}/www/npm \
54
			jq:${PORTSDIR}/textproc/jq \
55
			gtar:${PORTSDIR}/archivers/gtar
56
BUILD_DEPENDS+=		npm:${PORTSDIR}/www/npm \
57
			gmake:${PORTSDIR}/devel/gmake
58
RUN_DEPENDS+=		node:${PORTSDIR}/www/node
59
60
_NODE_DIR?=		${PORTNAME}-${PORTVERSION}
61
62
PORTREVISION?=	0
63
.if ${PORTREVISION} != 0
64
_NODE_SUF1=	_${PORTREVISION}
65
.endif
66
67
# commands
68
NPM_CMD?=		${LOCALBASE}/bin/npm
69
NODE_CMD?=		${LOCALBASE}/bin/node
70
GMAKE_CMD?=		${LOCALBASE}/bin/gmake
71
JQ_CMD?=		${LOCALBASE}/bin/jq
72
GTAR_CMD?=		${LOCALBASE}/bin/gtar
73
74
#_NODE_DISTRO_TAR_CMD=	${TAR}
75
_NODE_DISTRO_TAR_CMD=	${GTAR_CMD}
76
_NODE_DISTRO_GZIP_CMD=	gzip
77
78
# variables
79
_NODE_TMP_BASE_FETCH=	${DISTDIR}/${_NODE_DIR}.tmpdirs
80
_NODE_TMP_BASE_BUILD=	${WRKDIR}/.tmpdirs
81
_NODE_USERHOME_FETCH=	${_NODE_TMP_BASE_FETCH}/.userhome
82
_NODE_TMP_FETCH=	${_NODE_TMP_BASE_FETCH}/.tmp
83
_NODE_USERHOME_BUILD=	${_NODE_TMP_BASE_BUILD}/.userhome
84
_NODE_TMP_BUILD=	${_NODE_TMP_BASE_BUILD}/.tmp
85
_NODE_FAKE_GIT=		${_NODE_TMP_FETCH}/fake-git
86
_NODE_FAKE_GMAKE=	${_NODE_TMP_BUILD}/gmake
87
_NODE_NPMRC_FETCH=	${_NODE_USERHOME_FETCH}/.npmrc
88
_NODE_CR_TMP_DIR_FETCH=	${MKDIR} ${_NODE_USERHOME_FETCH} ${_NODE_TMP_FETCH}
89
_NODE_CR_TMP_DIR_BUILD=	${MKDIR} ${_NODE_USERHOME_BUILD} ${_NODE_TMP_BUILD}
90
_NODE_RM_TMP_DIR_FETCH=	${RM} -r ${_NODE_TMP_BASE_FETCH}
91
_NODE_RM_TMP_DIR_BUILD=	${RM} -r ${_NODE_TMP_BASE_BUILD}
92
_NODE_MK_TMP_DIR_FETCH=	${_NODE_RM_TMP_DIR_FETCH} && ${_NODE_CR_TMP_DIR_FETCH}
93
_NODE_MK_TMP_DIR_BUILD=	${_NODE_RM_TMP_DIR_BUILD} && ${_NODE_CR_TMP_DIR_BUILD}
94
# environment and arguments
95
CFLAGS+=		-I${LOCALBASE}/include/node
96
CXXFLAGS+=		-I${LOCALBASE}/include/node
97
NPM_ENV+=		C=${CC} CXX=${CXX}
98
NPM_ENV_FETCH=		${NPM_ENV} HOME=${_NODE_USERHOME_FETCH} TMP=${_NODE_TMP_FETCH} PATH=${_NODE_TMP_FETCH}:${PATH}
99
NPM_ENV_BUILD=		${NPM_ENV} HOME=${_NODE_USERHOME_BUILD} TMP=${_NODE_TMP_BUILD} PATH=${_NODE_TMP_BUILD}:${PATH}
100
NPM_LOG_LEVEL?=		warn
101
NPM_FETCH_ARGS=		--loglevel ${NPM_LOG_LEVEL} --ignore-scripts
102
NPM_BUILD_ARGS=		--loglevel ${NPM_LOG_LEVEL} --nodedir=${LOCALBASE}
103
NPM_PRUNE_ARGS=		--loglevel ${NPM_LOG_LEVEL} --production=true
104
NPM_DEDUPE_ARGS=	--loglevel ${NPM_LOG_LEVEL} --production=true
105
NPM_SHRINKWRAP_ARGS=	--dev
106
# internal variables
107
_NODE_PACKAGE_JSON=	package.json
108
_NODE_PACKAGE_EXISTS=	[ -f ${_NODE_PACKAGE_JSON} ]
109
_NODE_IS_RELEASE_MODE=	[ ${_NODE_DEBUG_MODE} = no ]
110
_NODE_IS_DEBUG_MODE=	[ ${_NODE_DEBUG_MODE} = yes ]
111
_NODE_SHRINKWRAP_NAME:=	npm-shrinkwrap.json
112
_NODE_SHRINKWRAP_FILE:=	${FILESDIR}/${_NODE_SHRINKWRAP_NAME}
113
_NODE_DO_FAIL=		return 1
114
_NODE_ORIG_DISTFILES:=	${DISTFILES}
115
_NODE_MASTER_SITE_BACKUP_URLS= ${MASTER_SITE_BACKUP}${NODE_DISTFILE}
116
_NODE_BUILD_DIR?=		.
117
.if defined(NODE_SRCDIR)
118
_NODE_DO_CD=		node_modules/${NODE_SUBDIR}
119
.else
120
_NODE_DO_CD=		.
121
.endif
122
_NODE_FETCH_WORKDIR=	${DISTDIR}
123
#
124
NODE_INSTALL_BASE?=	${LOCALBASE}/share/node-projects
125
NODE_INSTALL_DIR:=	${NODE_INSTALL_BASE}/${PORTNAME}
126
NODE_DISTFILE:=		${PORTNAME}-${PORTVERSION}${_NODE_SUF1}-nodejs.tar.gz
127
# variables to be used by ports
128
NODE_FILES_TO_CLEAN+=	.git* CVS .svn
129
NODE_FILES_TO_CLEAN+=	.lock-wscript .wafpickle-N *.swp .DS_Store ._* .editorconfig .eslintrc .jshintignore npm-debug.log bower.json
130
NODE_FILES_TO_CLEAN+=	*.bak *.log *.bat file .travis.yml man *.info .npmignore .jshintrc .jscsrc .bowerrc .dockerignore .mailmap
131
NODE_FILES_TO_CLEAN+=	CHANGELOG CHANGELOG.md HISTORY.md README README.* AUTHORS AUTHORS.* CONTRIBUTORS CONTRIBUTING.md HISTORY HISTORY.*
132
NODE_FILES_TO_CLEAN+=	Makefile *.mk *.cmake Dockerfile Vagrantfile Rakefile
133
134
CKSUMFILES+=		${NODE_DISTFILE}
135
WRKSRC=			${WRKDIR}/${_NODE_DIR}
136
137
.if ! exists(${_NODE_SHRINKWRAP_FILE})
138
NO_CHECKSUM=yes
139
_NODE_DEBUG_MODE=yes
140
node-remind-debug-mode:
141
	@${ECHO_CMD} "(!!!)"
142
	@${ECHO_CMD} "(!!!) Port ${PORTNAME} is in the DEBUG mode, run 'make makerelease' to finalize it"
143
	@${ECHO_CMD} "(!!!)"
144
node-assert-debug-mode: node-check-shrinkwrap-files
145
node-assert-release-mode: node-check-shrinkwrap-files
146
	@${ECHO} "(!!!)"
147
	@${ECHO} "(!!!) already in the DEBUG mode"
148
	@${ECHO} "(!!!)"
149
	@${FALSE}
150
node-print-mode: node-check-shrinkwrap-files
151
	@${ECHO} "Port ${PORTNAME} is in the DEBUG mode"
152
node-check-shrinkwrap-files:
153
	@for sp in ${NODE_SUB_PROJECTS}; do \
154
	  if [ -f ${FILESDIR}/$${sp}/${_NODE_SHRINKWRAP_NAME} ]; then \
155
	    ${ECHO} "(!!!) ERROR: shrinkwrap file for sub-project $${sp} exists in DEBUG mode!"; \
156
	    ${FALSE}; \
157
	  fi; \
158
	done
159
.else
160
_NODE_DEBUG_MODE=no
161
node-remind-debug-mode:
162
node-assert-debug-mode: node-check-shrinkwrap-files
163
	@${ECHO} "(!!!)"
164
	@${ECHO} "(!!!) already in RELEASE mode"
165
	@${ECHO} "(!!!)"
166
	@${FALSE}
167
node-assert-release-mode: node-check-shrinkwrap-files
168
node-print-mode: node-check-shrinkwrap-files
169
	@${ECHO} "Port ${PORTNAME} is in the RELEASE mode"
170
node-check-shrinkwrap-files:
171
	@for sp in ${NODE_SUB_PROJECTS}; do \
172
	  if ! [ -f ${FILESDIR}/$${sp}/${_NODE_SHRINKWRAP_NAME} ]; then \
173
	    ${ECHO} "(!!!) ERROR: shrinkwrap file for sub-project $${sp} is missing!"; \
174
	    ${_NODE_DO_FAIL}; \
175
	  fi; \
176
	done
177
.endif
178
179
# uses
180
.for f in ${NODE_USES}
181
_f:=	${f:C/\:.*//}
182
.if ${_f}=="grunt"
183
FETCH_DEPENDS+=		grunt:${PORTSDIR}/devel/grunt
184
GRUNT_CMD?=		${LOCALBASE}/bin/grunt
185
GRUNT_ENV+=		HOME=${_NODE_USERHOME_BUILD} TMP=${_NODE_TMP_BUILD} PATH=${_NODE_TMP_BUILD}:${PATH}
186
GRUNT_BUILD_ARGS+=
187
NODE_GRUNT_TARGETS?=
188
_NODE_USES_GRUNT=	yes
189
.elif ${_f}=="merge-pkg-deps"
190
_NODE_USES_MERGE_PKG_DEPS=	yes
191
.elif ${_f}=="rm-coffee"
192
_NODE_USES_RM_COFFEE=	yes
193
.else
194
.  error Unknown NODE_USES value.
195
.endif
196
.endfor
197
198
# exported development mode targets
199
makerelease: node-assert-debug-mode node-delete-distfile clean fetch node-make-shrinkwrap node-post-make-shrinkwrap
200
makedebug: node-assert-release-mode node-delete-shrinkwrap
201
printmode: node-print-mode
202
acceptplist: node-accept-plist
203
204
# internal targets
205
node-accept-plist: stage
206
	@${MAKE} makeplist | tail -n +2 > pkg-plist
207
node-delete-distfile:
208
	@${RM} -f ${_NODE_FETCH_WORKDIR}/${NODE_DISTFILE}
209
210
node-make-shrinkwrap:
211
	@${ECHO} "===>  Making npm-shrinkwrap set to freeze the component versions for ${PKGNAME}"
212
	@createWithNpm() { \
213
	  ${NPM_ENV_FETCH} ${NPM_CMD} shrinkwrap ${NPM_SHRINKWRAP_ARGS}; \
214
	}; \
215
	createOne() { \
216
	  local dir=$$1; \
217
	  (for subdir in $$([ -d $${dir}/node_modules ] && cd $${dir}/node_modules && ls | sort | grep -v "^\."); do \
218
	    local deps=$$(createOne "$${dir}/node_modules/$${subdir}"); \
219
	    ${JQ_CMD} -s 'map({(.name): ({version, from: "\(.name)@=\(.version)", resolved: ._resolved} \
220
	                                *({dependencies: '"$$deps"'}|select(.dependencies!=null)//{}))})[]' \
221
	      "$${dir}/node_modules/$${subdir}/package.json"; \
222
	  done) | ${JQ_CMD} -s 'add'; \
223
	}; \
224
	createWithJq() { \
225
	  (${JQ_CMD} '{name,version}' package.json && (createOne . | ${JQ_CMD} -s 'add|{"dependencies":.}')) | ${JQ_CMD} -s 'add' > npm-shrinkwrap.json; \
226
	}; \
227
	${_NODE_MK_TMP_DIR_FETCH} && \
228
	cd ${_NODE_FETCH_WORKDIR} && \
229
	${RM} -rf ${_NODE_DIR} && \
230
	${EXTRACT_CMD} ${EXTRACT_BEFORE_ARGS} ${NODE_DISTFILE} ${EXTRACT_AFTER_ARGS} && \
231
	cd ${_NODE_DIR}/${_NODE_DO_CD} && \
232
	(cd ${_NODE_BUILD_DIR} && \
233
	  createWithJq && \
234
	  ${MKDIR} ${FILESDIR} && \
235
	  ${MV} ${_NODE_SHRINKWRAP_NAME} ${_NODE_SHRINKWRAP_FILE}) && \
236
	for sp in ${NODE_SUB_PROJECTS}; do \
237
	  (cd $${sp} && \
238
	    createWithJq && \
239
	    ${MKDIR} ${FILESDIR}/$${sp} && \
240
	    ${MV} ${_NODE_SHRINKWRAP_NAME} ${FILESDIR}/$${sp}/) || ${_NODE_DO_FAIL}; \
241
	done && \
242
	cd ${_NODE_FETCH_WORKDIR} && \
243
	${_NODE_RM_TMP_DIR_FETCH} && \
244
	${RM} -r ${_NODE_DIR}
245
246
node-delete-dist-file:
247
	@cd ${_NODE_FETCH_WORKDIR} && \
248
	${RM} ${NODE_DISTFILE}
249
250
node-post-make-shrinkwrap: node-delete-dist-file node-enter-release-mode-msg node-refetch-for-release-mode node-in-release-mode-msg
251
252
node-enter-release-mode-msg:
253
	@${ECHO} "%%%"
254
	@${ECHO} "%%% shrinkwrap file(s) have been generated, entering RELEASE mode"
255
	@${ECHO} "%%%"
256
257
node-refetch-for-release-mode:
258
	@${ECHO} "==>  Re-fetching with shrinkwrap in RELEASE mode" && \
259
	_NODE_FETCH_DESCR="(re-fetch with shrinkwrap)" ${MAKE} fetch
260
261
node-in-release-mode-msg:
262
	@${ECHO} "%%%"
263
	@${ECHO} "%%% in RELEASE mode now, run 'make makesum'"
264
	@${ECHO} "%%%"
265
266
node-delete-shrinkwrap: node-assert-release-mode
267
	@${RM} -f `${FIND} ${FILESDIR} -name ${_NODE_SHRINKWRAP_NAME}`
268
	@${ECHO} "%%%"
269
	@${ECHO} "%%% shrinkwrap file(s) have been deleted, entering DEBUG mode"
270
	@${ECHO} "%%%"
271
272
node-fakegit: .EXEC .PHONY
273
	@${_NODE_MK_TMP_DIR_FETCH} && \
274
	(${ECHO} '#!/bin/sh'; \
275
	${ECHO} ''; \
276
	${ECHO} 'name="nodejs-fetch"'; \
277
	${ECHO} 'DISTDIR="${DISTDIR}"'; \
278
	${ECHO} 'NODE_ORIG_DISTFILES="${_NODE_ORIG_DISTFILES:C@^([^:]+).*@\1@}"'; \
279
	${ECHO} 'NODE_VERBOSE="${NODE_VERBOSE}"'; \
280
	${ECHO} 'NODE_DEBUG="${NODE_DEBUG}"'; \
281
	${ECHO} ''; \
282
	${ECHO} 'msg() {'; \
283
	${ECHO} '  [ "$$NODE_VERBOSE" = yes ] && echo "$${name}: $$1" >&2'; \
284
	${ECHO} '  dbg_log "$${name}: $$1"'; \
285
	${ECHO} '}'; \
286
	${ECHO} 'err() {'; \
287
	${ECHO} '  echo "$${name}: ERROR: $$1" >&2'; \
288
	${ECHO} '  dbg_log "$${name}: ERROR: $$1"'; \
289
	${ECHO} '}'; \
290
	${ECHO} 'dbg_log() {'; \
291
	${ECHO} '  [ "$$NODE_DEBUG" = yes ] && (echo "$$1" >>/tmp/nodejs-$$$$.log)'; \
292
	${ECHO} '}'; \
293
	${ECHO} ''; \
294
	${ECHO} 'dbg_log "called with arguments: $$*"'; \
295
	${ECHO} ''; \
296
	${ECHO} 'cmd_clone_remote() {'; \
297
	${ECHO} '  local mirror="$$1"'; \
298
	${ECHO} '  local dir="$$2"'; \
299
	${ECHO} '  msg "Git clone requested: mirror=$$mirror -> dir=$${dir}"'; \
300
	${ECHO} '  local fname_regex=$$(echo $$mirror | sed -E "s/https:\/\/github\.com\/([^/]+)\/([^/]+)\.git$$/^\1-\2-[[:alnum:].]*_GH0.tar.gz$$/g")'; \
301
	${ECHO} '  local fname=$$(find_file "$${fname_regex}")'; \
302
	${ECHO} '  if [ -n "$${fname}" ]; then'; \
303
	${ECHO} '    msg "Found distfile=$$fname for $$mirror"'; \
304
	${ECHO} '    (cd $${dir} && tar xzf $${DISTDIR}/$${fname} --strip 1)'; \
305
	${ECHO} '    return $$?'; \
306
	${ECHO} '  else'; \
307
	${ECHO} '    err "Failed to find distfile for $$mirror"'; \
308
	${ECHO} '    return 1'; \
309
	${ECHO} '  fi'; \
310
	${ECHO} '}'; \
311
	${ECHO} 'cmd_clone_local() {'; \
312
	${ECHO} '  local src="$$1"'; \
313
	${ECHO} '  local dst="$$2"'; \
314
	${ECHO} '  msg "copy $$src -> $$dst"'; \
315
	${ECHO} '  (cd $${src} && tar czf - .) | (cd $${dst} && tar xzf -)'; \
316
	${ECHO} '}'; \
317
	${ECHO} ''; \
318
	${ECHO} 'cmd_checkout() {'; \
319
	${ECHO} '  msg "do nothing for checkout of $$1 in `pwd`"'; \
320
	${ECHO} '}'; \
321
	${ECHO} ''; \
322
	${ECHO} 'find_file() {'; \
323
	${ECHO} '  for f in $${NODE_ORIG_DISTFILES}; do'; \
324
	${ECHO} '    if expr "$${f}" : "$${fname_regex}" > /dev/null; then'; \
325
	${ECHO} '      echo "$$f"'; \
326
	${ECHO} '      return'; \
327
	${ECHO} '    fi'; \
328
	${ECHO} '  done'; \
329
	${ECHO} '}'; \
330
	${ECHO} ''; \
331
	${ECHO} 'case $$1 in'; \
332
	${ECHO} 'clone)'; \
333
	${ECHO} '  shift'; \
334
	${ECHO} '  while [ $$# -gt 0 ]; do'; \
335
	${ECHO} '    key="$$1"'; \
336
	${ECHO} '    case $$key in'; \
337
	${ECHO} '        --template=*)'; \
338
	${ECHO} '      ;;'; \
339
	${ECHO} '      --mirror)'; \
340
	${ECHO} '        MIRROR="$$2"'; \
341
	${ECHO} '        shift'; \
342
	${ECHO} '      ;;'; \
343
	${ECHO} '      -*)'; \
344
	${ECHO} '        err "Unknown argument: $$key" && exit 1'; \
345
	${ECHO} '      ;;'; \
346
	${ECHO} '      *)'; \
347
	${ECHO} '        if [ $$# -eq 1 -a -n "$$MIRROR" ]; then'; \
348
	${ECHO} '          cmd_clone_remote "$${MIRROR}" "$$key"'; \
349
	${ECHO} '          exit $$?'; \
350
	${ECHO} '        fi'; \
351
	${ECHO} '        if [ $$# -eq 2 -a -z "$$MIRROR" ]; then'; \
352
	${ECHO} '          cmd_clone_local "$$1" "$$2"'; \
353
	${ECHO} '          exit $$?'; \
354
	${ECHO} '        fi'; \
355
	${ECHO} '        err "Unknown argument #=$$#: $$key"'; \
356
	${ECHO} '        exit 1'; \
357
	${ECHO} '      ;;'; \
358
	${ECHO} '    esac'; \
359
	${ECHO} '    shift'; \
360
	${ECHO} '  done'; \
361
	${ECHO} '  ;;'; \
362
	${ECHO} 'rev-list)'; \
363
	${ECHO} '  shift'; \
364
	${ECHO} '  while [ $$# -gt 0 ]; do'; \
365
	${ECHO} '    key="$$1"'; \
366
	${ECHO} '    case $$key in'; \
367
	${ECHO} '      -n1)'; \
368
	${ECHO} '        shift'; \
369
	${ECHO} '        [ $$# -eq 1 ] || ! err "Unknown argument: $$key" || exit 1'; \
370
	${ECHO} '        msg "Returning same revision $$1"'; \
371
	${ECHO} '        echo $$1'; \
372
	${ECHO} '        exit 0'; \
373
	${ECHO} '      ;;'; \
374
	${ECHO} '      *)'; \
375
	${ECHO} '        err "Unknown argument: $$key" && exit 1'; \
376
	${ECHO} '      ;;'; \
377
	${ECHO} '    esac'; \
378
	${ECHO} '    shift'; \
379
	${ECHO} '  done'; \
380
	${ECHO} '  err "rev-list without arguments" && exit 1'; \
381
	${ECHO} '  ;;'; \
382
	${ECHO} 'checkout)'; \
383
	${ECHO} '  shift'; \
384
	${ECHO} '  if [ $$# -eq 1 ]; then'; \
385
	${ECHO} '    cmd_checkout "$$1"'; \
386
	${ECHO} '    exit 0'; \
387
	${ECHO} '  fi'; \
388
	${ECHO} '  ;;'; \
389
	${ECHO} 'config)'; \
390
	${ECHO} '  echo ""'; \
391
	${ECHO} '  ;;'; \
392
	${ECHO} '*)'; \
393
	${ECHO} '  err "Unknown command: $$1" && exit 1'; \
394
	${ECHO} '  ;;'; \
395
	${ECHO} 'esac'; \
396
	${ECHO} '') > ${_NODE_FAKE_GIT}
397
	@${CHMOD} +x ${_NODE_FAKE_GIT}
398
	@${ECHO} "git = ${_NODE_FAKE_GIT}" >> ${_NODE_NPMRC_FETCH}
399
400
node-fakemake: .EXEC .PHONY
401
	@${_NODE_MK_TMP_DIR_BUILD} && \
402
	(${ECHO} '#!/bin/sh'; \
403
	${ECHO} ''; \
404
	${ECHO} '${MAKE_ENV} PATH=$$PATH:${LOCALBASE}/bin ${GMAKE_CMD} ${MAKE_ARGS} $$@'; \
405
	${ECHO} '') >> ${_NODE_FAKE_GMAKE}
406
	@${CHMOD} +x ${_NODE_FAKE_GMAKE}
407
408
# XXX need this?
409
.if !target(nodejs-patch-fetch)
410
nodejs-patch-fetch:
411
.endif
412
413
_USES_fetch+= 750:node-npm-fetch
414
node-npm-fetch: node-fakegit
415
	@${MKDIR} ${_NODE_FETCH_WORKDIR}
416
	@cd ${_NODE_FETCH_WORKDIR}; \
417
	force_fetch=false; \
418
	for afile in ${FORCE_FETCH}; do \
419
	  afile=$${afile##*/}; \
420
	  if [ "x$$afile" = "x${NODE_DISTFILE}" ]; then \
421
	    force_fetch=true; \
422
	  fi; \
423
	done; \
424
	if [ ! -f ${NODE_DISTFILE} -o "$$force_fetch" = "true" ]; then \
425
	  ${RM} -rf ${_NODE_DIR} ${NODE_DISTFILE}; \
426
	  if ${_NODE_IS_RELEASE_MODE}; then \
427
	    for url in ${_NODE_MASTER_SITE_BACKUP_URLS}; do \
428
	      if ${ECHO_MSG} "===>  Attempting to fetch ${PORTNAME} from the master backup site" && \
429
	        ${SETENV} ${FETCH_ENV} ${FETCH_CMD} ${FETCH_BEFORE_ARGS} $${url} ${FETCH_AFTER_ARGS}; then \
430
	        return 0; \
431
	      fi; \
432
	    done; \
433
	  fi && \
434
	  if ${ECHO_MSG} "===>  Extracting node project source for ${PKGNAME} ${_NODE_FETCH_DESCR}" && \
435
	     ${MKDIR} ${_NODE_DIR} && \
436
	     for main_distfile in ${_NODE_ORIG_DISTFILES:N*\:*}; do \
437
	       ${EXTRACT_CMD} ${EXTRACT_BEFORE_ARGS} $${main_distfile} ${EXTRACT_AFTER_ARGS} \
438
	           -C ${_NODE_DIR} --strip 1 || ${_NODE_DO_FAIL}; \
439
	     done && \
440
	     for sp in ${NODE_SUB_PROJECTS}; do \
441
	       for df in `${ECHO} ${_NODE_ORIG_DISTFILES} | tr ' ' '\n' | grep :$${sp}$$`; do \
442
	         ${MKDIR} ${_NODE_DIR}/$${sp} && \
443
	         ${EXTRACT_CMD} ${EXTRACT_BEFORE_ARGS} ${DISTDIR}/`${ECHO} $${df} | ${SED} -e 's/:[^:]*$$//g'` ${EXTRACT_AFTER_ARGS} \
444
	           -C ${_NODE_DIR}/$${sp} --strip 1 || ${_NODE_DO_FAIL}; \
445
	       done; \
446
	     done && \
447
	     (cd ${_NODE_DIR} && ${MAKE} -f ${MASTERDIR}/Makefile nodejs-patch-fetch) && \
448
	     ${ECHO_MSG} "===>  Preparing the node project for ${PKGNAME} ${_NODE_FETCH_DESCR}" && \
449
	     cd ${_NODE_DIR} && \
450
	     ([ -z "${NODE_SRCDIR}" ] || \
451
	        (${MKDIR} node_modules && \
452
	         ${MV} ${NODE_SRCDIR} node_modules/${NODE_SUBDIR} \
453
	        ) \
454
	     ) && cd ${_NODE_DO_CD} && \
455
	     for m in ${NODE_MODULES_ADD}; do \
456
	       if expr $$m : ".*@.*@.*" > /dev/null ; then \
457
	         mloc=$${m%@*@*}; \
458
	         mdir=$${m%@*}; \
459
	         mdir=$${mdir#*@}; \
460
	         mmod=$${m#*@*@}; \
461
	       elif expr $$m : ".*@.*" > /dev/null ; then \
462
	         mloc=dependencies; \
463
	         mdir=$${m%@*}; \
464
	         mmod=$${m#*@}; \
465
	       else \
466
	         mloc=dependencies; \
467
	         mdir=.; \
468
	         mmod=$$m; \
469
	       fi && \
470
	       mloc=$$(${ECHO} $$mloc | ${SED} -E 's/^(dev|peer|bundle)$$/\1Dependencies/') && \
471
	       (cd $$mdir && ${JQ_CMD} -s ".[0] * `echo $$mmod | sed -E 's/^([[:alnum:]_-]+):(.+)$$/{"'$$mloc'":{"\\1":"\\2"}}/'`" \
472
	         package.json > package.json.new && ${MV} package.json.new package.json) || ${_NODE_DO_FAIL}; \
473
	     done && \
474
	     for m in ${NODE_MODULES_DEL}; do \
475
	       if expr $$m : ".*@.*@.*" > /dev/null ; then \
476
	         mloc=$${m%@*@*}; \
477
	         mdir=$${m%@*}; \
478
	         mdir=$${mdir#*@}; \
479
	         mmod=$${m#*@*@}; \
480
	       elif expr $$m : ".*@.*" > /dev/null ; then \
481
	         mloc=dependencies; \
482
	         mdir=$${m%@*}; \
483
	         mmod=$${m#*@}; \
484
	       else \
485
	         mloc=dependencies; \
486
	         mdir=.; \
487
	         mmod=$$m; \
488
	       fi && \
489
	       mloc=$$(${ECHO} $$mloc | ${SED} -E 's/^(dev|peer|bundle)$$/\1Dependencies/') && \
490
	       (cd $$mdir && ${JQ_CMD} -s ".[0] | del(.[\"$$mloc\"][\"$$mmod\"])" \
491
	         package.json > package.json.new && ${MV} package.json.new package.json) || ${_NODE_DO_FAIL}; \
492
	     done && \
493
	     ([ -z ${_NODE_USES_MERGE_PKG_DEPS} ] || \
494
	       (${JQ_CMD} -s '(.[0] | del(.["packageDependencies"])) * (.[0]["packageDependencies"] | {"dependencies": .})' \
495
	         package.json > package.json.new && ${MV} package.json.new package.json)) && \
496
	     if ${_NODE_IS_RELEASE_MODE}; then \
497
	       ${CP} ${_NODE_SHRINKWRAP_FILE} . && \
498
	       for sp in ${NODE_SUB_PROJECTS}; do \
499
	         (cd $${sp} && ${CP} ${FILESDIR}/$${sp}/${_NODE_SHRINKWRAP_NAME} .) || ${_NODE_DO_FAIL}; \
500
	       done; \
501
	     fi && \
502
	     ${ECHO_MSG} "===>  Downloading the nodejs dependencies for ${PKGNAME} ${_NODE_FETCH_DESCR}" && \
503
	     (cd ${_NODE_BUILD_DIR} && ! ${_NODE_PACKAGE_EXISTS} || ${NPM_ENV_FETCH} ${NPM_CMD} install ${NPM_FETCH_ARGS}) && \
504
	     for sp in ${NODE_SUB_PROJECTS}; do \
505
	       ${ECHO_MSG} "===>  Downloading the nodejs dependencies for ${PKGNAME}/$${sp} ${_NODE_FETCH_DESCR}" && \
506
	       (cd $${sp} && ${NPM_ENV_FETCH} ${NPM_CMD} install ${NPM_FETCH_ARGS}) || ${_NODE_DO_FAIL}; \
507
	     done && \
508
	     for dir in ${NODE_RM_DIRS}; do \
509
	       ${RM} -r ${_NODE_BUILD_DIR}/$${dir} || ${_NODE_DO_FAIL}; \
510
	     done && \
511
	     cd ${_NODE_FETCH_WORKDIR} && \
512
	     ${_NODE_RM_TMP_DIR_FETCH} && \
513
	     ${ECHO_MSG} "===>  Removing redundant information from package.json for ${PKGNAME} ${_NODE_FETCH_DESCR}" && \
514
	     ${FIND} ${_NODE_DIR} -name package.json -and -exec test -s {} \; -print0 | \
515
	       ${XARGS} -0 -n1 -I @@ -S 10000 \
516
	         ${SH} -c "${JQ_CMD} -s '.[0] | (del(.[\"scripts\"]) \
517
	                                        * ((select(.scripts.preinstall)  | {scripts:{preinstall:  .scripts.preinstall}})  // { }) \
518
	                                        * ((select(.scripts.install)     | {scripts:{install:     .scripts.install}})     // { }) \
519
	                                        * ((select(.scripts.postinstall) | {scripts:{postinstall: .scripts.postinstall}}) // { })) \
520
	                                      | del(.[\"scripts\"] | select(length==0)) \
521
	                                      | del(.[\"man\"])' \
522
	                                      @@ > @@.new && ${MV} @@.new @@" && \
523
	     ${ECHO_MSG} "===>  Packaging the final distfile for ${PKGNAME} ${_NODE_FETCH_DESCR}" && \
524
	     ${FIND} -d ${_NODE_DIR} -and -exec ${TOUCH} -h -m -a -d 1970-01-01T00:00:00Z {} \; && \
525
	     ${FIND} ${_NODE_DIR} -print0 | \
526
	       LC_ALL=C sort -z | \
527
	       ${_NODE_DISTRO_TAR_CMD} cf - \
528
	         --no-recursion --null -T - | \
529
	       ${_NODE_DISTRO_GZIP_CMD} -9n > ${NODE_DISTFILE} && \
530
	     ${RM} -rf ${_NODE_DIR}; then \
531
	     return 0; \
532
	  fi; \
533
	  ${_NODE_RM_TMP_DIR_FETCH} && \
534
	  ${ECHO_MSG} "===>  Fetch failed for ${PKGNAME}"; \
535
	  ${FALSE}; \
536
	fi;
537
538
do-extract:
539
	@cd ${WRKDIR} && \
540
	${TAR} xzf ${DISTDIR}/${NODE_DISTFILE}
541
542
_USES_patch+= 750:patch-gyp-cflags
543
patch-gyp-cflags:
544
	@${FIND} ${WRKSRC} -name "*.gyp" -and -exec ${REINPLACE_CMD} -i "" -e "s|cflags': \[|cflags': ['-I${LOCALBASE}/include/node',|g" {} \;
545
546
node-npm-build: node-remind-debug-mode node-fakemake
547
	@${ECHO} "===>  NPM build for ${PKGNAME}" && \
548
	cd ${WRKSRC}/${_NODE_DO_CD} && \
549
	(cd ${_NODE_BUILD_DIR} && ! ${_NODE_PACKAGE_EXISTS} || ${NPM_ENV_BUILD} ${NPM_CMD} rebuild ${NPM_BUILD_ARGS}) && \
550
	for sp in ${NODE_SUB_PROJECTS}; do \
551
	  ${ECHO} "===>  NPM build for ${PKGNAME}/$${sp}" && \
552
	  (cd $${sp} && ${NPM_ENV_BUILD} ${NPM_CMD} rebuild ${NPM_BUILD_ARGS}); \
553
	done && \
554
	${_NODE_RM_TMP_DIR_BUILD}
555
556
# uses-optional targets
557
.if defined(_NODE_USES_GRUNT)
558
node-grunt-build:
559
	@${ECHO} "===>  Grunt build for ${PKGNAME}" && \
560
	${_NODE_MK_TMP_DIR_BUILD} && \
561
	cd ${WRKSRC}/${_NODE_DO_CD} && \
562
		${GRUNT_ENV} ${GRUNT_CMD} ${NODE_GRUNT_TARGETS} ${GRUNT_BUILD_ARGS} && \
563
	${_NODE_RM_TMP_DIR_BUILD}
564
node-opt-grunt-build: node-grunt-build
565
.else
566
node-opt-grunt-build:
567
.endif
568
569
.if defined(_NODE_USES_RM_COFFEE)
570
node-rm-coffee:
571
	@${ECHO} "===>  Removing coffee from ${PKGNAME}" && \
572
	${FIND} ${WRKSRC} -name "*.coffee" -and -exec test -f {} \; -and -exec ${SH} -c 'f="{}"; test -f $${f%%.coffee}.js && ${RM} $$f' \;
573
574
node-opt-rm-coffee: node-rm-coffee
575
.else
576
node-opt-rm-coffee:
577
.endif
578
579
.if !target(do-pre-build)
580
do-pre-build:
581
.endif
582
.if !target(do-post-build)
583
do-post-build:
584
.endif
585
586
# TODO npm-clean ?
587
node-npm-prune:
588
	@${ECHO} "===>  Pruning for ${PKGNAME}" && \
589
	${_NODE_MK_TMP_DIR_BUILD} && \
590
	cd ${WRKSRC}/${_NODE_DO_CD} && \
591
	(! ${_NODE_PACKAGE_EXISTS} || ${NPM_ENV_BUILD} ${NPM_CMD} prune ${NPM_PRUNE_ARGS}) && \
592
	for sp in ${NODE_SUB_PROJECTS}; do \
593
	  (cd $${sp} && ${NPM_ENV_BUILD} ${NPM_CMD} prune ${NPM_PRUNE_ARGS}) || ${_NODE_DO_FAIL}; \
594
	done && \
595
	${_NODE_RM_TMP_DIR_BUILD}
596
597
node-npm-dedupe:
598
	@${ECHO} "===>  Deduping for ${PKGNAME}" && \
599
	${_NODE_MK_TMP_DIR_BUILD} && \
600
	cd ${WRKSRC}/${_NODE_DO_CD} && \
601
	(! ${_NODE_PACKAGE_EXISTS} || ${NPM_ENV_BUILD} ${NPM_CMD} dedupe ${NPM_DEDUPE_ARGS}) && \
602
	for sp in ${NODE_SUB_PROJECTS}; do \
603
	  (cd $${sp} && ${NPM_ENV_BUILD} ${NPM_CMD} dedupe ${NPM_DEDUPE_ARGS}) || ${_NODE_DO_FAIL}; \
604
	done && \
605
	${_NODE_RM_TMP_DIR_BUILD}
606
607
node-clean-files:
608
	@${ECHO} "===>  Cleaning files for ${PKGNAME}" && \
609
	cd ${WRKSRC}/${_NODE_DO_CD} && \
610
	for f in ${NODE_FILES_TO_CLEAN}; do \
611
	  ${FIND} -d . -name "$${f}" -and -exec ${RM} -rf {} \;; \
612
	done && \
613
	${FIND} -d . -type d -empty -exec rmdir {} \;
614
615
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
616
617
.if !target(do-build)
618
do-build: node-do-build
619
.endif
620
621
_USES_build+= 751:delete-gyp-pyc
622
delete-gyp-pyc:
623
	@${ECHO} "===>  Deleting created .pyc files that npm should have installed"
624
	@${RM} -rf `${FIND} ${LOCALBASE}/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp -name "*.pyc"`
625
626
# we implement auto-plist feature
627
add-plist-post:
628
	@${ECHO} "===>  Generating plist for ${PKGNAME}"
629
	@${FIND} ${STAGEDIR} -type f -or -type l | \
630
	  ${SED} -e "s|^${STAGEDIR}${LOCALBASE}/||" | \
631
	  ${SED} -e "s|^share/licenses/.*$$||" | \
632
	  ${GREP} -v -e "^$$" \
633
	  >> ${TMPPLIST}
634
635
node-do-install:
636
	@${ECHO} "===>  Staging for ${PKGNAME}"
637
	@${MKDIR} ${STAGEDIR}${NODE_INSTALL_BASE}
638
	@${CP} -r ${WRKSRC} ${STAGEDIR}${NODE_INSTALL_DIR}
639
	@${RM} `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name "*.orig"`
640
	@${RM} `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name ${_NODE_SHRINKWRAP_NAME}`
641
	@${RM} -rf `${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name .deps`
642
	@${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name "*.o" -and -exec ${STRIP_CMD} {} \;
643
	@${FIND} ${STAGEDIR}${NODE_INSTALL_DIR} -name "*.node" -and -exec ${STRIP_CMD} {} \;
644
	@${FIND} -d ${STAGEDIR}${NODE_INSTALL_DIR} -type d -empty -delete
645
.for cmd in ${NODE_CMDS}
646
	@${MKDIR} ${STAGEDIR}${PREFIX}/${cmd:C/.*\://:C/\/[a-zA-Z0-9_-]+$//}
647
	@${LN} -s ${NODE_INSTALL_BASE}/${cmd:C/\:.*//} ${STAGEDIR}${PREFIX}/${cmd:C/.*\://}
648
.endfor
649
650
.if !target(do-install)
651
do-install: node-do-install
652
.endif
653
654
.endif

Return to bug 204577