inline-style-editor 1.2.16 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/n DELETED
@@ -1,1621 +0,0 @@
1
- #!/usr/bin/env bash
2
- # shellcheck disable=SC2155
3
- # Disabled "Declare and assign separately to avoid masking return values": https://github.com/koalaman/shellcheck/wiki/SC2155
4
-
5
- #
6
- # log <type> <msg>
7
- #
8
-
9
- log() {
10
- printf " ${SGR_CYAN}%10s${SGR_RESET} : ${SGR_FAINT}%s${SGR_RESET}\n" "$1" "$2"
11
- }
12
-
13
- #
14
- # verbose_log <type> <msg>
15
- # Can suppress with --quiet.
16
- # Like log but to stderr rather than stdout, so can also be used from "display" routines.
17
- #
18
-
19
- verbose_log() {
20
- if [[ "${SHOW_VERBOSE_LOG}" == "true" ]]; then
21
- >&2 printf " ${SGR_CYAN}%10s${SGR_RESET} : ${SGR_FAINT}%s${SGR_RESET}\n" "$1" "$2"
22
- fi
23
- }
24
-
25
- #
26
- # Exit with the given <msg ...>
27
- #
28
-
29
- abort() {
30
- >&2 printf "\n ${SGR_RED}Error: %s${SGR_RESET}\n\n" "$*" && exit 1
31
- }
32
-
33
- #
34
- # Synopsis: trace message ...
35
- # Debugging output to stderr, not used in production code.
36
- #
37
-
38
- function trace() {
39
- >&2 printf "trace: %s\n" "$*"
40
- }
41
-
42
- #
43
- # Synopsis: echo_red message ...
44
- # Highlight message in colour (on stdout).
45
- #
46
-
47
- function echo_red() {
48
- printf "${SGR_RED}%s${SGR_RESET}\n" "$*"
49
- }
50
-
51
- #
52
- # Synopsis: n_grep <args...>
53
- # grep wrapper to ensure consistent grep options and circumvent aliases.
54
- #
55
-
56
- function n_grep() {
57
- GREP_OPTIONS='' command grep "$@"
58
- }
59
-
60
- #
61
- # Setup and state
62
- #
63
-
64
- VERSION="v9.0.1"
65
-
66
- N_PREFIX="${N_PREFIX-/usr/local}"
67
- N_PREFIX=${N_PREFIX%/}
68
- readonly N_PREFIX
69
-
70
- N_CACHE_PREFIX="${N_CACHE_PREFIX-${N_PREFIX}}"
71
- N_CACHE_PREFIX=${N_CACHE_PREFIX%/}
72
- CACHE_DIR="${N_CACHE_PREFIX}/n/versions"
73
- readonly N_CACHE_PREFIX CACHE_DIR
74
-
75
- N_NODE_MIRROR=${N_NODE_MIRROR:-${NODE_MIRROR:-https://nodejs.org/dist}}
76
- N_NODE_MIRROR=${N_NODE_MIRROR%/}
77
- readonly N_NODE_MIRROR
78
-
79
- N_NODE_DOWNLOAD_MIRROR=${N_NODE_DOWNLOAD_MIRROR:-https://nodejs.org/download}
80
- N_NODE_DOWNLOAD_MIRROR=${N_NODE_DOWNLOAD_MIRROR%/}
81
- readonly N_NODE_DOWNLOAD_MIRROR
82
-
83
- # Using xz instead of gzip is enabled by default, if xz compatibility checks pass.
84
- # User may set N_USE_XZ to 0 to disable, or set to anything else to enable.
85
- # May also be overridden by command line flags.
86
-
87
- # Normalise external values to true/false
88
- if [[ "${N_USE_XZ}" = "0" ]]; then
89
- N_USE_XZ="false"
90
- elif [[ -n "${N_USE_XZ+defined}" ]]; then
91
- N_USE_XZ="true"
92
- fi
93
- # Not setting to readonly. Overriden by CLI flags, and update_xz_settings_for_version.
94
-
95
- N_MAX_REMOTE_MATCHES=${N_MAX_REMOTE_MATCHES:-20}
96
- # modified by update_mirror_settings_for_version
97
- g_mirror_url=${N_NODE_MIRROR}
98
- g_mirror_folder_name="node"
99
-
100
- # Options for curl and wget.
101
- # Defining commands in variables is fraught (https://mywiki.wooledge.org/BashFAQ/050)
102
- # but we can follow the simple case and store arguments in an array.
103
-
104
- GET_SHOWS_PROGRESS="false"
105
- # --location to follow redirects
106
- # --fail to avoid happily downloading error page from web server for 404 et al
107
- # --show-error to show why failed (on stderr)
108
- CURL_OPTIONS=( "--location" "--fail" "--show-error" )
109
- if [[ -t 1 ]]; then
110
- CURL_OPTIONS+=( "--progress-bar" )
111
- command -v curl &> /dev/null && GET_SHOWS_PROGRESS="true"
112
- else
113
- CURL_OPTIONS+=( "--silent" )
114
- fi
115
- WGET_OPTIONS=( "-q" "-O-" )
116
-
117
- # Legacy support using unprefixed env. No longer documented in README.
118
- if [ -n "$HTTP_USER" ];then
119
- if [ -z "$HTTP_PASSWORD" ]; then
120
- abort "Must specify HTTP_PASSWORD when supplying HTTP_USER"
121
- fi
122
- CURL_OPTIONS+=( "-u $HTTP_USER:$HTTP_PASSWORD" )
123
- WGET_OPTIONS+=( "--http-password=$HTTP_PASSWORD"
124
- "--http-user=$HTTP_USER" )
125
- elif [ -n "$HTTP_PASSWORD" ]; then
126
- abort "Must specify HTTP_USER when supplying HTTP_PASSWORD"
127
- fi
128
-
129
- # Set by set_active_node
130
- g_active_node=
131
-
132
- # set by various lookups to allow mixed logging and return value from function, especially for engine and node
133
- g_target_node=
134
-
135
- DOWNLOAD=false # set to opt-out of activate (install), and opt-in to download (run, exec)
136
- ARCH=
137
- SHOW_VERBOSE_LOG="true"
138
-
139
- # ANSI escape codes
140
- # https://en.wikipedia.org/wiki/ANSI_escape_code
141
- # https://no-color.org
142
- # https://bixense.com/clicolors
143
-
144
- USE_COLOR="true"
145
- if [[ -n "${CLICOLOR_FORCE+defined}" && "${CLICOLOR_FORCE}" != "0" ]]; then
146
- USE_COLOR="true"
147
- elif [[ -n "${NO_COLOR+defined}" || "${CLICOLOR}" = "0" || ! -t 1 ]]; then
148
- USE_COLOR="false"
149
- fi
150
- readonly USE_COLOR
151
- # Select Graphic Rendition codes
152
- if [[ "${USE_COLOR}" = "true" ]]; then
153
- # KISS and use codes rather than tput, avoid dealing with missing tput or TERM.
154
- readonly SGR_RESET="\033[0m"
155
- readonly SGR_FAINT="\033[2m"
156
- readonly SGR_RED="\033[31m"
157
- readonly SGR_CYAN="\033[36m"
158
- else
159
- readonly SGR_RESET=
160
- readonly SGR_FAINT=
161
- readonly SGR_RED=
162
- readonly SGR_CYAN=
163
- fi
164
-
165
- #
166
- # set_arch <arch> to override $(uname -a)
167
- #
168
-
169
- set_arch() {
170
- if test -n "$1"; then
171
- ARCH="$1"
172
- else
173
- abort "missing -a|--arch value"
174
- fi
175
- }
176
-
177
- #
178
- # Synopsis: set_insecure
179
- # Globals modified:
180
- # - CURL_OPTIONS
181
- # - WGET_OPTIONS
182
- #
183
-
184
- function set_insecure() {
185
- CURL_OPTIONS+=( "--insecure" )
186
- WGET_OPTIONS+=( "--no-check-certificate" )
187
- }
188
-
189
- #
190
- # Synposis: display_major_version numeric-version
191
- #
192
- display_major_version() {
193
- local version=$1
194
- version="${version#v}"
195
- version="${version%%.*}"
196
- echo "${version}"
197
- }
198
-
199
- #
200
- # Synopsis: update_mirror_settings_for_version version
201
- # e.g. <nightly/latest> means using download mirror and folder is nightly
202
- # Globals modified:
203
- # - g_mirror_url
204
- # - g_mirror_folder_name
205
- #
206
-
207
- function update_mirror_settings_for_version() {
208
- if is_download_folder "$1" ; then
209
- g_mirror_folder_name="$1"
210
- g_mirror_url="${N_NODE_DOWNLOAD_MIRROR}/${g_mirror_folder_name}"
211
- elif is_download_version "$1"; then
212
- [[ "$1" =~ ^([^/]+)/(.*) ]]
213
- local remote_folder="${BASH_REMATCH[1]}"
214
- g_mirror_folder_name="${remote_folder}"
215
- g_mirror_url="${N_NODE_DOWNLOAD_MIRROR}/${g_mirror_folder_name}"
216
- fi
217
- }
218
-
219
- #
220
- # Synopsis: update_xz_settings_for_version numeric-version
221
- # Globals modified:
222
- # - N_USE_XZ
223
- #
224
-
225
- function update_xz_settings_for_version() {
226
- # tarballs in xz format were available in later version of iojs, but KISS and only use xz from v4.
227
- if [[ "${N_USE_XZ}" = "true" ]]; then
228
- local major_version="$(display_major_version "$1")"
229
- if [[ "${major_version}" -lt 4 ]]; then
230
- N_USE_XZ="false"
231
- fi
232
- fi
233
- }
234
-
235
- #
236
- # Synopsis: update_arch_settings_for_version numeric-version
237
- # Globals modified:
238
- # - ARCH
239
- #
240
-
241
- function update_arch_settings_for_version() {
242
- local tarball_platform="$(display_tarball_platform)"
243
- if [[ -z "${ARCH}" && "${tarball_platform}" = "darwin-arm64" ]]; then
244
- # First native builds were for v16, but can use x64 in rosetta for older versions.
245
- local major_version="$(display_major_version "$1")"
246
- if [[ "${major_version}" -lt 16 ]]; then
247
- ARCH=x64
248
- fi
249
- fi
250
- }
251
-
252
- #
253
- # Synopsis: is_lts_codename version
254
- #
255
-
256
- function is_lts_codename() {
257
- # https://github.com/nodejs/Release/blob/master/CODENAMES.md
258
- # e.g. argon, Boron
259
- [[ "$1" =~ ^([Aa]rgon|[Bb]oron|[Cc]arbon|[Dd]ubnium|[Ee]rbium|[Ff]ermium|[Gg]allium|[Hh]ydrogen|[Ii]ron|[Jj]od)$ ]]
260
- }
261
-
262
- #
263
- # Synopsis: is_download_folder version
264
- #
265
-
266
- function is_download_folder() {
267
- # e.g. nightly
268
- [[ "$1" =~ ^(next-nightly|nightly|rc|release|test|v8-canary)$ ]]
269
- }
270
-
271
- #
272
- # Synopsis: is_download_version version
273
- #
274
-
275
- function is_download_version() {
276
- # e.g. nightly/, nightly/latest, nightly/v11
277
- if [[ "$1" =~ ^([^/]+)/(.*) ]]; then
278
- local remote_folder="${BASH_REMATCH[1]}"
279
- is_download_folder "${remote_folder}"
280
- return
281
- fi
282
- return 2
283
- }
284
-
285
- #
286
- # Synopsis: is_numeric_version version
287
- #
288
-
289
- function is_numeric_version() {
290
- # e.g. 6, v7.1, 8.11.3
291
- [[ "$1" =~ ^[v]{0,1}[0-9]+(\.[0-9]+){0,2}$ ]]
292
- }
293
-
294
- #
295
- # Synopsis: is_exact_numeric_version version
296
- #
297
-
298
- function is_exact_numeric_version() {
299
- # e.g. 6, v7.1, 8.11.3
300
- [[ "$1" =~ ^[v]{0,1}[0-9]+\.[0-9]+\.[0-9]+$ ]]
301
- }
302
-
303
- #
304
- # Synopsis: is_node_support_version version
305
- # Reference: https://github.com/nodejs/package-maintenance/issues/236#issue-474783582
306
- #
307
-
308
- function is_node_support_version() {
309
- [[ "$1" =~ ^(active|lts_active|lts_latest|lts|current|supported)$ ]]
310
- }
311
-
312
- #
313
- # Synopsis: display_latest_node_support_alias version
314
- # Map aliases onto existing n aliases, current and lts
315
- #
316
-
317
- function display_latest_node_support_alias() {
318
- case "$1" in
319
- "active") printf "current" ;;
320
- "lts_active") printf "lts" ;;
321
- "lts_latest") printf "lts" ;;
322
- "lts") printf "lts" ;;
323
- "current") printf "current" ;;
324
- "supported") printf "current" ;;
325
- *) printf "unexpected-version"
326
- esac
327
- }
328
-
329
- #
330
- # Functions used when showing versions installed
331
- #
332
-
333
- enter_fullscreen() {
334
- # Set cursor to be invisible
335
- tput civis 2> /dev/null
336
- # Save screen contents
337
- tput smcup 2> /dev/null
338
- stty -echo
339
- }
340
-
341
- leave_fullscreen() {
342
- # Set cursor to normal
343
- tput cnorm 2> /dev/null
344
- # Restore screen contents
345
- tput rmcup 2> /dev/null
346
- stty echo
347
- }
348
-
349
- handle_sigint() {
350
- leave_fullscreen
351
- S="$?"
352
- kill 0
353
- exit $S
354
- }
355
-
356
- handle_sigtstp() {
357
- leave_fullscreen
358
- kill -s SIGSTOP $$
359
- }
360
-
361
- #
362
- # Output usage information.
363
- #
364
-
365
- display_help() {
366
- cat <<-EOF
367
-
368
- Usage: n [options] [COMMAND] [args]
369
-
370
- Commands:
371
-
372
- n Display downloaded Node.js versions and install selection
373
- n latest Install the latest Node.js release (downloading if necessary)
374
- n lts Install the latest LTS Node.js release (downloading if necessary)
375
- n <version> Install Node.js <version> (downloading if necessary)
376
- n install <version> Install Node.js <version> (downloading if necessary)
377
- n run <version> [args ...] Execute downloaded Node.js <version> with [args ...]
378
- n which <version> Output path for downloaded node <version>
379
- n exec <vers> <cmd> [args...] Execute command with modified PATH, so downloaded node <version> and npm first
380
- n rm <version ...> Remove the given downloaded version(s)
381
- n prune Remove all downloaded versions except the installed version
382
- n --latest Output the latest Node.js version available
383
- n --lts Output the latest LTS Node.js version available
384
- n ls Output downloaded versions
385
- n ls-remote [version] Output matching versions available for download
386
- n uninstall Remove the installed Node.js
387
-
388
- Options:
389
-
390
- -V, --version Output version of n
391
- -h, --help Display help information
392
- -p, --preserve Preserve npm and npx during install of Node.js
393
- -q, --quiet Disable curl output. Disable log messages processing "auto" and "engine" labels.
394
- -d, --download Download if necessary, and don't make active
395
- -a, --arch Override system architecture
396
- --all ls-remote displays all matches instead of last 20
397
- --insecure Turn off certificate checking for https requests (may be needed from behind a proxy server)
398
- --use-xz/--no-use-xz Override automatic detection of xz support and enable/disable use of xz compressed node downloads.
399
-
400
- Aliases:
401
-
402
- install: i
403
- latest: current
404
- ls: list
405
- lsr: ls-remote
406
- lts: stable
407
- rm: -
408
- run: use, as
409
- which: bin
410
-
411
- Versions:
412
-
413
- Numeric version numbers can be complete or incomplete, with an optional leading 'v'.
414
- Versions can also be specified by label, or codename,
415
- and other downloadable releases by <remote-folder>/<version>
416
-
417
- 4.9.1, 8, v6.1 Numeric versions
418
- lts Newest Long Term Support official release
419
- latest, current Newest official release
420
- auto Read version from file: .n-node-version, .node-version, .nvmrc, or package.json
421
- engine Read version from package.json
422
- boron, carbon Codenames for release streams
423
- lts_latest Node.js support aliases
424
-
425
- and nightly, rc/10 et al
426
-
427
- EOF
428
- }
429
-
430
- err_no_installed_print_help() {
431
- display_help
432
- abort "no downloaded versions yet, see above help for commands"
433
- }
434
-
435
- #
436
- # Synopsis: next_version_installed selected_version
437
- # Output version after selected (which may be blank under some circumstances).
438
- #
439
-
440
- function next_version_installed() {
441
- display_cache_versions | n_grep "$1" -A 1 | tail -n 1
442
- }
443
-
444
- #
445
- # Synopsis: prev_version_installed selected_version
446
- # Output version before selected (which may be blank under some circumstances).
447
- #
448
-
449
- function prev_version_installed() {
450
- display_cache_versions | n_grep "$1" -B 1 | head -n 1
451
- }
452
-
453
- #
454
- # Output n version.
455
- #
456
-
457
- display_n_version() {
458
- echo "$VERSION" && exit 0
459
- }
460
-
461
- #
462
- # Synopsis: set_active_node
463
- # Checks cached downloads for a binary matching the active node.
464
- # Globals modified:
465
- # - g_active_node
466
- #
467
-
468
- function set_active_node() {
469
- g_active_node=
470
- local node_path="$(command -v node)"
471
- if [[ -x "${node_path}" ]]; then
472
- local installed_version=$(node --version)
473
- installed_version=${installed_version#v}
474
- for dir in "${CACHE_DIR}"/*/ ; do
475
- local folder_name="${dir%/}"
476
- folder_name="${folder_name##*/}"
477
- if diff &> /dev/null \
478
- "${CACHE_DIR}/${folder_name}/${installed_version}/bin/node" \
479
- "${node_path}" ; then
480
- g_active_node="${folder_name}/${installed_version}"
481
- break
482
- fi
483
- done
484
- fi
485
- }
486
-
487
- #
488
- # Display sorted versions directories paths.
489
- #
490
-
491
- display_versions_paths() {
492
- find "$CACHE_DIR" -maxdepth 2 -type d \
493
- | sed 's|'"$CACHE_DIR"'/||g' \
494
- | n_grep -E "/[0-9]+\.[0-9]+\.[0-9]+" \
495
- | sed 's|/|.|' \
496
- | sort -k 1,1 -k 2,2n -k 3,3n -k 4,4n -t . \
497
- | sed 's|\.|/|'
498
- }
499
-
500
- #
501
- # Display installed versions with <selected>
502
- #
503
-
504
- display_versions_with_selected() {
505
- local selected="$1"
506
- echo
507
- for version in $(display_versions_paths); do
508
- if test "$version" = "$selected"; then
509
- printf " ${SGR_CYAN}ο${SGR_RESET} %s\n" "$version"
510
- else
511
- printf " ${SGR_FAINT}%s${SGR_RESET}\n" "$version"
512
- fi
513
- done
514
- echo
515
- printf "Use up/down arrow keys to select a version, return key to install, d to delete, q to quit"
516
- }
517
-
518
- #
519
- # Synopsis: display_cache_versions
520
- #
521
-
522
- function display_cache_versions() {
523
- for folder_and_version in $(display_versions_paths); do
524
- echo "${folder_and_version}"
525
- done
526
- }
527
-
528
- #
529
- # Display current node --version and others installed.
530
- #
531
-
532
- menu_select_cache_versions() {
533
- enter_fullscreen
534
- set_active_node
535
- local selected="${g_active_node}"
536
-
537
- clear
538
- display_versions_with_selected "${selected}"
539
-
540
- trap handle_sigint INT
541
- trap handle_sigtstp SIGTSTP
542
-
543
- ESCAPE_SEQ=$'\033'
544
- UP=$'A'
545
- DOWN=$'B'
546
- CTRL_P=$'\020'
547
- CTRL_N=$'\016'
548
-
549
- while true; do
550
- read -rsn 1 key
551
- case "$key" in
552
- "$ESCAPE_SEQ")
553
- # Handle ESC sequences followed by other characters, i.e. arrow keys
554
- read -rsn 1 -t 1 tmp
555
- # See "[" if terminal in normal mode, and "0" in application mode
556
- if [[ "$tmp" == "[" || "$tmp" == "O" ]]; then
557
- read -rsn 1 -t 1 arrow
558
- case "$arrow" in
559
- "$UP")
560
- clear
561
- selected="$(prev_version_installed "${selected}")"
562
- display_versions_with_selected "${selected}"
563
- ;;
564
- "$DOWN")
565
- clear
566
- selected="$(next_version_installed "${selected}")"
567
- display_versions_with_selected "${selected}"
568
- ;;
569
- esac
570
- fi
571
- ;;
572
- "d")
573
- if [[ -n "${selected}" ]]; then
574
- clear
575
- # Note: prev/next is constrained to min/max
576
- local after_delete_selection="$(next_version_installed "${selected}")"
577
- if [[ "${after_delete_selection}" == "${selected}" ]]; then
578
- after_delete_selection="$(prev_version_installed "${selected}")"
579
- fi
580
- remove_versions "${selected}"
581
-
582
- if [[ "${after_delete_selection}" == "${selected}" ]]; then
583
- clear
584
- leave_fullscreen
585
- echo "All downloaded versions have been deleted from cache."
586
- exit
587
- fi
588
-
589
- selected="${after_delete_selection}"
590
- display_versions_with_selected "${selected}"
591
- fi
592
- ;;
593
- # Vim or Emacs 'up' key
594
- "k"|"$CTRL_P")
595
- clear
596
- selected="$(prev_version_installed "${selected}")"
597
- display_versions_with_selected "${selected}"
598
- ;;
599
- # Vim or Emacs 'down' key
600
- "j"|"$CTRL_N")
601
- clear
602
- selected="$(next_version_installed "${selected}")"
603
- display_versions_with_selected "${selected}"
604
- ;;
605
- "q")
606
- clear
607
- leave_fullscreen
608
- exit
609
- ;;
610
- "")
611
- # enter key returns empty string
612
- leave_fullscreen
613
- [[ -n "${selected}" ]] && activate "${selected}"
614
- exit
615
- ;;
616
- esac
617
- done
618
- }
619
-
620
- #
621
- # Move up a line and erase.
622
- #
623
-
624
- erase_line() {
625
- printf "\033[1A\033[2K"
626
- }
627
-
628
- #
629
- # Disable PaX mprotect for <binary>
630
- #
631
-
632
- disable_pax_mprotect() {
633
- test -z "$1" && abort "binary required"
634
- local binary="$1"
635
-
636
- # try to disable mprotect via XATTR_PAX header
637
- local PAXCTL="$(PATH="/sbin:/usr/sbin:$PATH" command -v paxctl-ng 2>&1)"
638
- local PAXCTL_ERROR=1
639
- if [ -x "$PAXCTL" ]; then
640
- $PAXCTL -l && $PAXCTL -m "$binary" >/dev/null 2>&1
641
- PAXCTL_ERROR="$?"
642
- fi
643
-
644
- # try to disable mprotect via PT_PAX header
645
- if [ "$PAXCTL_ERROR" != 0 ]; then
646
- PAXCTL="$(PATH="/sbin:/usr/sbin:$PATH" command -v paxctl 2>&1)"
647
- if [ -x "$PAXCTL" ]; then
648
- $PAXCTL -Cm "$binary" >/dev/null 2>&1
649
- fi
650
- fi
651
- }
652
-
653
- #
654
- # clean_copy_folder <source> <target>
655
- #
656
-
657
- clean_copy_folder() {
658
- local source="$1"
659
- local target="$2"
660
- if [[ -d "${source}" ]]; then
661
- rm -rf "${target}"
662
- cp -fR "${source}" "${target}"
663
- fi
664
- }
665
-
666
- #
667
- # Activate <version>
668
- #
669
-
670
- activate() {
671
- local version="$1"
672
- local dir="$CACHE_DIR/$version"
673
- local original_node="$(command -v node)"
674
- local installed_node="${N_PREFIX}/bin/node"
675
- log "copying" "$version"
676
-
677
-
678
- # Ideally we would just copy from cache to N_PREFIX, but there are some complications
679
- # - various linux versions use symlinks for folders in /usr/local and also error when copy folder onto symlink
680
- # - we have used cp for years, so keep using it for backwards compatibility (instead of say rsync)
681
- # - we allow preserving npm
682
- # - we want to be somewhat robust to changes in tarball contents, so use find instead of hard-code expected subfolders
683
- #
684
- # This code was purist and concise for a long time.
685
- # Now twice as much code, but using same code path for all uses, and supporting more setups.
686
-
687
- # Copy lib before bin so symlink targets exist.
688
- # lib
689
- mkdir -p "$N_PREFIX/lib"
690
- # Copy everything except node_modules.
691
- find "$dir/lib" -mindepth 1 -maxdepth 1 \! -name node_modules -exec cp -fR "{}" "$N_PREFIX/lib" \;
692
- if [[ -z "${N_PRESERVE_NPM}" ]]; then
693
- mkdir -p "$N_PREFIX/lib/node_modules"
694
- # Copy just npm, skipping possible added global modules after download. Clean copy to avoid version change problems.
695
- clean_copy_folder "$dir/lib/node_modules/npm" "$N_PREFIX/lib/node_modules/npm"
696
- fi
697
- # Takes same steps for corepack (experimental in node 16.9.0) as for npm, to avoid version problems.
698
- if [[ -e "$dir/lib/node_modules/corepack" && -z "${N_PRESERVE_COREPACK}" ]]; then
699
- mkdir -p "$N_PREFIX/lib/node_modules"
700
- clean_copy_folder "$dir/lib/node_modules/corepack" "$N_PREFIX/lib/node_modules/corepack"
701
- fi
702
-
703
- # bin
704
- mkdir -p "$N_PREFIX/bin"
705
- # Remove old node to avoid potential problems with firewall getting confused on Darwin by overwrite.
706
- rm -f "$N_PREFIX/bin/node"
707
- # Copy bin items by hand, in case user has installed global npm modules into cache.
708
- cp -f "$dir/bin/node" "$N_PREFIX/bin"
709
- [[ -e "$dir/bin/node-waf" ]] && cp -f "$dir/bin/node-waf" "$N_PREFIX/bin" # v0.8.x
710
- if [[ -z "${N_PRESERVE_COREPACK}" ]]; then
711
- [[ -e "$dir/bin/corepack" ]] && cp -fR "$dir/bin/corepack" "$N_PREFIX/bin" # from 16.9.0
712
- fi
713
- if [[ -z "${N_PRESERVE_NPM}" ]]; then
714
- [[ -e "$dir/bin/npm" ]] && cp -fR "$dir/bin/npm" "$N_PREFIX/bin"
715
- [[ -e "$dir/bin/npx" ]] && cp -fR "$dir/bin/npx" "$N_PREFIX/bin"
716
- fi
717
-
718
- # include
719
- mkdir -p "$N_PREFIX/include"
720
- find "$dir/include" -mindepth 1 -maxdepth 1 -exec cp -fR "{}" "$N_PREFIX/include" \;
721
-
722
- # share
723
- mkdir -p "$N_PREFIX/share"
724
- # Copy everything except man, at it is a symlink on some Linux (e.g. archlinux).
725
- find "$dir/share" -mindepth 1 -maxdepth 1 \! -name man -exec cp -fR "{}" "$N_PREFIX/share" \;
726
- mkdir -p "$N_PREFIX/share/man"
727
- find "$dir/share/man" -mindepth 1 -maxdepth 1 -exec cp -fR "{}" "$N_PREFIX/share/man" \;
728
-
729
- disable_pax_mprotect "${installed_node}"
730
-
731
- local active_node="$(command -v node)"
732
- if [[ -e "${active_node}" && -e "${installed_node}" && "${active_node}" != "${installed_node}" ]]; then
733
- # Installed and active are different which might be a PATH problem. List both to give user some clues.
734
- log "installed" "$("${installed_node}" --version) to ${installed_node}"
735
- log "active" "$("${active_node}" --version) at ${active_node}"
736
- else
737
- local npm_version_str=""
738
- local installed_npm="${N_PREFIX}/bin/npm"
739
- local active_npm="$(command -v npm)"
740
- if [[ -z "${N_PRESERVE_NPM}" && -e "${active_npm}" && -e "${installed_npm}" && "${active_npm}" = "${installed_npm}" ]]; then
741
- npm_version_str=" (with npm $(npm --version))"
742
- fi
743
-
744
- log "installed" "$("${installed_node}" --version)${npm_version_str}"
745
-
746
- # Extra tips for changed location.
747
- if [[ -e "${active_node}" && -e "${original_node}" && "${active_node}" != "${original_node}" ]]; then
748
- printf '\nNote: the node command changed location and the old location may be remembered in your current shell.\n'
749
- log old "${original_node}"
750
- log new "${active_node}"
751
- printf 'If "node --version" shows the old version then start a new shell, or reset the location hash with:\nhash -r (for bash, zsh, ash, dash, and ksh)\nrehash (for csh and tcsh)\n'
752
- fi
753
- fi
754
- }
755
-
756
- #
757
- # Install <version>
758
- #
759
-
760
- install() {
761
- [[ -z "$1" ]] && abort "version required"
762
- local version
763
- get_latest_resolved_version "$1" || return 2
764
- version="${g_target_node}"
765
- [[ -n "${version}" ]] || abort "no version found for '$1'"
766
- update_mirror_settings_for_version "$1"
767
- update_xz_settings_for_version "${version}"
768
- update_arch_settings_for_version "${version}"
769
-
770
- local dir="${CACHE_DIR}/${g_mirror_folder_name}/${version}"
771
-
772
- # Note: decompression flags ignored with default Darwin tar which autodetects.
773
- if test "$N_USE_XZ" = "true"; then
774
- local tarflag="-Jx"
775
- else
776
- local tarflag="-zx"
777
- fi
778
-
779
- if test -d "$dir"; then
780
- if [[ ! -e "$dir/n.lock" ]] ; then
781
- if [[ "$DOWNLOAD" == "false" ]] ; then
782
- activate "${g_mirror_folder_name}/${version}"
783
- fi
784
- exit
785
- fi
786
- fi
787
-
788
- log installing "${g_mirror_folder_name}-v$version"
789
-
790
- local url="$(tarball_url "$version")"
791
- is_ok "${url}" || abort "download preflight failed for '$version' (${url})"
792
-
793
- log mkdir "$dir"
794
- mkdir -p "$dir" || abort "sudo required (or change ownership, or define N_PREFIX)"
795
- touch "$dir/n.lock"
796
-
797
- cd "${dir}" || abort "Failed to cd to ${dir}"
798
-
799
- log fetch "$url"
800
- do_get "${url}" | tar "$tarflag" --strip-components=1 --no-same-owner -f -
801
- pipe_results=( "${PIPESTATUS[@]}" )
802
- if [[ "${pipe_results[0]}" -ne 0 ]]; then
803
- abort "failed to download archive for $version"
804
- fi
805
- if [[ "${pipe_results[1]}" -ne 0 ]]; then
806
- abort "failed to extract archive for $version"
807
- fi
808
- [ "$GET_SHOWS_PROGRESS" = "true" ] && erase_line
809
- rm -f "$dir/n.lock"
810
-
811
- disable_pax_mprotect bin/node
812
-
813
- if [[ "$DOWNLOAD" == "false" ]]; then
814
- activate "${g_mirror_folder_name}/$version"
815
- fi
816
- }
817
-
818
- #
819
- # Be more silent.
820
- #
821
-
822
- set_quiet() {
823
- SHOW_VERBOSE_LOG="false"
824
- command -v curl > /dev/null && CURL_OPTIONS+=( "--silent" ) && GET_SHOWS_PROGRESS="false"
825
- }
826
-
827
- #
828
- # Synopsis: do_get [option...] url
829
- # Call curl or wget with combination of global and passed options.
830
- #
831
-
832
- function do_get() {
833
- if command -v curl &> /dev/null; then
834
- curl "${CURL_OPTIONS[@]}" "$@"
835
- elif command -v wget &> /dev/null; then
836
- wget "${WGET_OPTIONS[@]}" "$@"
837
- else
838
- abort "curl or wget command required"
839
- fi
840
- }
841
-
842
- #
843
- # Synopsis: do_get_index [option...] url
844
- # Call curl or wget with combination of global and passed options,
845
- # with options tweaked to be more suitable for getting index.
846
- #
847
-
848
- function do_get_index() {
849
- if command -v curl &> /dev/null; then
850
- # --silent to suppress progress et al
851
- curl --silent --compressed "${CURL_OPTIONS[@]}" "$@"
852
- elif command -v wget &> /dev/null; then
853
- wget "${WGET_OPTIONS[@]}" "$@"
854
- else
855
- abort "curl or wget command required"
856
- fi
857
- }
858
-
859
- #
860
- # Synopsis: remove_versions version ...
861
- #
862
-
863
- function remove_versions() {
864
- [[ -z "$1" ]] && abort "version(s) required"
865
- while [[ $# -ne 0 ]]; do
866
- local version
867
- get_latest_resolved_version "$1" || break
868
- version="${g_target_node}"
869
- if [[ -n "${version}" ]]; then
870
- update_mirror_settings_for_version "$1"
871
- local dir="${CACHE_DIR}/${g_mirror_folder_name}/${version}"
872
- if [[ -s "${dir}" ]]; then
873
- rm -rf "${dir}"
874
- else
875
- echo "$1 (${version}) not in downloads cache"
876
- fi
877
- else
878
- echo "No version found for '$1'"
879
- fi
880
- shift
881
- done
882
- }
883
-
884
- #
885
- # Synopsis: prune_cache
886
- #
887
-
888
- function prune_cache() {
889
- set_active_node
890
-
891
- for folder_and_version in $(display_versions_paths); do
892
- if [[ "${folder_and_version}" != "${g_active_node}" ]]; then
893
- echo "${folder_and_version}"
894
- rm -rf "${CACHE_DIR:?}/${folder_and_version}"
895
- fi
896
- done
897
- }
898
-
899
- #
900
- # Synopsis: find_cached_version version
901
- # Finds cache directory for resolved version.
902
- # Globals modified:
903
- # - g_cached_version
904
-
905
- function find_cached_version() {
906
- [[ -z "$1" ]] && abort "version required"
907
- local version
908
- get_latest_resolved_version "$1" || exit 1
909
- version="${g_target_node}"
910
- [[ -n "${version}" ]] || abort "no version found for '$1'"
911
-
912
- update_mirror_settings_for_version "$1"
913
- g_cached_version="${CACHE_DIR}/${g_mirror_folder_name}/${version}"
914
- if [[ ! -d "${g_cached_version}" && "${DOWNLOAD}" == "true" ]]; then
915
- (install "${version}")
916
- fi
917
- [[ -d "${g_cached_version}" ]] || abort "'$1' (${version}) not in downloads cache"
918
- }
919
-
920
-
921
- #
922
- # Synopsis: display_bin_path_for_version version
923
- #
924
-
925
- function display_bin_path_for_version() {
926
- find_cached_version "$1"
927
- echo "${g_cached_version}/bin/node"
928
- }
929
-
930
- #
931
- # Synopsis: run_with_version version [args...]
932
- # Run the given <version> of node with [args ..]
933
- #
934
-
935
- function run_with_version() {
936
- find_cached_version "$1"
937
- shift # remove version from parameters
938
- exec "${g_cached_version}/bin/node" "$@"
939
- }
940
-
941
- #
942
- # Synopsis: exec_with_version <version> command [args...]
943
- # Modify the path to include <version> and execute command.
944
- #
945
-
946
- function exec_with_version() {
947
- find_cached_version "$1"
948
- shift # remove version from parameters
949
- PATH="${g_cached_version}/bin:$PATH" exec "$@"
950
- }
951
-
952
- #
953
- # Synopsis: is_ok url
954
- # Check the HEAD response of <url>.
955
- #
956
-
957
- function is_ok() {
958
- # Note: both curl and wget can follow redirects, as present on some mirrors (e.g. https://npm.taobao.org/mirrors/node).
959
- # The output is complicated with redirects, so keep it simple and use command status rather than parse output.
960
- if command -v curl &> /dev/null; then
961
- do_get --silent --head "$1" > /dev/null || return 1
962
- else
963
- do_get --spider "$1" > /dev/null || return 1
964
- fi
965
- }
966
-
967
- #
968
- # Synopsis: can_use_xz
969
- # Test system to see if xz decompression is supported by tar.
970
- #
971
-
972
- function can_use_xz() {
973
- # Be conservative and only enable if xz is likely to work. Unfortunately we can't directly query tar itself.
974
- # For research, see https://github.com/shadowspawn/nvh/issues/8
975
- local uname_s="$(uname -s)"
976
- if [[ "${uname_s}" = "Linux" ]] && command -v xz &> /dev/null ; then
977
- # tar on linux is likely to support xz if it is available as a command
978
- return 0
979
- elif [[ "${uname_s}" = "Darwin" ]]; then
980
- local macos_version="$(sw_vers -productVersion)"
981
- local macos_major_version="$(echo "${macos_version}" | cut -d '.' -f 1)"
982
- local macos_minor_version="$(echo "${macos_version}" | cut -d '.' -f 2)"
983
- if [[ "${macos_major_version}" -gt 10 || "${macos_minor_version}" -gt 8 ]]; then
984
- # tar on recent Darwin has xz support built-in
985
- return 0
986
- fi
987
- fi
988
- return 2 # not supported
989
- }
990
-
991
- #
992
- # Synopsis: display_tarball_platform
993
- #
994
-
995
- function display_tarball_platform() {
996
- # https://en.wikipedia.org/wiki/Uname
997
-
998
- local os="unexpected_os"
999
- local uname_a="$(uname -a)"
1000
- case "${uname_a}" in
1001
- Linux*) os="linux" ;;
1002
- Darwin*) os="darwin" ;;
1003
- SunOS*) os="sunos" ;;
1004
- AIX*) os="aix" ;;
1005
- CYGWIN*) >&2 echo_red "Cygwin is not supported by n" ;;
1006
- MINGW*) >&2 echo_red "Git BASH (MSYS) is not supported by n" ;;
1007
- esac
1008
-
1009
- local arch="unexpected_arch"
1010
- local uname_m="$(uname -m)"
1011
- case "${uname_m}" in
1012
- x86_64) arch=x64 ;;
1013
- i386 | i686) arch="x86" ;;
1014
- aarch64) arch=arm64 ;;
1015
- armv8l) arch=arm64 ;; # armv8l probably supports arm64, and there is no specific armv8l build so give it a go
1016
- *)
1017
- # e.g. armv6l, armv7l, arm64
1018
- arch="${uname_m}"
1019
- ;;
1020
- esac
1021
- # Override from command line, or version specific adjustment.
1022
- [ -n "$ARCH" ] && arch="$ARCH"
1023
-
1024
- echo "${os}-${arch}"
1025
- }
1026
-
1027
- #
1028
- # Synopsis: display_compatible_file_field
1029
- # display <file> for current platform, as per <file> field in index.tab, which is different than actual download
1030
- #
1031
-
1032
- function display_compatible_file_field {
1033
- local compatible_file_field="$(display_tarball_platform)"
1034
- if [[ -z "${ARCH}" && "${compatible_file_field}" = "darwin-arm64" ]]; then
1035
- # Look for arm64 for native but also x64 for older versions which can run in rosetta.
1036
- # (Downside is will get an install error if install version above 16 with x64 and not arm64.)
1037
- compatible_file_field="osx-arm64-tar|osx-x64-tar"
1038
- elif [[ "${compatible_file_field}" =~ darwin-(.*) ]]; then
1039
- compatible_file_field="osx-${BASH_REMATCH[1]}-tar"
1040
- fi
1041
- echo "${compatible_file_field}"
1042
- }
1043
-
1044
- #
1045
- # Synopsis: tarball_url version
1046
- #
1047
-
1048
- function tarball_url() {
1049
- local version="$1"
1050
- local ext=gz
1051
- [ "$N_USE_XZ" = "true" ] && ext="xz"
1052
- echo "${g_mirror_url}/v${version}/node-v${version}-$(display_tarball_platform).tar.${ext}"
1053
- }
1054
-
1055
- #
1056
- # Synopsis: get_file_node_version filename
1057
- # Sets g_target_node
1058
- #
1059
-
1060
- function get_file_node_version() {
1061
- g_target_node=
1062
- local filepath="$1"
1063
- verbose_log "found" "${filepath}"
1064
- # read returns a non-zero status but does still work if there is no line ending
1065
- local version
1066
- <"${filepath}" read -r version
1067
- # trim possible trailing \d from a Windows created file
1068
- version="${version%%[[:space:]]}"
1069
- verbose_log "read" "${version}"
1070
- g_target_node="${version}"
1071
- }
1072
-
1073
- #
1074
- # Synopsis: get_package_engine_version\
1075
- # Sets g_target_node
1076
- #
1077
-
1078
- function get_package_engine_version() {
1079
- g_target_node=
1080
- local filepath="$1"
1081
- verbose_log "found" "${filepath}"
1082
- command -v node &> /dev/null || abort "an active version of node is required to read 'engines' from package.json"
1083
- local range
1084
- range="$(node -e "package = require('${filepath}'); if (package && package.engines && package.engines.node) console.log(package.engines.node)")"
1085
- verbose_log "read" "${range}"
1086
- [[ -n "${range}" ]] || return 2
1087
- if [[ "*" == "${range}" ]]; then
1088
- verbose_log "target" "current"
1089
- g_target_node="current"
1090
- return
1091
- fi
1092
-
1093
- local version
1094
- if [[ "${range}" =~ ^([>~^=]|\>\=)?v?([0-9]+(\.[0-9]+){0,2})(.[xX*])?$ ]]; then
1095
- local operator="${BASH_REMATCH[1]}"
1096
- version="${BASH_REMATCH[2]}"
1097
- case "${operator}" in
1098
- '' | =) ;;
1099
- \> | \>=) version="current" ;;
1100
- \~) [[ "${version}" =~ ^([0-9]+\.[0-9]+)\.[0-9]+$ ]] && version="${BASH_REMATCH[1]}" ;;
1101
- ^) [[ "${version}" =~ ^([0-9]+) ]] && version="${BASH_REMATCH[1]}" ;;
1102
- esac
1103
- verbose_log "target" "${version}"
1104
- else
1105
- command -v npx &> /dev/null || abort "an active version of npx is required to use complex 'engine' ranges from package.json"
1106
- verbose_log "resolving" "${range}"
1107
- local version_per_line="$(n lsr --all)"
1108
- local versions_one_line=$(echo "${version_per_line}" | tr '\n' ' ')
1109
- # Using semver@7 so works with older versions of node.
1110
- # shellcheck disable=SC2086
1111
- version=$(npm_config_yes=true npx --quiet semver@7 -r "${range}" ${versions_one_line} | tail -n 1)
1112
- fi
1113
- g_target_node="${version}"
1114
- }
1115
-
1116
- #
1117
- # Synopsis: get_nvmrc_version
1118
- # Sets g_target_node
1119
- #
1120
-
1121
- function get_nvmrc_version() {
1122
- g_target_node=
1123
- local filepath="$1"
1124
- verbose_log "found" "${filepath}"
1125
- local version
1126
- <"${filepath}" read -r version
1127
- verbose_log "read" "${version}"
1128
- # Translate from nvm aliases
1129
- case "${version}" in
1130
- lts/\*) version="lts" ;;
1131
- lts/*) version="${version:4}" ;;
1132
- node) version="current" ;;
1133
- *) ;;
1134
- esac
1135
- g_target_node="${version}"
1136
- }
1137
-
1138
- #
1139
- # Synopsis: get_engine_version [error-message]
1140
- # Sets g_target_node
1141
- #
1142
-
1143
- function get_engine_version() {
1144
- g_target_node=
1145
- local error_message="${1-package.json not found}"
1146
- local parent
1147
- parent="${PWD}"
1148
- while [[ -n "${parent}" ]]; do
1149
- if [[ -e "${parent}/package.json" ]]; then
1150
- get_package_engine_version "${parent}/package.json"
1151
- else
1152
- parent=${parent%/*}
1153
- continue
1154
- fi
1155
- break
1156
- done
1157
- [[ -n "${parent}" ]] || abort "${error_message}"
1158
- [[ -n "${g_target_node}" ]] || abort "did not find supported version of node in 'engines' field of package.json"
1159
- }
1160
-
1161
- #
1162
- # Synopsis: get_auto_version
1163
- # Sets g_target_node
1164
- #
1165
-
1166
- function get_auto_version() {
1167
- g_target_node=
1168
- # Search for a version control file first
1169
- local parent
1170
- parent="${PWD}"
1171
- while [[ -n "${parent}" ]]; do
1172
- if [[ -e "${parent}/.n-node-version" ]]; then
1173
- get_file_node_version "${parent}/.n-node-version"
1174
- elif [[ -e "${parent}/.node-version" ]]; then
1175
- get_file_node_version "${parent}/.node-version"
1176
- elif [[ -e "${parent}/.nvmrc" ]]; then
1177
- get_nvmrc_version "${parent}/.nvmrc"
1178
- else
1179
- parent=${parent%/*}
1180
- continue
1181
- fi
1182
- break
1183
- done
1184
- # Fallback to package.json
1185
- [[ -n "${parent}" ]] || get_engine_version "no file found for auto version (.n-node-version, .node-version, .nvmrc, or package.json)"
1186
- [[ -n "${g_target_node}" ]] || abort "file found for auto did not contain target version of node"
1187
- }
1188
-
1189
- #
1190
- # Synopsis: get_latest_resolved_version version
1191
- # Sets g_target_node
1192
- #
1193
-
1194
- function get_latest_resolved_version() {
1195
- g_target_node=
1196
- local version=${1}
1197
- simple_version=${version#node/} # Only place supporting node/ [sic]
1198
- if is_exact_numeric_version "${simple_version}"; then
1199
- # Just numbers, already resolved, no need to lookup first.
1200
- simple_version="${simple_version#v}"
1201
- g_target_node="${simple_version}"
1202
- else
1203
- # Complicated recognising exact version, KISS and lookup.
1204
- g_target_node=$(N_MAX_REMOTE_MATCHES=1 display_remote_versions "$version")
1205
- fi
1206
- }
1207
-
1208
- #
1209
- # Synopsis: display_remote_index
1210
- # index.tab reference: https://github.com/nodejs/nodejs-dist-indexer
1211
- # Index fields are: version date files npm v8 uv zlib openssl modules lts security
1212
- # KISS and just return fields we currently care about: version files lts
1213
- #
1214
-
1215
- display_remote_index() {
1216
- local index_url="${g_mirror_url}/index.tab"
1217
- # tail to remove header line
1218
- do_get_index "${index_url}" | tail -n +2 | cut -f 1,3,10
1219
- if [[ "${PIPESTATUS[0]}" -ne 0 ]]; then
1220
- # Reminder: abort will only exit subshell, but consistent error display
1221
- abort "failed to download version index (${index_url})"
1222
- fi
1223
- }
1224
-
1225
- #
1226
- # Synopsis: display_match_limit limit
1227
- #
1228
-
1229
- function display_match_limit(){
1230
- if [[ "$1" -gt 1 && "$1" -lt 32000 ]]; then
1231
- echo "Listing remote... Displaying $1 matches (use --all to see all)."
1232
- fi
1233
- }
1234
-
1235
- #
1236
- # Synopsis: display_remote_versions version
1237
- #
1238
-
1239
- function display_remote_versions() {
1240
- local version="$1"
1241
- update_mirror_settings_for_version "${version}"
1242
- local match='.'
1243
- local match_count="${N_MAX_REMOTE_MATCHES}"
1244
-
1245
- # Transform some labels before processing further.
1246
- if is_node_support_version "${version}"; then
1247
- version="$(display_latest_node_support_alias "${version}")"
1248
- match_count=1
1249
- elif [[ "${version}" = "auto" ]]; then
1250
- # suppress stdout logging so lsr layout same as usual for scripting
1251
- get_auto_version || return 2
1252
- version="${g_target_node}"
1253
- elif [[ "${version}" = "engine" ]]; then
1254
- # suppress stdout logging so lsr layout same as usual for scripting
1255
- get_engine_version || return 2
1256
- version="${g_target_node}"
1257
- fi
1258
-
1259
- if [[ -z "${version}" ]]; then
1260
- match='.'
1261
- elif [[ "${version}" = "lts" || "${version}" = "stable" ]]; then
1262
- match_count=1
1263
- # Codename is last field, first one with a name is newest lts
1264
- match="${TAB_CHAR}[a-zA-Z]+\$"
1265
- elif [[ "${version}" = "latest" || "${version}" = "current" ]]; then
1266
- match_count=1
1267
- match='.'
1268
- elif is_numeric_version "${version}"; then
1269
- version="v${version#v}"
1270
- # Avoid restriction message if exact version
1271
- is_exact_numeric_version "${version}" && match_count=1
1272
- # Quote any dots in version so they are literal for expression
1273
- match="${version//\./\.}"
1274
- # Avoid 1.2 matching 1.23
1275
- match="^${match}[^0-9]"
1276
- elif is_lts_codename "${version}"; then
1277
- # Capitalise (could alternatively make grep case insensitive)
1278
- codename="$(echo "${version:0:1}" | tr '[:lower:]' '[:upper:]')${version:1}"
1279
- # Codename is last field
1280
- match="${TAB_CHAR}${codename}\$"
1281
- elif is_download_folder "${version}"; then
1282
- match='.'
1283
- elif is_download_version "${version}"; then
1284
- version="${version#"${g_mirror_folder_name}"/}"
1285
- if [[ "${version}" = "latest" || "${version}" = "current" ]]; then
1286
- match_count=1
1287
- match='.'
1288
- else
1289
- version="v${version#v}"
1290
- match="${version//\./\.}"
1291
- match="^${match}" # prefix
1292
- if is_numeric_version "${version}"; then
1293
- # Exact numeric match
1294
- match="${match}[^0-9]"
1295
- fi
1296
- fi
1297
- else
1298
- abort "invalid version '$1'"
1299
- fi
1300
- display_match_limit "${match_count}"
1301
-
1302
- # Implementation notes:
1303
- # - using awk rather than head so do not close pipe early on curl
1304
- # - restrict search to compatible files as not always available, or not at same time
1305
- # - return status of curl command (i.e. PIPESTATUS[0])
1306
- display_remote_index \
1307
- | n_grep -E "$(display_compatible_file_field)" \
1308
- | n_grep -E "${match}" \
1309
- | awk "NR<=${match_count}" \
1310
- | cut -f 1 \
1311
- | n_grep -E -o '[^v].*'
1312
- return "${PIPESTATUS[0]}"
1313
- }
1314
-
1315
- #
1316
- # Synopsis: delete_with_echo target
1317
- #
1318
-
1319
- function delete_with_echo() {
1320
- if [[ -e "$1" ]]; then
1321
- echo "$1"
1322
- rm -rf "$1"
1323
- fi
1324
- }
1325
-
1326
- #
1327
- # Synopsis: uninstall_installed
1328
- # Uninstall the installed node and npm (leaving alone the cache),
1329
- # so undo install, and may expose possible system installed versions.
1330
- #
1331
-
1332
- uninstall_installed() {
1333
- # npm: https://docs.npmjs.com/misc/removing-npm
1334
- # rm -rf /usr/local/{lib/node{,/.npm,_modules},bin,share/man}/npm*
1335
- # node: https://stackabuse.com/how-to-uninstall-node-js-from-mac-osx/
1336
- # Doing it by hand rather than scanning cache, so still works if cache deleted first.
1337
- # This covers tarballs for at least node 4 through 10.
1338
-
1339
- while true; do
1340
- read -r -p "Do you wish to delete node and npm from ${N_PREFIX}? " yn
1341
- case $yn in
1342
- [Yy]* ) break ;;
1343
- [Nn]* ) exit ;;
1344
- * ) echo "Please answer yes or no.";;
1345
- esac
1346
- done
1347
-
1348
- echo ""
1349
- echo "Uninstalling node and npm"
1350
- delete_with_echo "${N_PREFIX}/bin/node"
1351
- delete_with_echo "${N_PREFIX}/bin/npm"
1352
- delete_with_echo "${N_PREFIX}/bin/npx"
1353
- delete_with_echo "${N_PREFIX}/bin/corepack"
1354
- delete_with_echo "${N_PREFIX}/include/node"
1355
- delete_with_echo "${N_PREFIX}/lib/dtrace/node.d"
1356
- delete_with_echo "${N_PREFIX}/lib/node_modules/npm"
1357
- delete_with_echo "${N_PREFIX}/lib/node_modules/corepack"
1358
- delete_with_echo "${N_PREFIX}/share/doc/node"
1359
- delete_with_echo "${N_PREFIX}/share/man/man1/node.1"
1360
- delete_with_echo "${N_PREFIX}/share/systemtap/tapset/node.stp"
1361
- }
1362
-
1363
- #
1364
- # Synopsis: show_permission_suggestions
1365
- #
1366
-
1367
- function show_permission_suggestions() {
1368
- echo "Suggestions:"
1369
- echo "- run n with sudo, or"
1370
- echo "- define N_PREFIX to a writeable location, or"
1371
- }
1372
-
1373
- #
1374
- # Synopsis: show_diagnostics
1375
- # Show environment and check for common problems.
1376
- #
1377
-
1378
- function show_diagnostics() {
1379
- echo "This information is to help you diagnose issues, and useful when reporting an issue."
1380
- echo "Note: some output may contain passwords. Redact before sharing."
1381
-
1382
- printf "\n\nCOMMAND LOCATIONS AND VERSIONS\n"
1383
-
1384
- printf "\nbash\n"
1385
- command -v bash && bash --version
1386
-
1387
- printf "\nn\n"
1388
- command -v n && n --version
1389
-
1390
- printf "\nnode\n"
1391
- if command -v node &> /dev/null; then
1392
- command -v node && node --version
1393
- node -e 'if (process.versions.v8) console.log("JavaScript engine: v8");'
1394
-
1395
- printf "\nnpm\n"
1396
- command -v npm && npm --version
1397
- fi
1398
-
1399
- printf "\ntar\n"
1400
- if command -v tar &> /dev/null; then
1401
- command -v tar && tar --version
1402
- else
1403
- echo_red "tar not found. Needed for extracting downloads."
1404
- fi
1405
-
1406
- printf "\ncurl or wget\n"
1407
- if command -v curl &> /dev/null; then
1408
- command -v curl && curl --version
1409
- elif command -v wget &> /dev/null; then
1410
- command -v wget && wget --version
1411
- else
1412
- echo_red "Neither curl nor wget found. Need one of them for downloads."
1413
- fi
1414
-
1415
- printf "\nuname\n"
1416
- uname -a
1417
-
1418
- printf "\n\nSETTINGS\n"
1419
-
1420
- printf "\nn\n"
1421
- echo "node mirror: ${N_NODE_MIRROR}"
1422
- echo "node downloads mirror: ${N_NODE_DOWNLOAD_MIRROR}"
1423
- echo "install destination: ${N_PREFIX}"
1424
- [[ -n "${N_PREFIX}" ]] && echo "PATH: ${PATH}"
1425
- echo "ls-remote max matches: ${N_MAX_REMOTE_MATCHES}"
1426
- [[ -n "${N_PRESERVE_NPM}" ]] && echo "installs preserve npm by default"
1427
- [[ -n "${N_PRESERVE_COREPACK}" ]] && echo "installs preserve corepack by default"
1428
-
1429
- printf "\nProxy\n"
1430
- # disable "var is referenced but not assigned": https://github.com/koalaman/shellcheck/wiki/SC2154
1431
- # shellcheck disable=SC2154
1432
- [[ -n "${http_proxy}" ]] && echo "http_proxy: ${http_proxy}"
1433
- # shellcheck disable=SC2154
1434
- [[ -n "${https_proxy}" ]] && echo "https_proxy: ${https_proxy}"
1435
- if command -v curl &> /dev/null; then
1436
- # curl supports lower case and upper case!
1437
- # shellcheck disable=SC2154
1438
- [[ -n "${all_proxy}" ]] && echo "all_proxy: ${all_proxy}"
1439
- [[ -n "${ALL_PROXY}" ]] && echo "ALL_PROXY: ${ALL_PROXY}"
1440
- [[ -n "${HTTP_PROXY}" ]] && echo "HTTP_PROXY: ${HTTP_PROXY}"
1441
- [[ -n "${HTTPS_PROXY}" ]] && echo "HTTPS_PROXY: ${HTTPS_PROXY}"
1442
- if [[ -e "${CURL_HOME}/.curlrc" ]]; then
1443
- echo "have \$CURL_HOME/.curlrc"
1444
- elif [[ -e "${HOME}/.curlrc" ]]; then
1445
- echo "have \$HOME/.curlrc"
1446
- fi
1447
- elif command -v wget &> /dev/null; then
1448
- if [[ -e "${WGETRC}" ]]; then
1449
- echo "have \$WGETRC"
1450
- elif [[ -e "${HOME}/.wgetrc" ]]; then
1451
- echo "have \$HOME/.wgetrc"
1452
- fi
1453
- fi
1454
-
1455
- printf "\n\nCHECKS\n"
1456
-
1457
- printf "\nChecking n install destination is in PATH...\n"
1458
- local install_bin="${N_PREFIX}/bin"
1459
- local path_wth_guards=":${PATH}:"
1460
- if [[ "${path_wth_guards}" =~ :${install_bin}/?: ]]; then
1461
- printf "good\n"
1462
- else
1463
- echo_red "'${install_bin}' is not in PATH"
1464
- fi
1465
- if command -v node &> /dev/null; then
1466
- printf "\nChecking n install destination priority in PATH...\n"
1467
- local node_dir="$(dirname "$(command -v node)")"
1468
-
1469
- local index=0
1470
- local path_entry
1471
- local path_entries
1472
- local install_bin_index=0
1473
- local node_index=999
1474
- IFS=':' read -ra path_entries <<< "${PATH}"
1475
- for path_entry in "${path_entries[@]}"; do
1476
- (( index++ ))
1477
- [[ "${path_entry}" =~ ^${node_dir}/?$ ]] && node_index="${index}"
1478
- [[ "${path_entry}" =~ ^${install_bin}/?$ ]] && install_bin_index="${index}"
1479
- done
1480
- if [[ "${node_index}" -lt "${install_bin_index}" ]]; then
1481
- echo_red "There is a version of node installed which will be found in PATH before the n installed version."
1482
- else
1483
- printf "good\n"
1484
- fi
1485
- fi
1486
-
1487
- printf "\nChecking permissions for cache folder...\n"
1488
- # Most likely problem is ownership rather than than permissions as such.
1489
- local cache_root="${N_PREFIX}/n"
1490
- if [[ -e "${N_PREFIX}" && ! -w "${N_PREFIX}" && ! -e "${cache_root}" ]]; then
1491
- echo_red "You do not have write permission to create: ${cache_root}"
1492
- show_permission_suggestions
1493
- echo "- make a folder you own:"
1494
- echo " sudo mkdir -p \"${cache_root}\""
1495
- echo " sudo chown $(whoami) \"${cache_root}\""
1496
- elif [[ -e "${cache_root}" && ! -w "${cache_root}" ]]; then
1497
- echo_red "You do not have write permission to: ${cache_root}"
1498
- show_permission_suggestions
1499
- echo "- change folder ownership to yourself:"
1500
- echo " sudo chown -R $(whoami) \"${cache_root}\""
1501
- elif [[ ! -e "${cache_root}" ]]; then
1502
- echo "Cache folder does not exist: ${cache_root}"
1503
- echo "This is normal if you have not done an install yet, as cache is only created when needed."
1504
- elif [[ -e "${CACHE_DIR}" && ! -w "${CACHE_DIR}" ]]; then
1505
- echo_red "You do not have write permission to: ${CACHE_DIR}"
1506
- show_permission_suggestions
1507
- echo "- change folder ownership to yourself:"
1508
- echo " sudo chown -R $(whoami) \"${CACHE_DIR}\""
1509
- else
1510
- echo "good"
1511
- fi
1512
-
1513
- if [[ -e "${N_PREFIX}" ]]; then
1514
- # Most likely problem is ownership rather than than permissions as such.
1515
- printf "\nChecking permissions for install folders...\n"
1516
- local install_writeable="true"
1517
- for subdir in bin lib include share; do
1518
- if [[ -e "${N_PREFIX}/${subdir}" && ! -w "${N_PREFIX}/${subdir}" ]]; then
1519
- install_writeable="false"
1520
- echo_red "You do not have write permission to: ${N_PREFIX}/${subdir}"
1521
- break
1522
- fi
1523
- done
1524
- if [[ "${install_writeable}" = "true" ]]; then
1525
- echo "good"
1526
- else
1527
- show_permission_suggestions
1528
- echo "- change folder ownerships to yourself:"
1529
- echo " (cd \"${N_PREFIX}\" && sudo chown -R $(whoami) bin lib include share)"
1530
- fi
1531
- fi
1532
-
1533
- printf "\nChecking mirror is reachable...\n"
1534
- if is_ok "${N_NODE_MIRROR}/"; then
1535
- printf "good\n"
1536
- else
1537
- echo_red "mirror not reachable"
1538
- printf "Showing failing command and output\n"
1539
- if command -v curl &> /dev/null; then
1540
- ( set -x; do_get --head "${N_NODE_MIRROR}/" )
1541
- else
1542
- ( set -x; do_get --spider "${N_NODE_MIRROR}/" )
1543
- printf "\n"
1544
- fi
1545
- fi
1546
- }
1547
-
1548
- #
1549
- # Handle arguments.
1550
- #
1551
-
1552
- # First pass. Process the options so they can come before or after commands,
1553
- # particularly for `n lsr --all` and `n install --arch x686`
1554
- # which feel pretty natural.
1555
-
1556
- unprocessed_args=()
1557
- positional_arg="false"
1558
-
1559
- while [[ $# -ne 0 ]]; do
1560
- case "$1" in
1561
- --all) N_MAX_REMOTE_MATCHES=32000 ;;
1562
- -V|--version) display_n_version ;;
1563
- -h|--help|help) display_help; exit ;;
1564
- -q|--quiet) set_quiet ;;
1565
- -d|--download) DOWNLOAD="true" ;;
1566
- --insecure) set_insecure ;;
1567
- -p|--preserve) N_PRESERVE_NPM="true" N_PRESERVE_COREPACK="true" ;;
1568
- --no-preserve) N_PRESERVE_NPM="" N_PRESERVE_COREPACK="" ;;
1569
- --use-xz) N_USE_XZ="true" ;;
1570
- --no-use-xz) N_USE_XZ="false" ;;
1571
- --latest) display_remote_versions latest; exit ;;
1572
- --stable) display_remote_versions lts; exit ;; # [sic] old terminology
1573
- --lts) display_remote_versions lts; exit ;;
1574
- -a|--arch) shift; set_arch "$1";; # set arch and continue
1575
- exec|run|as|use)
1576
- unprocessed_args+=( "$1" )
1577
- positional_arg="true"
1578
- ;;
1579
- *)
1580
- if [[ "${positional_arg}" == "true" ]]; then
1581
- unprocessed_args+=( "$@" )
1582
- break
1583
- fi
1584
- unprocessed_args+=( "$1" )
1585
- ;;
1586
- esac
1587
- shift
1588
- done
1589
-
1590
- if [[ -z "${N_USE_XZ+defined}" ]]; then
1591
- N_USE_XZ="true" # Default to using xz
1592
- can_use_xz || N_USE_XZ="false"
1593
- fi
1594
-
1595
- set -- "${unprocessed_args[@]}"
1596
-
1597
- if test $# -eq 0; then
1598
- test -z "$(display_versions_paths)" && err_no_installed_print_help
1599
- menu_select_cache_versions
1600
- else
1601
- while test $# -ne 0; do
1602
- case "$1" in
1603
- bin|which) display_bin_path_for_version "$2"; exit ;;
1604
- run|as|use) shift; run_with_version "$@"; exit ;;
1605
- exec) shift; exec_with_version "$@"; exit ;;
1606
- doctor) show_diagnostics; exit ;;
1607
- rm|-) shift; remove_versions "$@"; exit ;;
1608
- prune) prune_cache; exit ;;
1609
- latest) install latest; exit ;;
1610
- stable) install stable; exit ;;
1611
- lts) install lts; exit ;;
1612
- ls|list) display_versions_paths; exit ;;
1613
- lsr|ls-remote|list-remote) shift; display_remote_versions "$1"; exit ;;
1614
- uninstall) uninstall_installed; exit ;;
1615
- i|install) shift; install "$1"; exit ;;
1616
- N_TEST_DISPLAY_LATEST_RESOLVED_VERSION) shift; get_latest_resolved_version "$1" > /dev/null || exit 2; echo "${g_target_node}"; exit ;;
1617
- *) install "$1"; exit ;;
1618
- esac
1619
- shift
1620
- done
1621
- fi