nkryptic-sandbox 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,156 @@
1
+
2
+ require 'fileutils'
3
+ require 'erb'
4
+
5
+ module Sandbox
6
+
7
+ class Installer
8
+
9
+ ## CLASS METHODS
10
+ class << self
11
+ end
12
+ ## END CLASS METHODS
13
+
14
+ attr_accessor :options
15
+
16
+ ## PUBLIC INSTANCE METHODS
17
+ public
18
+
19
+ def initialize( options={} )
20
+ @options = options.dup
21
+ @target = nil
22
+ end
23
+
24
+ def target
25
+ return @target unless @target.nil?
26
+ @target = resolve_target( options[ :target ] )
27
+ end
28
+
29
+ def populate
30
+ puts "creating sandbox at: #{target}" if Sandbox.verbose?
31
+ create_directories
32
+ install_scripts
33
+ install_gems
34
+ end
35
+
36
+ def create_directories
37
+ bin = File.join( target, 'bin' )
38
+ gembin = File.join( target, 'rubygems', 'bin' )
39
+
40
+ # mkdir /path/to/sandbox/
41
+ # mkdir /path/to/sandbox/rubygems
42
+ # mkdir /path/to/sandbox/rubygems/bin
43
+ FileUtils.mkdir_p( gembin )
44
+
45
+ # ln -s /path/to/sandbox/rubygems/bin /path/to/sandbox/bin
46
+ # symlink the bin directory, because when gems are installed, binaries are
47
+ # installed in GEM_HOME/bin
48
+ FileUtils.ln_s( gembin, bin )
49
+ end
50
+
51
+ def install_scripts
52
+ filename = File.join( target, 'bin', 'activate_sandbox' )
53
+ template = File.read( File.dirname( __FILE__ ) + '/templates/activate_sandbox.erb' )
54
+ script = ERB.new( template )
55
+ output = script.result( binding )
56
+ File.open( filename, 'w' ) do |f|
57
+ f.write output
58
+ end
59
+ end
60
+
61
+ def install_gems
62
+ # gem = `which gem`.chomp
63
+ # return if gem.empty?
64
+ puts "installing gems" if Sandbox.verbose?
65
+ begin
66
+ setup_sandbox_env
67
+ options[ :gems ].each do |gem|
68
+ puts " gem: #{gem}" if Sandbox.verbose?
69
+ cmd = "gem install #{gem}"
70
+ # cmd = cmd + ' -V' if Sandbox.really_verbose?
71
+ status, output = shell_out( cmd )
72
+ unless status
73
+ warn "failed to install gem: #{gem}"
74
+ end
75
+ end
76
+ ensure
77
+ restore_sandbox_env
78
+ end
79
+ end
80
+
81
+ def shell_out( cmd )
82
+ # err_capture = Sandbox.really_verbose? '2>&1' : '2>/dev/null'
83
+ # out = `#{cmd} #{err_capture}`
84
+ out = `#{cmd} 2>/dev/null`
85
+ result = $?.exitstatus == 0
86
+ [ result, out ]
87
+ end
88
+
89
+ def setup_sandbox_env
90
+ @old_env = Hash[ *ENV.select { |k,v| ['HOME','GEM_HOME','GEM_PATH'].include?( k ) }.flatten ]
91
+ # @old_env = {}
92
+ # @old_env[ 'HOME' ] = ENV[ 'HOME' ]
93
+ # @old_env[ 'GEM_HOME' ] = ENV[ 'GEM_HOME' ]
94
+ # @old_env[ 'GEM_PATH' ] = ENV[ 'GEM_PATH' ]
95
+
96
+ ENV[ 'HOME' ] = target
97
+ ENV[ 'GEM_HOME' ] = "#{target}/rubygems"
98
+ ENV[ 'GEM_PATH' ] = "#{target}/rubygems"
99
+ end
100
+
101
+ def restore_sandbox_env
102
+ ENV.update( @old_env )
103
+ # ENV[ 'HOME' ] = @old_env[ 'HOME' ]
104
+ # ENV[ 'GEM_HOME' ] = @old_env[ 'GEM_HOME' ]
105
+ # ENV[ 'GEM_PATH' ] = @old_env[ 'GEM_PATH' ]
106
+ end
107
+
108
+ def resolve_target( path )
109
+ # should consider replacing with 'pathname' => Pathname.new( path )
110
+ path = fix_path( path )
111
+ if File.exists?( path )
112
+ raise Sandbox::Error, "target '#{path}' exists"
113
+ end
114
+
115
+ base = path
116
+ while base = File.dirname( base )
117
+ if check_path!( base )
118
+ break
119
+ elsif base == '/'
120
+ break
121
+ end
122
+ end
123
+ return path
124
+ end
125
+
126
+ def check_path!( path )
127
+ if File.directory?( path )
128
+ if File.writable?( path )
129
+ return true
130
+ else
131
+ raise Sandbox::Error, "path '#{path}' has a permission problem"
132
+ end
133
+ elsif File.exists?( path )
134
+ raise Sandbox::Error, "path '#{path}' is not a directory"
135
+ end
136
+ false
137
+ end
138
+
139
+ def fix_path( path )
140
+ unless path.index( '/' ) == 0
141
+ path = File.join( FileUtils.pwd, path )
142
+ end
143
+ path
144
+ end
145
+
146
+ ## END PUBLIC INSTANCE METHODS
147
+
148
+
149
+ ## PRIVATE INSTANCE METHODS
150
+ private
151
+
152
+ ## END PRIVATE INSTANCE METHODS
153
+
154
+ end
155
+
156
+ end
@@ -0,0 +1,91 @@
1
+
2
+ # This file must be used with "source bin/activate" *from bash*
3
+ # you cannot run it directly
4
+
5
+ deactivate_sandbox () {
6
+ if [ -n "$_OLD_SANDBOX_PATH" ] ; then
7
+ PATH="$_OLD_SANDBOX_PATH"
8
+ export PATH
9
+ unset _OLD_SANDBOX_PATH
10
+ fi
11
+
12
+ if [ -n "$_OLD_SANDBOX_HOME" ] ; then
13
+ HOME="$_OLD_SANDBOX_HOME"
14
+ export HOME
15
+ unset _OLD_SANDBOX_HOME
16
+ fi
17
+
18
+ # This should detect bash and zsh, which have a hash command that must
19
+ # be called to get it to forget past commands. Without forgetting
20
+ # past commands the $PATH changes we made may not be respected
21
+ if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
22
+ hash -r
23
+ fi
24
+
25
+ if [ -n "$_OLD_SANDBOX_GEM_HOME" ] ; then
26
+ GEM_HOME="$_OLD_SANDBOX_GEM_HOME"
27
+ export GEM_HOME
28
+ unset _OLD_SANDBOX_GEM_HOME
29
+ fi
30
+
31
+ if [ -n "$_OLD_SANDBOX_GEM_PATH" ] ; then
32
+ GEM_PATH="$_OLD_SANDBOX_GEM_PATH"
33
+ export GEM_PATH
34
+ unset _OLD_SANDBOX_GEM_PATH
35
+ fi
36
+
37
+ if [ -n "$_OLD_SANDBOX_PS1" ] ; then
38
+ PS1="$_OLD_SANDBOX_PS1"
39
+ export PS1
40
+ unset _OLD_SANDBOX_PS1
41
+ fi
42
+
43
+ # unset again, in case they were missed because they were blank
44
+ unset _OLD_SANDBOX_GEM_HOME
45
+ unset _OLD_SANDBOX_GEM_PATH
46
+
47
+ unset SANDBOX_ENV
48
+ if [ ! "$1" = "nondestructive" ] ; then
49
+ # Self destruct!
50
+ unset deactivate_sandbox
51
+ fi
52
+ }
53
+
54
+ # unset irrelavent variables
55
+ deactivate_sandbox nondestructive
56
+
57
+ SANDBOX_ENV="<%= target %>"
58
+ export SANDBOX_ENV
59
+
60
+ _OLD_SANDBOX_PATH="$PATH"
61
+ PATH="$SANDBOX_ENV/bin:$PATH"
62
+ export PATH
63
+
64
+ _OLD_SANDBOX_HOME="$HOME"
65
+ HOME="$SANDBOX_ENV"
66
+ export HOME
67
+
68
+ _OLD_SANDBOX_GEM_HOME="$GEM_HOME"
69
+ GEM_HOME="$SANDBOX_ENV/rubygems"
70
+ export GEM_HOME
71
+
72
+ _OLD_SANDBOX_GEM_PATH="$GEM_PATH"
73
+ GEM_PATH="$GEM_HOME"
74
+ export GEM_PATH
75
+
76
+ _OLD_SANDBOX_PS1="$PS1"
77
+ if [ "`basename \"$SANDBOX_ENV\"`" = "__" ] ; then
78
+ # special case for Aspen magic directories
79
+ # see http://www.zetadev.com/software/aspen/
80
+ PS1="[sandbox:`basename \`dirname \"$SANDBOX_ENV\"\``] $PS1"
81
+ else
82
+ PS1="(sandbox:`basename \"$SANDBOX_ENV\"`)$PS1"
83
+ fi
84
+ export PS1
85
+
86
+ # This should detect bash and zsh, which have a hash command that must
87
+ # be called to get it to forget past commands. Without forgetting
88
+ # past commands the $PATH changes we made may not be respected
89
+ if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
90
+ hash -r
91
+ fi
@@ -0,0 +1,15 @@
1
+
2
+ module Sandbox
3
+
4
+ class Version #:nodoc:
5
+
6
+ MAJOR = 0
7
+ MINOR = 2
8
+ TINY = 0
9
+
10
+ STRING = [ MAJOR, MINOR, TINY ].join( '.' )
11
+
12
+ end
13
+
14
+ end
15
+
data/lib/sandbox.rb ADDED
@@ -0,0 +1,33 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless \
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+
5
+ module Sandbox
6
+
7
+ class << self
8
+
9
+ def verbosity
10
+ @verbosity ||= 0
11
+ end
12
+
13
+ def increase_verbosity
14
+ @verbosity = verbosity + 1
15
+ end
16
+
17
+ def decrease_verbosity
18
+ @verbosity = verbosity - 1
19
+ end
20
+
21
+ def quiet?() verbosity < 0 end
22
+ def really_quiet?() verbosity < 1 end
23
+ def verbose?() verbosity > 0 end
24
+ def really_verbose?() verbosity > 1 end
25
+
26
+ end
27
+
28
+ end
29
+
30
+ require 'sandbox/version'
31
+ require 'sandbox/errors'
32
+ require 'sandbox/installer'
33
+
data/sandbox.gemspec ADDED
@@ -0,0 +1,43 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{sandbox}
5
+
6
+ s.version = "0.2.0"
7
+
8
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
9
+ s.authors = ["Jacob Radford"]
10
+ s.date = %q{2008-12-01}
11
+ s.default_executable = %q{sandbox}
12
+ s.description = %q{Create virtual ruby/rubygems sandboxes.}
13
+ s.email = %q{nkryptic@gmail.com}
14
+ s.executables = ["sandbox"]
15
+ s.extra_rdoc_files = ["CHANGELOG", "TODO", "README.rdoc", "tasks/rspec.rake", "tasks/cucumber.rake", "tasks/gem.rake", "tasks/dcov.rake", "lib/sandbox.rb", "lib/sandbox/installer.rb", "lib/sandbox/cli.rb", "lib/sandbox/templates/activate_sandbox.erb", "lib/sandbox/version.rb", "lib/sandbox/errors.rb", "bin/sandbox"]
16
+ s.files = ["sandbox.gemspec", "CHANGELOG", "TODO", "spec/sandbox/cli_spec.rb", "spec/sandbox/installer_spec.rb", "spec/sandbox_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "Manifest", "features/steps/common.rb", "features/steps/env.rb", "features/development.feature", "README.rdoc", "tasks/rspec.rake", "tasks/cucumber.rake", "tasks/gem.rake", "tasks/dcov.rake", "Rakefile", "lib/sandbox.rb", "lib/sandbox/installer.rb", "lib/sandbox/cli.rb", "lib/sandbox/templates/activate_sandbox.erb", "lib/sandbox/version.rb", "lib/sandbox/errors.rb", "bin/sandbox"]
17
+ s.has_rdoc = true
18
+ s.homepage = %q{http://github.com/nkryptic/sandbox}
19
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Sandbox", "--main", "README.rdoc"]
20
+ s.require_paths = ["lib"]
21
+ s.rubyforge_project = %q{sandbox}
22
+ s.rubygems_version = %q{1.3.1}
23
+ s.summary = %q{Create virtual ruby/rubygems sandboxes.}
24
+
25
+ if s.respond_to? :specification_version then
26
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
27
+ s.specification_version = 2
28
+
29
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
30
+ s.add_development_dependency(%q<echoe>, ["~> 0", "= 3.0"])
31
+ s.add_development_dependency(%q<rspec>, ["~> 0", "= 1.1.0"])
32
+ s.add_development_dependency(%q<mocha>, ["~> 0", "= 0.9"])
33
+ else
34
+ s.add_dependency(%q<echoe>, ["~> 0", "= 3.0"])
35
+ s.add_dependency(%q<rspec>, ["~> 0", "= 1.1.0"])
36
+ s.add_dependency(%q<mocha>, ["~> 0", "= 0.9"])
37
+ end
38
+ else
39
+ s.add_dependency(%q<echoe>, ["~> 0", "= 3.0"])
40
+ s.add_dependency(%q<rspec>, ["~> 0", "= 1.1.0"])
41
+ s.add_dependency(%q<mocha>, ["~> 0", "= 0.9"])
42
+ end
43
+ end
@@ -0,0 +1,199 @@
1
+
2
+ require File.dirname( __FILE__ ) + '/../spec_helper'
3
+ require 'sandbox/cli'
4
+
5
+ describe Sandbox::CLI do
6
+
7
+ it "should raise an error when running from a loaded sandbox" do
8
+ begin
9
+ ENV[ 'SANDBOX' ] = 'something'
10
+ lambda { Sandbox::CLI.verify_environment! }.should raise_error( Sandbox::LoadedSandboxError )
11
+ ensure
12
+ ENV[ 'SANDBOX' ] = nil
13
+ end
14
+ end
15
+
16
+ describe "calling execute" do
17
+ before( :each ) do
18
+ @instance = stub_everything()
19
+ end
20
+
21
+ it "should handle all errors" do
22
+ Sandbox::CLI.stubs( :new ).raises( StandardError )
23
+ Sandbox::CLI.expects( :handle_error ).with( instance_of( StandardError ) )
24
+ Sandbox::CLI.execute
25
+ end
26
+
27
+ it "should attempt to parse ARGV by default" do
28
+ Sandbox::CLI.expects( :parse ).with( ARGV ).returns( @instance )
29
+ Sandbox::CLI.execute
30
+ end
31
+
32
+ it "should create a new instance" do
33
+ Sandbox::CLI.expects( :new ).returns( @instance )
34
+ Sandbox::CLI.execute
35
+ end
36
+
37
+ it "should call parse_args! on the new instance" do
38
+ @instance.expects( :parse_args! )
39
+ Sandbox::CLI.expects( :new ).returns( @instance )
40
+ Sandbox::CLI.execute
41
+ end
42
+
43
+ it "should run the instance" do
44
+ @instance.expects( :execute! )
45
+ Sandbox::CLI.expects( :parse ).returns( @instance )
46
+ Sandbox::CLI.execute
47
+ end
48
+ end
49
+
50
+ describe "a new instance" do
51
+
52
+ before( :each ) do
53
+ @cli = Sandbox::CLI.new
54
+ end
55
+
56
+ it "should have default 'gems to install'" do
57
+ @cli.options[ :gems ] = [ 'rake' ]
58
+ end
59
+
60
+ describe "instance calling parse_args!" do
61
+ def processor( *args ); lambda { @cli.parse_args!( args ) }; end
62
+ def process( *args ); processor( *args ).call; end
63
+
64
+ describe "using NO arguments" do
65
+ it "should use raise nothing" do
66
+ process()
67
+ @cli.options[ :original_args ].should == []
68
+ @cli.options[ :args ].should == []
69
+ end
70
+ end
71
+
72
+ describe "using VALID arguments" do
73
+ [ '-V', '--version' ].each do |arg|
74
+ it "should print the version for switch '#{arg}'" do
75
+ @cli.expects( :puts ).with( Sandbox::Version::STRING )
76
+ processor( arg ).should raise_error( SystemExit ) { |error| error.status.should == 0 }
77
+ end
78
+ end
79
+
80
+ [ '-V', '--version' ].each do |arg|
81
+ it "should ignore additional arguments after '#{arg}'" do
82
+ # @cli.stubs(:puts)
83
+ @cli.expects( :puts ).with( Sandbox::Version::STRING ).times(2)
84
+ processor( arg, '-x' ).should raise_error( SystemExit ) { |error| error.status.should == 0 }
85
+ processor( arg, 'unknown' ).should raise_error( SystemExit ) { |error| error.status.should == 0 }
86
+ end
87
+ end
88
+
89
+ [ '-h', '--help' ].each do |arg|
90
+ it "should show help for '#{arg}'" do
91
+ @cli.expects( :puts ).with( instance_of( OptionParser ) )
92
+ processor( arg ).should raise_error( SystemExit ) { |error| error.status.should == 0 }
93
+ end
94
+ end
95
+
96
+ [ '-h', '--help' ].each do |arg|
97
+ it "should ignore additional arguments after '#{arg}'" do
98
+ @cli.expects( :puts ).with( instance_of( OptionParser ) ).times(2)
99
+ processor( arg, '-x' ).should raise_error( SystemExit ) { |error| error.status.should == 0 }
100
+ processor( arg, 'unknown' ).should raise_error( SystemExit ) { |error| error.status.should == 0 }
101
+ end
102
+ end
103
+
104
+ [ '-H', '--long-help' ].each do |arg|
105
+ it "should show long help for '#{arg}'" do
106
+ @cli.expects( :puts )
107
+ @cli.expects( :long_help )
108
+ processor( arg ).should raise_error( SystemExit ) { |error| error.status.should == 0 }
109
+ end
110
+ end
111
+
112
+ [ '-v', '--verbose' ].each do |arg|
113
+ it "should increase verbosity with '#{arg}'" do
114
+ Sandbox.expects( :increase_verbosity )
115
+ process( arg )
116
+ @cli.options[ :original_args ].should == [ arg ]
117
+ @cli.options[ :args ].should == []
118
+ end
119
+ end
120
+
121
+ [ [ '-v', '-v' ], [ '--verbose', '--verbose' ] ].each do |args|
122
+ it "should increase verbosity twice with '#{args.join(' ')}'" do
123
+ Sandbox.expects( :increase_verbosity ).times(2)
124
+ process( *args )
125
+ @cli.options[ :original_args ].should == args
126
+ @cli.options[ :args ].should == []
127
+ end
128
+ end
129
+
130
+ it "should require additional arguments with switch '-g'" do
131
+ processor( '-g' ).should raise_error( Sandbox::ParseError )
132
+ end
133
+
134
+ it "should set 'gems to install' with switch '-g'" do
135
+ args = [ '-g', 'somegem,anothergem' ]
136
+ process( *args )
137
+ @cli.options[ :original_args ].should == args
138
+ @cli.options[ :args ].should == []
139
+ @cli.options[ :gems ].should == [ 'somegem', 'anothergem' ]
140
+ end
141
+
142
+ it "should clear 'gems to install' with switch '-n'" do
143
+ process( '-n' )
144
+ @cli.options[ :original_args ].should == [ '-n' ]
145
+ @cli.options[ :args ].should == []
146
+ @cli.options[ :gems ].should == []
147
+ end
148
+
149
+ it "should store leftover arguments in options for arguments '/path/to/somewhere'" do
150
+ args = [ '/path/to/somewhere' ]
151
+ process( *args )
152
+ @cli.options[ :original_args ].should == args
153
+ @cli.options[ :args ].should == args
154
+ end
155
+
156
+ it "should store leftover arguments in options for arguments '-v /path/to/somewhere'" do
157
+ args = [ '-v', '/path/to/somewhere' ]
158
+ process( *args )
159
+ @cli.options[ :original_args ].should == args
160
+ @cli.options[ :args ].should == [ args.last ]
161
+ end
162
+ end
163
+
164
+ describe "using INVALID arguments" do
165
+ it "should exit with message for invalid switch '-x'" do
166
+ processor( '-x' ).
167
+ should raise_error( Sandbox::ParseError ) { |error| error.message.should =~ /-x\b/ }
168
+ end
169
+ end
170
+ end
171
+
172
+ describe "instance calling execute!" do
173
+ def processor; lambda { @cli.execute! }; end
174
+ def process; processor.call; end
175
+
176
+ it "should raise error with no target specified" do
177
+ @cli.options[ :args ] = []
178
+ processor.should raise_error
179
+ end
180
+
181
+ it "should raise error with more than one target" do
182
+ @cli.options[ :args ] = [ 'one', 'two' ]
183
+ processor.should raise_error
184
+ end
185
+
186
+ it "should instantiate an Installer and call populate with one target" do
187
+ @cli.options.delete( :gems )
188
+ @cli.options[ :args ] = [ 'one' ]
189
+ installer = mock( 'Installer', :populate )
190
+ Sandbox::Installer.expects( :new ).with( { :target => 'one' } ).returns( installer )
191
+ process
192
+ end
193
+
194
+ end
195
+
196
+ end
197
+
198
+ end
199
+