Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Respect XDG basedir spec #27

Merged
merged 13 commits into from
Sep 2, 2019
33 changes: 17 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@

[![Build Status](https://travis-ci.org/nodenv/nodenv-default-packages.svg)](https://travis-ci.org/nodenv/nodenv-default-packages)

This nodenv plugin hooks into the `nodenv install` command to automatically
install `npm` packages every time you install a new version of Node. It
requires the `node-build` plugin to be installed.
This nodenv plugin hooks into the `nodenv install` command to automatically install `npm` packages every time you install a new version of Node.
It requires the `node-build` plugin to be installed.

Forked from the excellent [`rbenv-default-gems`][rbenv-default-gems] plugin from
[sstephenson][sstephenson].
Forked from the excellent [`rbenv-default-gems`][rbenv-default-gems] plugin from [sstephenson][sstephenson].

<!-- toc -->

- [Installation](#installation)
* [Installing as a nodenv plugin](#installing-as-a-nodenv-plugin)
* [Installing with Homebrew (for OS X users)](#installing-with-homebrew-for-os-x-users)
- [Usage](#usage)
* [default-packages Files](#default-packages-files)
* [Updating Default Packages](#updating-default-packages)
- [Credits](#credits)

Expand All @@ -30,11 +29,9 @@ Make sure you have the latest nodenv and node-build versions, then run:

### Installing with Homebrew (for OS X users)

Mac OS X users can install nodenv-default-packages with the
[Homebrew](http://brew.sh) package manager.
Mac OS X users can install nodenv-default-packages with the [Homebrew](http://brew.sh) package manager.

*This is the recommended method of installation if you installed nodenv
with Homebrew.*
*This is the recommended method of installation if you installed nodenv with Homebrew.*

```
$ brew install nodenv/nodenv/nodenv-default-packages
Expand All @@ -48,25 +45,28 @@ $ brew install --HEAD nodenv/nodenv/nodenv-default-packages

## Usage

nodenv-default-packages automatically installs the packages listed in the
`$(nodenv root)/default-packages` file every time you successfully install a new
version of Node with `nodenv install`.
nodenv-default-packages automatically installs the packages listed in the [default-packages file(s)](#default-packages-files) file every time you successfully install a new version of Node with `nodenv install`.

Specify packages in `$(nodenv root)/default-packages` by name, one per line. You may
optionally specify a semver version spec after the name. For example:
Specify packages in `default-packages` by name, one per line.
You may optionally specify a semver version spec after the name. For example:

grunt-cli
jshint ~2.6.3
csslint >= 0.9.0 < 0.10.0

Blank lines and lines beginning with a `#` are ignored.

### default-packages Files

nodenv-default-packages reads from `$(nodenv root)/default-packages` as well as `nodenv/default-packages` under all [XDG config directories][xdg].
The XDG config directories searched are `$XDG_CONFIG_HOME` (`$HOME/.config` if unset/empty) and all colon-separated `$XDG_CONFIG_DIRS` (`/etc/xdg` if unset/empty).

### Updating Default Packages

if you update your `$(nodenv root)/default-packages` and want to refresh some or all of
your existing node installations you can use commands like this:
if you update your `$(nodenv root)/default-packages` and want to refresh some or all of your existing node installations you can use commands like this:

nodenv default-packages install 8.8.1 # Reinstall default packages on Node version 8.8.1

nodenv default-packages install --all # Reinstall default packages on _all_ installed Node versions

*NOTE:* This may take some time.
Expand All @@ -79,3 +79,4 @@ Forked from [Sam Stephenson][sstephenson]'s [rbenv-default-gems][] by [Josh Hagi
[rbenv-default-gems]: https://github.com/rbenv/rbenv-default-gems
[jawshooah]: https://github.com/jawshooah
[nodenv]: https://github.com/nodenv/nodenv
[xdg]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
36 changes: 25 additions & 11 deletions bin/nodenv-default-packages
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
# Usage:
# nodenv default-packages list
# nodenv default-packages install [ --all | <version>...]
# nodenv default-packages files
#

set -eo pipefail
[ -n "$NODENV_DEBUG" ] && set -x

# Provide nodenv completions
if [ "$1" = --complete ]; then
echo files
echo install
echo list
echo --all
Expand All @@ -39,16 +41,9 @@ for_versions() {

# Read package names and versions from $NODENV_ROOT/default-packages
list_default_packages() {
[ -r "${NODENV_ROOT}/default-packages" ] || {
echo "No default-package file found" >&2
exit 1
}

local pkg_name pkg_version

# strip comments and empty lines
sed -e 's/#.*$//g' -e '/^[[:space:]]*$/d' "${NODENV_ROOT}/default-packages" |

default_packages_files |
tr '\n' '\0' | # replace newlines with nullchar so we can use xargs
xargs -0 sed -e 's/#.*$//g' -e '/^[[:space:]]*$/d' | # strip comments and empty lines
while IFS=" " read -r pkg_name pkg_version; do
echo "${pkg_name}${pkg_version:+@$pkg_version}"
done
Expand Down Expand Up @@ -78,14 +73,33 @@ install_default_packages() {
}
}

default_packages_files() {
local file_found

IFS=: read -ra xdg_dirs <<< "${XDG_CONFIG_HOME:-$HOME/.config}:${XDG_CONFIG_DIRS:-/etc/xdg}"

for dir in "$NODENV_ROOT" "${xdg_dirs[@]/%//nodenv}"; do
if test -r "$dir/default-packages"; then
echo "$_" && file_found=true
fi
done

if [ -z "${file_found:-}" ]; then
echo "nodenv: default-packages file not found" >&2
return 1
fi
}

unset cmd

case "$1" in
install ) for_versions install_default_packages "${@:2}" ;;

list ) list_default_packages ;;

-h | --help ) nodenv-help; exit ;;
files ) default_packages_files ;;

-h | --help ) nodenv-help ;;

*) nodenv-help --usage default-packages; exit 1 ;;
esac
68 changes: 68 additions & 0 deletions test/files.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env bats

load test_helper

@test "file errors if file not found" {
run nodenv default-packages files

assert_failure
assert_output "nodenv: default-packages file not found"
}

@test "file finds default-packages in NODENV_ROOT" {
with_file "$NODENV_ROOT/default-packages" <<<""

run nodenv default-packages files

assert_success
assert_output "$NODENV_ROOT/default-packages"
}

@test "file finds default-packages in default XDG_CONFIG_HOME" {
with_file "$HOME/.config/nodenv/default-packages" <<<""

run nodenv default-packages files

assert_success
assert_output "$HOME/.config/nodenv/default-packages"
}

@test "file finds default-packages in configured XDG_CONFIG_HOME" {
XDG_CONFIG_HOME=$HOME/myconfig
with_file "$XDG_CONFIG_HOME/nodenv/default-packages" <<<""

XDG_CONFIG_HOME="$XDG_CONFIG_HOME" run nodenv default-packages files

assert_success
assert_output "$XDG_CONFIG_HOME/nodenv/default-packages"
}

@test "file finds default-packages in configured XDG_CONFIG_DIRS" {
with_file "$HOME/myconfig/nodenv/default-packages" <<<""

XDG_CONFIG_DIRS="$HOME/myconfig:other" run nodenv default-packages files

assert_success
assert_output "$HOME/myconfig/nodenv/default-packages"
}

@test "file finds default-packages in default XDG_CONFIG_DIRS" {
skip "can't fake /etc/xdg"
}

@test "file finds multiple files" {
with_file "$NODENV_ROOT/default-packages" <<<""
with_file "$HOME/.config/nodenv/default-packages" <<<""
with_file "$HOME/myconfig/nodenv/default-packages" <<<""
with_file "$HOME/theirconfig/nodenv/default-packages" <<<""

XDG_CONFIG_DIRS="$HOME/myconfig:$HOME/theirconfig" run nodenv default-packages files

assert_success
assert_output - <<-OUT
$NODENV_ROOT/default-packages
$HOME/.config/nodenv/default-packages
$HOME/myconfig/nodenv/default-packages
$HOME/theirconfig/nodenv/default-packages
OUT
}
2 changes: 1 addition & 1 deletion test/hook.bats
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
load test_helper

@test "nodenv-install hook auto installs packages" {
with_default_packages_file <<< fake-package
with_file "$NODENV_ROOT/default-packages" <<< fake-package

run nodenv install 0.10.36

Expand Down
36 changes: 32 additions & 4 deletions test/install.bats
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ load test_helper
run nodenv default-packages install 1.2.3

assert_failure
refute_output "No default-packages file found"
assert_output "nodenv: default-packages file not found"
}

@test "install, without a version, installs to current node version" {
nodenv install --no-hooks 10.0.0
with_default_packages_file <<< fake-package
with_file "$NODENV_ROOT/default-packages" <<< fake-package

NODENV_VERSION=10.0.0 run nodenv default-packages install

Expand All @@ -21,7 +21,7 @@ load test_helper

@test "install accepts node version to which to install" {
nodenv install --no-hooks 10.0.0
with_default_packages_file <<< fake-package
with_file "$NODENV_ROOT/default-packages" <<< fake-package

run nodenv default-packages install 10.0.0

Expand All @@ -31,10 +31,38 @@ load test_helper

@test "install npm-installs single package" {
nodenv install --no-hooks 10.0.0
with_default_packages_file <<< fake-package
with_file "$NODENV_ROOT/default-packages" <<< fake-package

run nodenv default-packages install 10.0.0

assert_success
assert_output -p "npm invoked with: 'install -g fake-package'"
}

@test "install combines all default-packages files" {
nodenv install --no-hooks 10.0.0
with_file "$NODENV_ROOT/default-packages" <<< pkg-from-nodenv-root
with_file "$HOME/.config/nodenv/default-packages" <<< pkg-from-config-home
with_file "$HOME/myconfig/nodenv/default-packages" <<< pkg-from-config-dirs1
with_file "$HOME/theirconfig/nodenv/default-packages" <<< pkg-from-config-dirs2

XDG_CONFIG_DIRS="$HOME/myconfig:$HOME/theirconfig" NODENV_VERSION=10.0.0 run nodenv default-packages install

assert_success
assert_output -p "npm invoked with: 'install -g pkg-from-nodenv-root'"
assert_output -p "npm invoked with: 'install -g pkg-from-config-home'"
assert_output -p "npm invoked with: 'install -g pkg-from-config-dirs1'"
assert_output -p "npm invoked with: 'install -g pkg-from-config-dirs2'"
}

@test "install handles filenames with spaces" {
nodenv install --no-hooks 10.0.0
with_file "$HOME/my config/nodenv/default-packages" <<< pkg-from-config-dirs1
with_file "$HOME/their config/nodenv/default-packages" <<< pkg-from-config-dirs2

XDG_CONFIG_DIRS="$HOME/my config:$HOME/their config" NODENV_VERSION=10.0.0 run nodenv default-packages install

assert_success
assert_output -p "npm invoked with: 'install -g pkg-from-config-dirs1'"
assert_output -p "npm invoked with: 'install -g pkg-from-config-dirs2'"
}
3 changes: 1 addition & 2 deletions test/installer.bats
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ load test_helper

@test "overwrites old installation" {
cd "$BATS_TMPDIR"
mkdir -p etc/nodenv.d/install
touch etc/nodenv.d/install/default-packages.bash
with_file etc/nodenv.d/install/default-packages.bash <<<""

PREFIX="$PWD" run "${BATS_TEST_DIRNAME}/../install.sh"
assert_success
Expand Down
4 changes: 2 additions & 2 deletions test/list.bats
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ load test_helper
}

@test "list default-packages" {
with_default_packages_file <<< fake-package
with_file "$NODENV_ROOT/default-packages" <<< fake-package

run nodenv default-packages list

Expand All @@ -19,7 +19,7 @@ load test_helper
}

@test "list skips comments and empty lines" {
with_default_packages_file <<-PKGS
with_file "$NODENV_ROOT/default-packages" <<-PKGS
fake-package

# comment
Expand Down
16 changes: 13 additions & 3 deletions test/test_helper.bash
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ setup() {
unset "$nodenv_var"
done

# unset all XDG_ vars
local xdg_var
for xdg_var in $(env 2>/dev/null | grep '^XDG_' | cut -d= -f1); do
unset "$xdg_var"
done

# set a restricted PATH (test bin, app bin, and node bin, no homebrew)
local test_bin="$BATS_TEST_DIRNAME/bin"
local package_bin="$BATS_TEST_DIRNAME/../bin"
Expand All @@ -26,17 +32,21 @@ setup() {

mkdir -p "$BATS_TMPDIR"
testdir=$(mktemp -d "$BATS_TMPDIR/$BATS_TEST_NAME.XXX") || exit 1

export NODENV_ROOT=$testdir/nodenv_root
mkdir -p "$NODENV_ROOT"

export HOME=$testdir/home
mkdir -p "$HOME/.config/nodenv"

export NODENV_HOOK_PATH="$BATS_TEST_DIRNAME/../etc/nodenv.d"
}

teardown() {
rm -rf "$BATS_TMPDIR" # same as BATS_MOCK_TMPDIR
}

with_default_packages_file() {
touch "$NODENV_ROOT/default-packages"
cat - >> "$NODENV_ROOT/default-packages"
with_file() {
mkdir -p "$(dirname "$1")"
cat - > "$1"
}