Skip to content

Instantly share code, notes, and snippets.

@bgotink
Last active March 30, 2022 18:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bgotink/6e56bbee5f1657b72aaf6c409486e8c4 to your computer and use it in GitHub Desktop.
Save bgotink/6e56bbee5f1657b72aaf6c409486e8c4 to your computer and use it in GitHub Desktop.
Yarn wrapper script to use checked in yarn version without installing it globally
#!/usr/bin/env bash
#
# Wrapper script that executes the yarn version checked in in a project without
# requiring the global package to be available.
#
# This script uses nvm when a .nvmrc file is found next to it.
#
# Usage:
# - Place yarnw into the folder containing your .yarnrc / .yarnrc.yml file
# pointing to a local yarn version.
# - Replace calls to yarn with calls to `./yarnw`
#
# Environment:
# - NVM_DIR: if set, and a .nvmrc is found next to this wrapper script, load nvm
# from this folder instead of the default ~/.nvm
# - YARNW_SKIP_NVM: if set, yarnw ignores any nvmrc file
#
# @author Bram Gotink <bram@gotink.me> [https://github.com/bgotink]
# @license Public Domain
# @source https://gist.github.com/bgotink/6e56bbee5f1657b72aaf6c409486e8c4
# fail fast, fail hard
set -e
ROOT="$(cd "$(dirname "$0")" && pwd)"
function die {
echo "$@" >&2
exit 1
}
function has_command {
command -v "$1" >/dev/null || return 1
}
function run_node {
if [ -f "$ROOT/.nvmrc" ] && [ "_${YARNW_SKIP_NVM}" == "_" ]; then
if ! has_command nvm; then
local actual_nvm_dir="${NVM_DIR:-$HOME/.nvm}"
if ! [ -d "$actual_nvm_dir" ] || ! [ -s "${actual_nvm_dir}/nvm.sh" ]; then
die 'This repository contains a .nvmrc but nvm was not found'
fi
source "${actual_nvm_dir}/nvm.sh"
fi
cd "$ROOT"
nvm use >/dev/null
cd - >/dev/null 2>&1
fi
if has_command node; then
exec node "$@"
elif has_command nodejs; then
exec nodejs "$@"
else
die 'No NodeJS found'
fi
}
function parse_yarn_path_from_syml {
local yarnrc="$ROOT/.yarnrc"
if ! [ -f "$yarnrc" ]; then
return 1
fi
grep -E '^yarn-path' "$yarnrc" | sed -e 's|^yarn-path||' -e 's|^:||' -e 's|^[[:space:]]*||' -e 's|"\(.*\)"|\1|'
}
function parse_yarn_path_from_yaml {
local yarnrc="$ROOT/.yarnrc.yml"
if ! [ -f "$yarnrc" ]; then
return 1
fi
# Modified from https://stackoverflow.com/a/21189044
local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
sed -ne "s|^\($s\):|\1|" \
-e "s|^\($s\)\($w\)$s:$s[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p" \
-e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" "$yarnrc" |
awk -F$fs '{
if (length($1) == 0) {
if ($2 == "yarnPath") {
printf("%s", $3);
}
}
}'
}
yarn="$ROOT/$(parse_yarn_path_from_yaml || parse_yarn_path_from_syml || die 'No local yarn path found, use the global yarn instead of yarnw')"
YARN_IGNORE_PATH=1 run_node "$yarn" "$@"

The author disclaims copyright to this source code. In place of a legal notice, here is a blessing:

  • May you do good and not evil.
  • May you find forgiveness for yourself and forgive others.
  • May you share freely, never taking more than you give.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment