ruby-virtualenv 0.5.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,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