ruby-virtualenv 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ require File.dirname(__FILE__) + "/../../lib/sandbox"
2
+
3
+ begin
4
+ require 'cucumber'
5
+ require 'spec'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'cucumber'
9
+ require 'spec'
10
+ end
@@ -0,0 +1,41 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless \
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ module Sandbox
5
+ class << self
6
+
7
+ def verbosity
8
+ @verbosity ||= 0
9
+ end
10
+
11
+ def increase_verbosity
12
+ @verbosity = verbosity + 1
13
+ end
14
+
15
+ def decrease_verbosity
16
+ @verbosity = verbosity - 1
17
+ end
18
+
19
+ def quiet?
20
+ verbosity < 0
21
+ end
22
+
23
+ def really_quiet?
24
+ verbosity < -1
25
+ end
26
+
27
+ def verbose?
28
+ verbosity > 0
29
+ end
30
+
31
+ def really_verbose?
32
+ verbosity > 1
33
+ end
34
+
35
+ end
36
+ end
37
+
38
+ require 'sandbox/version'
39
+ require 'sandbox/errors'
40
+ require 'sandbox/output'
41
+ require 'sandbox/installer'
@@ -0,0 +1,173 @@
1
+ require 'optparse'
2
+ require 'sandbox'
3
+
4
+ module Sandbox
5
+ class CLI
6
+ include Sandbox::Output
7
+ extend Sandbox::Output
8
+
9
+ DEFAULTS = {
10
+ :gems => []
11
+ }
12
+
13
+ ## CLASS METHODS
14
+ class << self
15
+
16
+ # invokes sandbox via command-line ARGV as the options
17
+ def execute(args = ARGV)
18
+ verify_environment!
19
+ parse(args).execute!
20
+ rescue Exception => error
21
+ handle_error(error)
22
+ end
23
+
24
+ # returns a new CLI instance which has parsed the given arguments.
25
+ # will load the command to execute based upon the arguements.
26
+ # if an error occurs, it will print out simple error message and exit.
27
+ def parse(args)
28
+ cli = new
29
+ cli.parse_args!(args)
30
+ cli
31
+ end
32
+
33
+ def verify_environment!
34
+ raise LoadedSandboxError if ENV['SANDBOX']
35
+ end
36
+
37
+ # pretty error handling
38
+ def handle_error(error)
39
+ case error
40
+ when Sandbox::Error
41
+ tell_unless_really_quiet(error.message)
42
+ when StandardError #, Timeout::Error
43
+ tell_unless_really_quiet("Error: #{error.message}")
44
+ tell_when_really_verbose(error.backtrace.collect { |bt| " #{bt}" }.join( "\n" )) if error.backtrace
45
+ when Interrupt
46
+ tell_unless_really_quiet("Interrupted")
47
+ else
48
+ raise error
49
+ end
50
+ end
51
+
52
+ end
53
+ ## END CLASS METHODS
54
+
55
+ ## PUBLIC INSTANCE METHODS
56
+ public
57
+
58
+ # The options for this execution.
59
+ attr_reader :options
60
+
61
+ # setup of a new CLI instance
62
+ def initialize
63
+ @options = DEFAULTS.dup
64
+ @parser = nil
65
+ end
66
+
67
+ # perform the sandbox creation
68
+ def execute!
69
+ targets = options.delete(:args)
70
+
71
+ if targets.size < 1
72
+ raise Sandbox::Error.new('no target specified - see `ruby-virtualenv --help` for assistance')
73
+ elsif targets.size > 1
74
+ raise Sandbox::Error.new('multiple targets specified - see `ruby-virtualenv --help` for assistance')
75
+ end
76
+
77
+ options[ :target ] = targets[0]
78
+
79
+ Sandbox::Installer.new(options).populate
80
+ end
81
+
82
+ # processes +args+ to:
83
+ #
84
+ # * load global option for the application
85
+ # * determine command name to lookup in CommandManager
86
+ # * load command and have it process any add't options
87
+ # * catches exceptions for unknown switches or commands
88
+ def parse_args!( args )
89
+ options[:original_args] = args.dup
90
+ parser.parse!(args)
91
+ rescue OptionParser::ParseError => ex
92
+ raise_parse_error(ex.reason, ex.args)
93
+ else
94
+ options[:args] = args
95
+ end
96
+
97
+ def parser
98
+ @parser ||= create_parser
99
+ end
100
+
101
+ def create_parser
102
+ OptionParser.new do |o|
103
+ o.set_summary_indent(' ')
104
+ o.program_name = 'ruby-virtualenv TARGET'
105
+ o.define_head "Create virtual ruby/rubygems environments."
106
+ o.separator ""
107
+
108
+ o.separator "ARGUMENTS:"
109
+ o.separator " TARGET Target path to new virtualenv. Must not exist beforehand."
110
+ o.separator ""
111
+
112
+ o.separator "OPTIONS"
113
+ o.on('-g', '--gems gem1,gem2', Array, 'Gems to install after virtualenv is created.') { |gems| @options[:gems] = gems }
114
+ o.on('-n', '--no-gems', 'Do not install any gems after virtualenv is created.') { @options[:gems] = [] }
115
+ o.on('-q', '--quiet', 'Show less output. (multiple allowed)') { |f| Sandbox.decrease_verbosity }
116
+ o.on('-v', '--verbose', 'Show more output. (multiple allowed)') { |f| Sandbox.increase_verbosity }
117
+ o.on_tail('-h', '--help', 'Show this help message and exit.') { tell_unless_really_quiet( o ); exit }
118
+ o.on_tail('-H', '--long-help', 'Show the full description about the program.') { tell_unless_really_quiet( long_help ); exit }
119
+ o.on_tail('-V', '--version', 'Display the program version and exit.' ) { tell_unless_really_quiet( Sandbox::VERSION ); exit }
120
+ o.separator ""
121
+ end
122
+ end
123
+
124
+ def long_help
125
+ <<-HELP
126
+ Sandbox is a utility to create sandboxed Ruby/Rubygems environments.
127
+
128
+ It is meant to address the following issues:
129
+
130
+ 1. Conflicts with unspecified gem dependency versions.
131
+ 2. Applications can have their own gem repositories.
132
+ 3. Permissions for installing your own gems.
133
+ 4. Ability to try gems out without installing into your global repository.
134
+ 5. A Simple way to enable this.
135
+
136
+ Running from your own gem repositories is fairly straight-forward, but
137
+ managing the necessary environment is a pain. This utility will create a new
138
+ environment which may be activated by the script `bin/activate` in
139
+ your sandbox directory.
140
+
141
+ Run the script with the following to enable your new environment:
142
+
143
+ $ source bin/activate
144
+
145
+ When you want to leave the environment:
146
+
147
+ $ deactivate
148
+
149
+ NOTES:
150
+
151
+ 1. It creates an environment that has its own installation directory for Gems.
152
+ 2. It doesn't share gems with other sandbox environments.
153
+ 3. It (optionally) doesn't use the globally installed gems either.
154
+ 4. It will use a local to the sandbox .gemrc file
155
+
156
+ WARNINGS:
157
+
158
+ Activating your sandbox environment will change your HOME directory
159
+ temporarily to the sandbox directory. Other environment variables are set to
160
+ enable this funtionality, so if you may experience odd behavior. Everything
161
+ should be reset when you deactivate the virtualenv.
162
+
163
+ HELP
164
+ end
165
+
166
+ private
167
+
168
+ def raise_parse_error(reason, args=[])
169
+ raise Sandbox::ParseError.new(reason, args)
170
+ end
171
+
172
+ end
173
+ end
@@ -0,0 +1,38 @@
1
+ module Sandbox
2
+ class Error < StandardError
3
+
4
+ def initialize(msg=nil)
5
+ super(msg)
6
+ end
7
+
8
+ def message
9
+ out = ["Sandbox error: #{super}"]
10
+ out.concat(backtrace.collect { |bt| " #{bt}" }) if Sandbox.really_verbose?
11
+ out.join("\n")
12
+ end
13
+
14
+ end
15
+
16
+ class LoadedSandboxError < Sandbox::Error
17
+ def initialize(msg="You cannot run sandbox from a loaded sandbox environment")
18
+ super(msg)
19
+ end
20
+ end
21
+
22
+ class ParseError < Sandbox::Error
23
+
24
+ def initialize(reason=nil, args=[])
25
+ msg = if args.is_a?(Array) && args.size > 0
26
+ "#{reason} => #{args.join( ' ' )}"
27
+ elsif args.is_a?(String) && args.length > 0
28
+ "#{reason} => #{args}"
29
+ else
30
+ reason
31
+ end
32
+
33
+ super(msg)
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,175 @@
1
+ require 'fileutils'
2
+ require 'erb'
3
+
4
+ module Sandbox
5
+ class Installer
6
+ include Sandbox::Output
7
+ extend Sandbox::Output
8
+
9
+ class << self
10
+ end
11
+
12
+ attr_accessor :options
13
+
14
+ def initialize(options={})
15
+ @options = options.dup
16
+ @target = nil
17
+ end
18
+
19
+ def target
20
+ return @target unless @target.nil?
21
+ @target = resolve_target(options[:target])
22
+ end
23
+
24
+ def populate
25
+ tell("creating sandbox at: #{target}")
26
+ create_directories
27
+ tell("installing activation script")
28
+ install_scripts
29
+ tell("installing .gemrc")
30
+ install_gemrc
31
+ tell("installing gems")
32
+ install_gems
33
+ end
34
+
35
+ ##
36
+ # Create folders:
37
+ #
38
+ # mkdir -p /path/to/sandbox/rubygems/bin
39
+ #
40
+ # Symlink the bin directory, because when gems are installed, binaries
41
+ # are installed in GEM_HOME/bin:
42
+ #
43
+ # $ ln -s /path/to/sandbox/rubygems/bin /path/to/sandbox/bin
44
+ #
45
+ def create_directories
46
+ gembin = File.join(target, 'rubygems', 'bin')
47
+ FileUtils.mkdir_p(gembin)
48
+
49
+ bin = File.join(target, 'bin')
50
+ FileUtils.ln_s( gembin, bin )
51
+ end
52
+
53
+ def install_gemrc
54
+ filename = File.join(target, '.gemrc')
55
+ template = File.read(File.dirname( __FILE__ ) + '/templates/gemrc.erb')
56
+ script = ERB.new(template)
57
+ output = script.result(binding)
58
+
59
+ File.open(filename, 'w') do |f|
60
+ f.write output
61
+ end
62
+ end
63
+
64
+ def install_scripts
65
+ filename = File.join(target, 'bin', 'activate')
66
+ template = File.read(File.dirname( __FILE__ ) + '/templates/activate.erb')
67
+ script = ERB.new(template)
68
+ output = script.result(binding)
69
+
70
+ File.open(filename, 'w') do |f|
71
+ f.write output
72
+ end
73
+ end
74
+
75
+ def install_gems
76
+ # gem = `which gem`.chomp
77
+ # return if gem.empty?
78
+ gems = options[ :gems ] || []
79
+ if gems.size == 0
80
+ tell( " nothing to install" )
81
+ return
82
+ end
83
+
84
+ begin
85
+ setup_sandbox_env
86
+ gems.each do |gem|
87
+ tell_unless_really_quiet( " gem: #{gem}" )
88
+ cmd = "gem install #{gem}"
89
+ # cmd = cmd + ' -V' if Sandbox.really_verbose?
90
+ status, output = shell_out( cmd )
91
+ unless status
92
+ tell_unless_really_quiet( " failed to install gem: #{gem}" )
93
+ end
94
+ end
95
+ ensure
96
+ restore_sandbox_env
97
+ end
98
+ end
99
+
100
+ def shell_out( cmd )
101
+ # err_capture = Sandbox.really_verbose? '2>&1' : '2>/dev/null'
102
+ # out = `#{cmd} #{err_capture}`
103
+ out = `#{cmd} 2>/dev/null`
104
+ result = $?.exitstatus == 0
105
+ [ result, out ]
106
+ end
107
+
108
+ def setup_sandbox_env
109
+ @old_env = Hash[ *ENV.select { |k,v| ['HOME','GEM_HOME','GEM_PATH'].include?( k ) }.flatten ]
110
+ # @old_env = {}
111
+ # @old_env[ 'HOME' ] = ENV[ 'HOME' ]
112
+ # @old_env[ 'GEM_HOME' ] = ENV[ 'GEM_HOME' ]
113
+ # @old_env[ 'GEM_PATH' ] = ENV[ 'GEM_PATH' ]
114
+
115
+ ENV[ 'HOME' ] = target
116
+ ENV[ 'GEM_HOME' ] = "#{target}/rubygems"
117
+ ENV[ 'GEM_PATH' ] = "#{target}/rubygems"
118
+ end
119
+
120
+ def restore_sandbox_env
121
+ # ENV.update( @old_env )
122
+ ENV[ 'HOME' ] = @old_env[ 'HOME' ]
123
+ ENV[ 'GEM_HOME' ] = @old_env[ 'GEM_HOME' ]
124
+ ENV[ 'GEM_PATH' ] = @old_env[ 'GEM_PATH' ]
125
+ end
126
+
127
+ def resolve_target( path )
128
+ # should consider replacing with 'pathname' => Pathname.new( path )
129
+ path = fix_path( path )
130
+ if File.exists?( path )
131
+ raise Sandbox::Error, "target '#{path}' exists"
132
+ end
133
+
134
+ base = path
135
+ while base = File.dirname( base )
136
+ if check_path!( base )
137
+ break
138
+ elsif base == '/'
139
+ raise "something is seriously wrong; we should never get here"
140
+ end
141
+ end
142
+ return path
143
+ end
144
+
145
+ def check_path!( path )
146
+ if File.directory?( path )
147
+ if File.writable?( path )
148
+ return true
149
+ else
150
+ raise Sandbox::Error, "path '#{path}' has a permission problem"
151
+ end
152
+ elsif File.exists?( path )
153
+ raise Sandbox::Error, "path '#{path}' is not a directory"
154
+ end
155
+ false
156
+ end
157
+
158
+ def fix_path( path )
159
+ unless path.index( '/' ) == 0
160
+ path = File.join( FileUtils.pwd, path )
161
+ end
162
+ path
163
+ end
164
+
165
+ ## END PUBLIC INSTANCE METHODS
166
+
167
+
168
+ ## PRIVATE INSTANCE METHODS
169
+ private
170
+
171
+ ## END PRIVATE INSTANCE METHODS
172
+
173
+ end
174
+
175
+ end
@@ -0,0 +1,25 @@
1
+ module Sandbox
2
+ module Output
3
+
4
+ def tell(msg)
5
+ tell_unless_quiet(msg)
6
+ end
7
+
8
+ def tell_when_verbose(msg)
9
+ puts msg if Sandbox.verbose?
10
+ end
11
+
12
+ def tell_when_really_verbose(msg)
13
+ puts msg if Sandbox.really_verbose?
14
+ end
15
+
16
+ def tell_unless_quiet(msg)
17
+ puts msg unless Sandbox.quiet?
18
+ end
19
+
20
+ def tell_unless_really_quiet(msg)
21
+ puts msg unless Sandbox.really_quiet?
22
+ end
23
+
24
+ end
25
+ end