This repository has been archived by the owner on Mar 25, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathsetup.sh
executable file
·470 lines (370 loc) · 16.2 KB
/
setup.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
#!/usr/bin/env bash
# Run this script prior to running `yarn install` on the host,
# in order to setup and configure yarn correctly before using it.
# Note this is an alternative to checking in the yarn release itself.
# NOTE: This script also runs as the entrypoint of every JS container
# Simply run:
# ./setup.sh
SPLITGRAPH_DIR=${1-"$(cd -P -- "$(dirname -- "$0")" && pwd -P)"}
# If `yarn --version` is not exact match of `$TARGET_YARN_VERSION`, install yarn
TARGET_YARN_VERSION="${TARGET_YARN_VERSION-"2.4.2"}"
prep_env() {
echo "Ensure yq..." \
&& ensure_yq \
&& echo "Ensure yarn..." \
&& ensure_yarn \
&& return 0
return 1
}
ensure_yq() {
if ! which yq && test -f node_modules/.bin/yq ; then
ln -s /src/js/node_modules/.bin/yq /usr/bin/yq
fi
if ! which yq || ! ( yq -V | grep -q 4.13.2 ) ; then
echo "Warning: yq is required but not installed"
YQ_VERSION="${YQ_VERSION-"v4.13.2"}"
echo "Attempting install: yq $YQ_VERSION"
set -x
# if we don't have (the right version of) yq, it's probably because we're
# iterating on this script. save it to node_modules so it's in a volume
# that persists across each container that shares the node_modules volume
mkdir -p /src/js/node_modules/.bin
curl -L "https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_linux_amd64" \
-o /src/js/node_modules/.bin/yq \
&& chmod +x /src/js/node_modules/.bin/yq \
&& ln -s /src/js/node_modules/.bin/yq /usr/bin/yq
set +x
which yq || { echo "Failed to install required binary yq" ; exit 1 ; }
fi
}
ensure_yarn() {
set -e
if ! dir_has_yarn_release "$SPLITGRAPH_DIR" ; then
# yarn 1 will not allow us to do anything but `yarn set version berry`
# so we need to install berry first, then we can install our pinned version
echo "Install yarn berry so we can install our target version"
set -e
pushd "$SPLITGRAPH_DIR"
yarn set version berry
berry_saved_to="$(yarn config get yarnPath)"
echo "-- .yarnrc.yml"
cat .yarnrc.yml
echo "--"
echo "Now install the target version ($TARGET_YARN_VERSION)"
set -e
saved_to="$(yarn set version "${TARGET_YARN_VERSION}" \
| grep -i 'saving' \
| grep "$TARGET_YARN_VERSION" \
| awk '{ print $NF }')"
set +e
echo "Saved to: $saved_to"
if test -f "$saved_to" && test "$(dirname "$saved_to")" != "$(dirname ".yarn/releases/.")" ; then
echo "Need to move newly installed file into .yarn dir"
mv "$saved_to" .yarn/releases/
fi
set_version_to=".yarn/releases/$(ls -t .yarn/releases/ | head -n1)"
echo "Delete .yarnrc.yml with wrong version and overwrite it"
echo "yarnPath: $set_version_to" > .yarnrc.yml
# rm .yarnrc.yml
# echo "Set version to: $set_version_to"
# yarn config set yarnPath "$set_version_to"
berry_saved_to_workspace="$(dirname $(dirname $(dirname "$berry_saved_to")))"
parent_dir_yarnrc="$berry_saved_to_workspace/.yarnrc.yml"
echo "berry_saved_to_workspace=$berry_saved_to_workspace"
if [[ $PWD/ = /$berry_saved_to_workspace/* ]] ; then
# todo: might want to save it beforehand and have a way to recover
echo "Berry was installed to parent, so delete that .yarnrc too"
# we're assuming it's in a dir called .yarn/releases
berry_saved_to_workspace="$(dirname $(dirname $(dirname "$berry_saved_to")))"
parent_dir_yarnrc="$berry_saved_to_workspace/.yarnrc.yml"
if test -f "$parent_dir_yarnrc" ; then
echo "delete: $parent_dir_yarnrc"
rm "$parent_dir_yarnrc"
fi
fi
if test -f "$berry_saved_to" ; then
echo "Delete yarn berry: $berry_saved_to"
rm "$berry_saved_to"
fi
popd
# yarn set version "$saved_to"
echo "Installed: $(yarn --version)"
# Yarn berry changes the name of the yarn executable in some releases,
# but we want to make sure it's called yarn-berry.js for consistency,
# and for referencing it in dockerfiles, etc.
# So, account for their various historical name changes.
# when a new dev joins with a fresh install of yarn, they may have
# changed the naming again, so look here for a fix.
# Account for releases with naming scheme yarn-rc.js
if test -f "$SPLITGRAPH_DIR"/.yarn/releases/yarn-rc.js ; then
mv "$SPLITGRAPH_DIR"/.yarn/releases/yarn-rc.js \
"$SPLITGRAPH_DIR"/.yarn/releases/yarn-berry.js \
&& sed -i 's/yarn-rc/yarn-berry/' "$SPLITGRAPH_DIR"/.yarnrc.yml
fi
# Account for releases with naming scheme yarn-2*.(js|cjs)
if ls "$SPLITGRAPH_DIR"/.yarn/releases/yarn-2* 2>/dev/null ; then
echo "found this one: "
ls "$SPLITGRAPH_DIR"/.yarn/releases/yarn-2*
mv "$SPLITGRAPH_DIR"/.yarn/releases/yarn-2* \
"$SPLITGRAPH_DIR"/.yarn/releases/yarn-berry.js \
&& sed -Ei 's/yarn-[0-9+\.]+\.(cjs|js)/yarn-berry.js/' "$SPLITGRAPH_DIR"/.yarnrc.yml
fi
# Account for releases with naming scheme yarn-3*.(js|cjs)
if ls "$SPLITGRAPH_DIR"/.yarn/releases/yarn-3* 2>/dev/null ; then
mv "$SPLITGRAPH_DIR"/.yarn/releases/yarn-3* \
"$SPLITGRAPH_DIR"/.yarn/releases/yarn-berry.js \
&& sed -Ei 's/yarn-[0-9+\.]+\.(cjs|js)/yarn-berry.js/' "$SPLITGRAPH_DIR"/.yarnrc.yml
fi
# Account for releases with naming scheme yarn-berry.cjs
if test -f "$SPLITGRAPH_DIR"/.yarn/releases/yarn-berry.cjs ; then
mv "$SPLITGRAPH_DIR"/.yarn/releases/yarn-berry.cjs \
"$SPLITGRAPH_DIR"/.yarn/releases/yarn-berry.js \
&& sed -i 's/yarn-berry\.cjs/yarn-berry\.js/' "$SPLITGRAPH_DIR"/.yarnrc.yml
fi
fi
pushd "$SPLITGRAPH_DIR"
has_correct_config || setup_yarn
popd
if ! dir_has_yarn_plugins "$SPLITGRAPH_DIR" ; then
echo "Install yarn plugins into $SPLITGRAPH_DIR"
install_plugins "$SPLITGRAPH_DIR"
fi
if ! dir_has_local_plugins "$SPLITGRAPH_DIR" ; then
echo "Install local plugins into $SPLITGRAPH_DIR"
install_local_plugins "$SPLITGRAPH_DIR"
fi
set +e
return 0
}
# By convention, assume all `yarn-plugin-*.js` files represent our plugins
# (naive assumption, but we only have yarn-plugin-pin-deps.js atm so it works)
find_local_plugins() {
find . -type f -name 'yarn-plugin-*.js' ! -path '*node-modules*'
}
# we just want to set the yml item for the local plugin to a string with its file path
# but `yarn plugin import` copies target to a new file and sets it as "spec"
# so unfortunately instead of `yarn plugin import`, need to mangle the YML
install_local_plugins() {
local prefixDir="$1"
shift
local yarnrcFile
yarnrcFile="$(get_yarnrc_file "$prefixDir")"
pushd "$prefixDir"
while read -r localPluginPath ; do
if yarnrc_has_local_plugin "$yarnrcFile" ; then
echo "[$yarnrcFile] skip install plugin, already imported: $localPluginPath"
continue
fi
echo "[$yarnrcFile] add local plugin: $localPluginPath"
yq -i eval '.plugins = .plugins + "'"$localPluginPath"'"' "$yarnrcFile"
done < <(find_local_plugins)
popd
}
# unfortunately cannot simply use `yarn plugin import` for local plugins,
# because it copies the file to .yarn/plugins and sets original as "spec"
dir_has_local_plugins() {
local prefixDir="$1"
shift
yarnrcFile="$(get_yarnrc_file "$prefixDir")"
pushd "$prefixDir"
while read -r localPluginPath ; do
if yarnrc_has_local_plugin "$yarnrcFile" "$localPluginPath" ; then
echo "[$yarnrcFile] check plugin, already imported: $localPluginPath"
continue
fi
popd
return 1
done < <(find_local_plugins)
popd
return 0
}
yarnrc_has_local_plugin() {
local yarnrcFile="$1"
shift
local localPluginPath="$1"
shift
if [[ "true" == "$(yq eval 'contains({"plugins": "'"$localPluginPath"'"})' "$yarnrcFile" )" ]] ; then
return 0
fi
return 1
}
install_plugins() {
local prefixDir="$1"
shift
WORKSPACE_TOOLS='https://raw.githubusercontent.com/yarnpkg/berry/%40yarnpkg/plugin-workspace-tools/2.2.0/packages/plugin-workspace-tools/bin/%40yarnpkg/plugin-workspace-tools.js'
CONSTRAINTS='https://raw.githubusercontent.com/yarnpkg/berry/%40yarnpkg/plugin-constraints/2.2.0/packages/plugin-constraints/bin/%40yarnpkg/plugin-constraints.js'
INTERACTIVE_TOOLS='https://raw.githubusercontent.com/yarnpkg/berry/%40yarnpkg/plugin-interactive-tools/2.2.0/packages/plugin-interactive-tools/bin/%40yarnpkg/plugin-interactive-tools.js'
pushd "$prefixDir" && yarn plugin import https://raw.githubusercontent.com/milesforks/yarn-plugin-workspace-lockfile/main/packages/plugin/bundles/%40yarnpkg/plugin-workspace-lockfile.js \
&& popd
pushd "$prefixDir" && yarn plugin import "$INTERACTIVE_TOOLS" && popd
pushd "$prefixDir" && yarn plugin import "$CONSTRAINTS" && popd
pushd "$prefixDir" && yarn plugin import "$WORKSPACE_TOOLS" && popd
# Yarn sometimes releases workspace tools with .js and .cjs (tbh, maybe all .cjs now)
# AFAICT it costs nothing to rename this to .js to standardize our checked in versions
if test -f "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs ; then
mv "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs \
"$prefixDir"/.yarn/plugins/@yarnpkg/plugin-workspace-tools.js
fi
if test -f "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs ; then
mv "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs \
"$prefixDir"/.yarn/plugins/@yarnpkg/plugin-interactive-tools.js
fi
if test -f "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-workspace-lockfile.cjs ; then
mv "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-workspace-lockfile.cjs \
"$prefixDir"/.yarn/plugins/@yarnpkg/plugin-workspace-lockfile.js
fi
if test -f "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-constraints.cjs ; then
mv "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-constraints.cjs \
"$prefixDir"/.yarn/plugins/@yarnpkg/plugin-constraints.js
fi
fix_yarnrc() {
local yarnrcFile="$1"
shift
grep 'plugin-workspace-tools' "$yarnrcFile" \
&& sed -i 's/plugin-workspace-tools\.cjs/plugin-workspace-tools\.js/' "$yarnrcFile"
grep 'plugin-interactive-tools' "$yarnrcFile" \
&& sed -i 's/plugin-interactive-tools\.cjs/plugin-interactive-tools\.js/' "$yarnrcFile"
grep 'plugin-workspace-lockfile' "$yarnrcFile" \
&& sed -i 's/plugin-workspace-lockfile\.cjs/plugin-workspace-lockfile\.js/' "$yarnrcFile"
grep 'plugin-constraints' "$yarnrcFile" \
&& sed -i 's/plugin-constraints\.cjs/plugin-constraints\.js/' "$yarnrcFile"
return 0
}
# todo: Is it actually possible to have a .yarnrc named either of these things? Maybe was
# earlier code covering a corner case that no longer exists? But is harmless to check both.
fix_yarnrc "$(get_yarnrc_file "$prefixDir")"
return 0
}
dir_has_yarn_release() {
local prefixDir="$1"
shift
echo "Dir has yarn release?"
# Clean up old files that are deprecated and shouldn't be checked in anymore if they exist
if test -f "$prefixDir"/.yarn/releases/yarn-rc.js ; then
rm -f "$prefixDir"/.yarn/releases/yarn-rc.js
fi
if test -f "$prefixDir"/.yarn/releases/yarn-berry.cjs ; then
rm -f "$prefixDir"/.yarn/releases/yarn-berry.cjs
fi
if test -f "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs ; then
rm -f "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
fi
if test -f "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs ; then
rm -f "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
fi
if test -f "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-workspace-lockfile.cjs ; then
rm -f "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-workspace-lockfile.cjs
fi
if test -f "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-constraints.cjs ; then
rm -f "$prefixDir"/.yarn/plugins/@yarnpkg/plugin-constraints.cjs
fi
if has_broken_yarn "$prefixDir" ; then
echo "yarn seems broken in $prefixDir, remove .yarnrc.yml"
rm -f "$prefixDir"/.yarnrc.yml
return 1
fi
if has_wrong_yarn_version "$prefixDir" ; then
echo "yarn seems outdated in $prefixDir, return 1 to trick into upgrade"
rm -f "$prefixDir"/.yarnrc.yml
return 1
fi
test -f "$prefixDir"/.yarn/releases/yarn-berry.js \
&& return 0
return 1
}
get_yarnrc_file() {
local prefixDir="$1"
shift
local yarnrcFile
if test -f "$prefixDir"/.yarnrc ; then
yarnrcFile=""$prefixDir"/.yarnrc"
elif test -f "$prefixDir"/.yarnrc.yml ; then
yarnrcFile=""$prefixDir"/.yarnrc.yml"
else
echo "/dev/null"
echo "warning: yarnrc file not found" 2>&1
fi
echo "$yarnrcFile"
}
dir_has_yarn_plugins() {
yarnrcFile="$(get_yarnrc_file "$1")"
grep -q 'plugin-workspace-tools.js' "$yarnrcFile" \
&& grep -q 'plugin-interactive-tools.js' "$yarnrcFile" \
&& grep -q 'plugin-workspace-lockfile.js' "$yarnrcFile" \
&& grep -q 'plugin-constraints.js' "$yarnrcFile" \
&& return 0
return 1
}
# OPTIONAL:
# If $TARGET_YARN_VERSION is set, then `yarn --version` must be exact match
has_wrong_yarn_version() {
# specifying a target version is optional, so bail out if not specified
if test -z "$TARGET_YARN_VERSION" ; then
return 1
fi
local prefixDir="$1"
shift
pushd "$prefixDir"
local yarn_version
yarn_version="$(yarn --version)"
# For now we just check exact match
if test "$yarn_version" != "$TARGET_YARN_VERSION" ; then
echo "yarn --version ($yarn_version) is not TARGET_YARN_VERSION ($TARGET_YARN_VERSION)"
popd && return 0
fi
popd && return 1
}
# Sometimes a mismatch between .yarnrc.yml yarnPath and the actual yarn file
# can cause yarn to fail to start due to looking for the wrong file
has_broken_yarn() {
local prefixDir="$1"
shift
pushd "$prefixDir"
if ! yarn config >/dev/null 2>/dev/null ; then
echo "Broken yarn"
popd && return 0
fi
popd && return 1
}
setup_yarn() {
if test ! -z "$WORKSPACE_LOCKFILE" ; then
echo "set the lockfile to $WORKSPACE_LOCKFILE"
# We need to remove any existing directive, because otherwise yarn config set
# will not override the setting if yarnrc.yml says it's yarn.lock
sed -i '/lockfileFilename:/d' "$(yarn config get rcFilename)"
yarn config set lockfileFilename "$WORKSPACE_LOCKFILE"
fi
yarn config set nodeLinker node-modules \
&& return 0
return 1
}
has_correct_config() {
# If user has specified a custom lockfile name, make sure it's set correctly
if test ! -z "$WORKSPACE_LOCKFILE" \
&& test "$(yarn config get lockfileFilename)" != "$WORKSPACE_LOCKFILE" ; then
echo "lockfile is wrong, need to set it"
return 1
fi
# (hacky, but efficient)
# We want to be as fast as possible. So to avoid calling `yarn config` twice,
# take a shortcut: run `yarn config` once, grep for one line we expect to
# be there, and verify the line count is 1. Specifically, we expect that
# `nodeLinker === node-modules`. Note we do not check for cache folder because
# this is set by an environment variable (see export_envvars)
yarn config \
| grep -E 'node-modules' \
| wc -l \
| grep -qE 1$ \
&& return 0
return 1
}
export DEBUG=1
if test -n "$DEBUG" && test "$DEBUG" == "1" ; then
prep_env || { echo "Fatal error." ; exit 1 ; }
else
prep_env >/dev/null || { \
echo "Fatal error in setup.sh. (note: message may have been sent to /dev/null)"; \
exit 1 ;\
}
fi
exit 0