Skip to content

Commit

Permalink
Adds '--choose-env' flag to use rbenv if available, otherwise rvm
Browse files Browse the repository at this point in the history
  • Loading branch information
mnussbaum committed Oct 25, 2013
1 parent 17b50f1 commit 702ecad
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 18 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -2,3 +2,4 @@
.bundle
Gemfile.lock
pkg/*
/vendor/bundle
17 changes: 16 additions & 1 deletion README.md
Expand Up @@ -26,7 +26,8 @@ The gem provides an executable called ```subcontract``` that you will use from y
```
USAGE: subcontract [options] -- executable
-r, --rvm RVM run in a specific RVM (use `.` for ruby from `PATH`)
-b, --rbenv RBENV run in a specific RBENV
-b, --rbenv RBENV run in a specific RBENV (use `.` for local rbenv)
-c, --choose-env ENV run in either a specified RBENV or RVM, whichever is present
-d, --chdir PATH chdir to PATH before starting process
-s, --signal SIGNAL signal to send to process to kill it, default TERM
```
Expand All @@ -53,6 +54,19 @@ You can use specific rbenv version.
rbenv_app: bundle exec subcontract --rbenv 'ree-1.8.7-2012.02' --chdir ~/rbenv_app -- bundle exec rails server -p 3001
```

Or you can use whatever the local rbenv settings are for a project. This will load whatever `rbenv local` returns out of the current folder once it has been changed to the folder specified by --chdir

```
rbenv_app: bundle exec subcontract --rbenv . --chdir ~/rbenv_app -- bundle exec rails server -p 3001
```

If you have team members using both rvm and rbenv on a project then use --choose-env to use whatever version manager is present on the system. If both are present rbenv is chosen.

```
mixed_env_manager_app: bundle exec subcontract --choose-env . --chdir ~/mixed_env_manager_app -- bundle exec rails server -p 3001
```


### Contributions
* Fork the project
* Make your change
Expand All @@ -65,3 +79,4 @@ rbenv_app: bundle exec subcontract --rbenv 'ree-1.8.7-2012.02' --chdir ~/rbenv_a
* Paul Gross [github](http://github.com/pgr0ss) [blog](http://www.pgrs.net) [twitter](http://twitter.com/pgr0ss)
* Rune Skjoldborg Madsen [github](https://github.com/runemadsen)
* Masahiro Ihara [github](http://github.com/ihara2525) [twitter](http://twitter.com/ihara2525)
* Michael Nussbaum [github](https://github.com/mnussbaum)
30 changes: 13 additions & 17 deletions lib/subcontractor/cli.rb
@@ -1,11 +1,12 @@
require 'optparse'
require 'pty'
require "optparse"
require "pty"
require "subcontractor/command"

$stdout.sync = true

module SafePty
def self.spawn command, &block
if Object.const_defined?('Bundler')
if Object.const_defined?("Bundler")
Bundler.with_clean_env do
self.clear_more_env
self.spawn_internal command, &block
Expand All @@ -29,16 +30,15 @@ def self.spawn_internal command, &block
end

def self.clear_more_env
['GEM_HOME', 'GEM_PATH', 'RUBYOPT', 'RBENV_DIR'].each { |e| ENV.delete(e) }
["GEM_HOME", "GEM_PATH", "RUBYOPT", "RBENV_DIR"].each { |e| ENV.delete(e) }
end
end

module Subcontractor
class CLI

def run
options = parse_options(ARGV)
command = build_command(ARGV.dup, options)
command = Subcontractor::Command.build(ARGV, options)
Dir.chdir(options[:chdir]) if options[:chdir]
signal = options[:signal] || "TERM"
SafePty.spawn(command) do |stdin, stdout, pid|
Expand Down Expand Up @@ -74,33 +74,29 @@ def find_child_pids(pids)
end.map(&:first).map(&:to_i)
end

def build_command(parts, options)
parts.unshift("rvm #{options[:rvm]} exec") if options.has_key?(:rvm)
parts.unshift("env RBENV_VERSION=#{options[:rbenv]} rbenv exec") if options.has_key?(:rbenv)
parts.join(' ')
end

def parse_options(argv)
options = {}
parser = OptionParser.new do |opt|
opt.banner = "USAGE: subcontract [options] -- executable"
opt.on('-r', '--rvm RVM', 'run in a specific RVM') do |rvm|
opt.on("-r", "--rvm RVM", "run in a specific RVM") do |rvm|
options[:rvm] = rvm
end
opt.on('-b', '--rbenv RBENV', 'run in a specific RBENV') do |rbenv|
opt.on("-b", "--rbenv RBENV", "run in a specific RBENV") do |rbenv|
options[:rbenv] = rbenv
end
opt.on('-d', '--chdir PATH', 'chdir to PATH before starting process') do |path|
opt.on("-c", "--choose-env ENV", "run in either specified RBENV or RVM, whichever is present") do |env|
options[:choose_env] = env
end
opt.on("-d", "--chdir PATH", "chdir to PATH before starting process") do |path|
options[:chdir] = path
end
opt.on('-s', '--signal SIGNAL', 'signal to send to process to kill it, default TERM') do |signal|
opt.on("-s", "--signal SIGNAL", "signal to send to process to kill it, default TERM") do |signal|
options[:signal] = signal
end
end

parser.parse! argv
options
end

end
end
40 changes: 40 additions & 0 deletions lib/subcontractor/command.rb
@@ -0,0 +1,40 @@
module Subcontractor
class Command
def self.build(parts, options)
new(parts.dup, options).build
end

def initialize(parts, options)
@parts = parts
@options = options
end

def build
if _use_command?(:rbenv)
@parts.unshift("#{_set_rbenv_version} rbenv exec")
elsif _use_command?(:rvm)
@parts.unshift("rvm #{_env_specifier(:rvm)} exec")
end

@parts.join(" ")
end

def _use_command?(command)
@options.has_key?(command) || _choose_env_and_command_present?(command)
end

def _choose_env_and_command_present?(command)
@options.has_key?(:choose_env) && system("which #{command} > /dev/null 2>&1")
end

def _set_rbenv_version
env_specifier = _env_specifier(:rbenv)
env_specifier = "`rbenv local`" if env_specifier == "."
"env RBENV_VERSION=#{env_specifier}"
end

def _env_specifier(command)
@options[command] || @options[:choose_env]
end
end
end
6 changes: 6 additions & 0 deletions spec/spec_helper.rb
@@ -0,0 +1,6 @@
require "subcontractor"
require "subcontractor/cli"

RSpec.configure do |config|
config.color = true
end
54 changes: 54 additions & 0 deletions spec/subcontractor/cli_spec.rb
@@ -0,0 +1,54 @@
require "spec_helper"

describe Subcontractor::CLI do
before(:each) do
Object.instance_eval{ remove_const(:ARGV) }
end

describe "#run" do
it "uses rvm with --rvm" do
ARGV = ["--rvm", ".", "test"]
SafePty.should_receive(:spawn).with("rvm . exec test")
Subcontractor::CLI.new.run
end

context "with --rbenv" do
it "specifies a rbenv" do
ARGV = ["--rbenv", "1.9.3", "test"]
SafePty.should_receive(:spawn).with("env RBENV_VERSION=1.9.3 rbenv exec test")
Subcontractor::CLI.new.run
end

it "uses 'rbenv local' if a '.' is given as the rbenv version" do
ARGV = ["--rbenv", ".", "test"]
SafePty.should_receive(:spawn).with("env RBENV_VERSION=`rbenv local` rbenv exec test")
Subcontractor::CLI.new.run
end
end

it "creates a valid command if no environment manager is specifed" do
ARGV = ["test"]
SafePty.should_receive(:spawn).with("test")
Subcontractor::CLI.new.run
end

context "with --choose-env" do
it "uses rbenv when rbenv is present" do
ARGV = ["--choose-env", "1.9.3", "test"]
SafePty.should_receive(:spawn).with("env RBENV_VERSION=1.9.3 rbenv exec test")
command = Subcontractor::Command.any_instance
command.should_receive(:system).with("which rbenv > /dev/null 2>&1").and_return(true)
Subcontractor::CLI.new.run
end

it "uses rvm when rvm is present and rbenv isn't" do
ARGV = ["--choose-env", ".", "test"]
SafePty.should_receive(:spawn).with("rvm . exec test")
command = Subcontractor::Command.any_instance
command.should_receive(:system).with("which rbenv > /dev/null 2>&1").and_return(false)
command.should_receive(:system).with("which rvm > /dev/null 2>&1").and_return(true)
Subcontractor::CLI.new.run
end
end
end
end
2 changes: 2 additions & 0 deletions subcontractor.gemspec
Expand Up @@ -14,6 +14,8 @@ Gem::Specification.new do |s|

s.rubyforge_project = "subcontractor"

s.add_development_dependency("rspec")

s.files = `git ls-files`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]
Expand Down

0 comments on commit 702ecad

Please sign in to comment.