Skip to content

Is there a deterministic way of checking whether bundle exec is necessary? #486

@mculp

Description

@mculp

Sort of related to #433, I've recently found out that bundle exec adds a significant amount of time to commands as opposed to the naked command when the binstub doesn't exist. This is especially important when running linters as a pre-commit hook.

I posted on lefthook's discussion board about this, but our team mostly uses chruby in local environments because it's in our onboarding guide, and y'all seem to more likely to know the answer to this: is there a deterministic or even near-deterministic way of checking whether bundle exec is necessary?

I came up with this pretty naive exec-wrapper script:

#!/usr/bin/env sh

if test -n "$RUBY_VERSION"
then
  if test -x "$0"
  then
    exec "$@"
  elif test -x chruby-exec
  then
    chruby-exec "$RUBY_VERSION" -- "$@"
  fi
else
  bundle exec "$@"
fi
Command Mean [ms] Min [ms] Max [ms] Relative
rubocop --server ... 190.9 ± 5.9 183.4 199.9 1.00
bin/exec-wrapper rubocop --server ... 200.2 ± 8.4 184.1 212.1 1.05 ± 0.05
chruby-exec 3.1.2 -- rubocop --server ... 210.5 ± 7.8 195.2 222.7 1.10 ± 0.05
bundle exec rubocop ... 709.4 ± 5.2 702.7 716.7 3.72 ± 0.12
Benchmark 1: bin/exec-wrapper rubocop --server ...
  Time (mean ± σ):     197.1 ms ±   4.9 ms    [User: 93.1 ms, System: 30.3 ms]
  Range (min … max):   186.4 ms … 202.3 ms    14 runs

Benchmark 2: rubocop --server ...
  Time (mean ± σ):     189.4 ms ±   7.3 ms    [User: 92.3 ms, System: 28.8 ms]
  Range (min … max):   173.7 ms … 200.5 ms    15 runs

Benchmark 3: bundle exec rubocop --server ...
  Time (mean ± σ):     706.4 ms ±   5.3 ms    [User: 567.1 ms, System: 64.8 ms]
  Range (min … max):   699.2 ms … 715.6 ms    10 runs

Benchmark 4: chruby-exec 3.1.2 -- rubocop ...
  Time (mean ± σ):     212.0 ms ±   5.2 ms    [User: 98.5 ms, System: 34.4 ms]
  Range (min … max):   203.9 ms … 219.4 ms    14 runs

Summary
  'rubocop --server ...
    1.04 ± 0.05 times faster than 'bin/exec-wrapper rubocop --server ...'
    1.12 ± 0.05 times faster than 'chruby-exec 3.1.2 -- rubocop --server ...'
    3.73 ± 0.15 times faster than 'bundle exec rubocop --server ...'

I would like to commit this pretty significant quality of life change, but I don't want to break anyone's machine by missing something in this script.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions