rvm 0.1.41 → 0.1.42

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/binscripts/rvm +1 -1
  2. data/binscripts/rvm-shell +32 -0
  3. data/binscripts/rvmsudo +1 -6
  4. data/config/db +2 -2
  5. data/config/known +2 -2
  6. data/config/md5 +6 -5
  7. data/contrib/install-system-wide +81 -0
  8. data/install +23 -24
  9. data/lib/VERSION.yml +1 -1
  10. data/lib/rvm.rb +156 -1
  11. data/lib/rvm/capistrano.rb +45 -0
  12. data/lib/rvm/environment.rb +62 -0
  13. data/lib/rvm/environment/alias.rb +69 -0
  14. data/lib/rvm/environment/cleanup.rb +54 -0
  15. data/lib/rvm/environment/configuration.rb +60 -0
  16. data/lib/rvm/environment/env.rb +52 -0
  17. data/lib/rvm/environment/gemset.rb +222 -0
  18. data/lib/rvm/environment/info.rb +13 -0
  19. data/lib/rvm/environment/list.rb +124 -0
  20. data/lib/rvm/environment/rubies.rb +50 -0
  21. data/lib/rvm/environment/sets.rb +123 -0
  22. data/lib/rvm/environment/tools.rb +41 -0
  23. data/lib/rvm/environment/utility.rb +167 -0
  24. data/lib/rvm/environment/wrapper.rb +23 -0
  25. data/lib/rvm/errors.rb +28 -0
  26. data/lib/rvm/shell.rb +21 -10
  27. data/lib/rvm/shell/abstract_wrapper.rb +145 -0
  28. data/lib/rvm/shell/result.rb +42 -0
  29. data/lib/rvm/shell/shell_wrapper.sh +10 -0
  30. data/lib/rvm/shell/single_shot_wrapper.rb +56 -0
  31. data/lib/rvm/shell/utility.rb +37 -0
  32. data/lib/rvm/version.rb +12 -8
  33. data/rvm.gemspec +27 -4
  34. data/scripts/cd +17 -32
  35. data/scripts/cli +46 -16
  36. data/scripts/completion +1 -1
  37. data/scripts/disk-usage +52 -0
  38. data/scripts/fetch +8 -2
  39. data/scripts/gemsets +15 -4
  40. data/scripts/initialize +3 -3
  41. data/scripts/install +23 -24
  42. data/scripts/list +16 -8
  43. data/scripts/log +4 -1
  44. data/scripts/man +0 -0
  45. data/scripts/manage +51 -34
  46. data/scripts/md5 +4 -5
  47. data/scripts/package +28 -6
  48. data/scripts/rubygems +2 -2
  49. data/scripts/rvm +2 -2
  50. data/scripts/rvm-install +23 -24
  51. data/scripts/selector +2 -2
  52. data/scripts/tools +34 -0
  53. data/scripts/update +23 -24
  54. data/scripts/utility +54 -12
  55. data/scripts/wrapper +21 -18
  56. metadata +29 -6
  57. data/lib/rvm/open4.rb +0 -395
  58. data/lib/rvm/rvm.rb +0 -14
@@ -0,0 +1,23 @@
1
+ module RVM
2
+ class Environment
3
+
4
+ # Generates wrappers with the specified prefix, pointing
5
+ # to ruby_string.
6
+ def wrapper(ruby_string, wrapper_prefix, *binaries)
7
+ rvm(:wrapper, ruby_string, wrapper_prefix, *binaries).successful?
8
+ end
9
+
10
+ # Generates the default wrappers.
11
+ def default_wrappers(ruby_string, *binaries)
12
+ wrapper ruby_string, '', *binaries
13
+ end
14
+
15
+ # If available, return the path to the wrapper for
16
+ # the given executable. Will return ni if the wrapper
17
+ # is unavailable.
18
+ def wrapper_path_for(executable)
19
+ raise NotImplementedError
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ module RVM
2
+
3
+ # Generic error in RVM
4
+ class Error < StandardError; end
5
+
6
+ # Generic error with the shell command output attached.
7
+ # The RVM::Shell::Result instance is available via +#result+.
8
+ class ErrorWithResult < Error
9
+ attr_reader :result
10
+
11
+ def initialize(result, message = nil)
12
+ @result = result
13
+ super message
14
+ end
15
+
16
+ end
17
+
18
+ # Something occured processing the command and rvm couldn't parse the results.
19
+ class IncompleteCommandError < Error; end
20
+
21
+ # The given action can't replace the env for the current process.
22
+ # Typically raised by RVM::Environment#gemset_use when the gemset
23
+ # is for another, incompatible ruby interpreter.
24
+ #
25
+ # Provides access to the output of the shell command via +#result+.
26
+ class IncompatibleRubyError < ErrorWithResult; end
27
+
28
+ end
@@ -1,14 +1,25 @@
1
1
  module RVM
2
- class Shell
3
- attr_reader :errors, :output
4
-
5
- def initialize(command)
6
- @command = (command =~ /^rvm /) ? command : "rvm #{command}"
7
- Open4::popen4("/bin/bash -l -c '#{@command.tr("'","\\'")}'") do |pid, stdin, stdout, stderr|
8
- stdin.close
9
- @output = stdout.readlines.join
10
- @errors = stderr.readlines.join
11
- end
2
+ # Provides Generic access to a more ruby-like shell interface.
3
+ # For more details, see AbstractWrapper.
4
+ module Shell
5
+
6
+ autoload :AbstractWrapper, 'rvm/shell/abstract_wrapper'
7
+ autoload :SingleShotWrapper, 'rvm/shell/single_shot_wrapper'
8
+ # Current unimplemented
9
+ #autoload :PersistingWrapper, 'rvm/shell/persisting_wrapper'
10
+ autoload :TestWrapper, 'rvm/shell/test_wrapper'
11
+ autoload :Utility, 'rvm/shell/utility'
12
+ autoload :Result, 'rvm/shell/result'
13
+
14
+ # Returns the default shell wrapper class to use
15
+ def self.default_wrapper
16
+ @@default_wrapper ||= SingleShotWrapper
12
17
  end
18
+
19
+ # Sets the default shell wrapper class to use.
20
+ def self.default_wrapper=(wrapper)
21
+ @@default_wrapper = wrapper
22
+ end
23
+
13
24
  end
14
25
  end
@@ -0,0 +1,145 @@
1
+ require 'yaml'
2
+
3
+ module RVM
4
+ module Shell
5
+ # Provides the most common functionality expected of a shell wrapper.
6
+ # Namely, implements general utility methods and tools to extract output
7
+ # from a given command but doesn't actually run any commands itself,
8
+ # leaving that up to concrete implementations.
9
+ #
10
+ # == Usage
11
+ #
12
+ # Commands are run inside of a shell (usually bash) and can either be exectuted in
13
+ # two situations (each with wrapper methods available) - silently or verbosely.
14
+ #
15
+ # Silent commands (via run_silently and run_command) do exactly as
16
+ # they say - that can modify the environment etc but anything they print (to stdout
17
+ # or stderr) will be discarded.
18
+ #
19
+ # Verbose commands will run the command and then print the command epilog (which
20
+ # contains the output stastus and the current env in yaml format). This allows us
21
+ # to not only capture all output but to also return the exit status and environment
22
+ # variables in a way that makes persisted shell sessions possible.
23
+ #
24
+ # Under the hood, #run and run_silently are the preferred ways of invoking commands - if
25
+ # passed a single command, they'll run it as is (much like system in ruby) but when
26
+ # given multiple arguments anything after the first will be escaped (e.g. you can
27
+ # hence pass code etc). #run will also parse the results of this epilog into a usable
28
+ # RVM::Shell::Result object.
29
+ #
30
+ # run_command and run_command_silently do the actual hard work for these behind the scenes,
31
+ # running a string as the shell command. Hence, these two commands are what must be
32
+ # implemented in non-abstract wrappers.
33
+ #
34
+ # For an example of the shell wrapper functionality in action, see RVM::Environment
35
+ # which delegates most of the work to a shell wrapper.
36
+ class AbstractWrapper
37
+
38
+ # Used the mark the end of a commands output and the start of the rvm env.
39
+ COMMAND_EPILOG_START = "---------------RVM-RESULTS-START---------------"
40
+ # Used to mark the end of the commands epilog.
41
+ COMMAND_EPILOG_END = "----------------RVM-RESULTS-END----------------"
42
+ # The location of the shell file with the epilog function definition.
43
+ WRAPPER_LOCATION = File.expand_path('./shell_wrapper.sh', File.dirname(__FILE__))
44
+
45
+ # Defines the shell exectuable.
46
+ attr_reader :shell_executable
47
+
48
+ # Initializes a new shell wrapper, including setting the
49
+ # default setup block. Implementations must override this method
50
+ # but must ensure that they call super to perform the expected
51
+ # standard setup.
52
+ def initialize(sh = 'bash', &setup_block)
53
+ setup &setup_block
54
+ @shell_executable = sh
55
+ end
56
+
57
+ # Defines a setup block to be run when initiating a wrapper session.
58
+ # Usually used for doing things such as sourcing the rvm file. Please note
59
+ # that the wrapper file is automatically source.
60
+ #
61
+ # The setup block should be automatically run by wrapper implementations.
62
+ def setup(&blk)
63
+ @setup_block = blk
64
+ end
65
+
66
+ # Runs the gives command (with optional arguments), returning an
67
+ # RVM::Shell::Result object, including stdout / stderr streams.
68
+ # Under the hood, uses run_command to actually process it all.
69
+ def run(command, *arguments)
70
+ expanded_command = build_cli_call(command, arguments)
71
+ status, out, err = run_command(expanded_command)
72
+ Result.new(expanded_command, status, out, err)
73
+ end
74
+
75
+ # Wrapper around run_command_silently that correctly escapes arguments.
76
+ # Essentially, #run but using run_command_silently.
77
+ def run_silently(command, *arguments)
78
+ run_command_silently build_cli_call(command, arguments)
79
+ end
80
+
81
+ # Given a command, it will execute it in the current wrapper
82
+ # and once done, will return:
83
+ # - the hash from the epilog output.
84
+ # - a string representing stdout.
85
+ # - a string representing stderr.
86
+ def run_command(full_command)
87
+ raise NotImplementedError.new("run_command is only available in concrete implementations")
88
+ end
89
+
90
+ # Like run_command, but doesn't care about output.
91
+ def run_command_silently(full_command)
92
+ raise NotImplementedError.new("run_command_silently is only available in concrete implementations")
93
+ end
94
+
95
+ # Returns a given environment variables' value.
96
+ def [](var_name)
97
+ run(:true)[var_name]
98
+ end
99
+
100
+ protected
101
+
102
+ # When called, will use the current environment to source the wrapper scripts
103
+ # as well as invoking the current setup block. as defined on initialization / via #setup.
104
+ def invoke_setup!
105
+ source_command_wrapper
106
+ @setup_block.call(self) if @setup_block
107
+ end
108
+
109
+ # Uses run_silently to source the wrapper file.
110
+ def source_command_wrapper
111
+ run_silently :source, WRAPPER_LOCATION
112
+ end
113
+
114
+ # Returns a command followed by the call to show the epilog.
115
+ def wrapped_command(command)
116
+ "#{command}; __rvm_show_command_epilog"
117
+ end
118
+
119
+ # Wraps a command in a way that it prints no output.
120
+ def silent_command(command)
121
+ "{ #{command}; } >/dev/null 2>&1"
122
+ end
123
+
124
+ # Checks whether the given command includes a epilog, marked by
125
+ # epilog start and end lines.
126
+ def command_complete?(c)
127
+ start_index, end_index = c.index(COMMAND_EPILOG_START), c.index(COMMAND_EPILOG_END)
128
+ start_index && end_index && start_index < end_index
129
+ end
130
+
131
+ # Takes a raw string from a processes STDIO and returns three things:
132
+ # 1. The actual stdout, minus epilogue.
133
+ # 2. YAML output of the process results.
134
+ # 3. Any left over from the STDIO text.
135
+ def raw_stdout_to_parts(c)
136
+ raise IncompleteCommandError if !command_complete?(c)
137
+ before, after = c.split(COMMAND_EPILOG_START, 2)
138
+ epilog, after = after.split(COMMAND_EPILOG_END, 2)
139
+ return before, YAML.load(epilog.strip), after
140
+ end
141
+
142
+ include RVM::Shell::Utility
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,42 @@
1
+ module RVM
2
+ module Shell
3
+ # Represents the output of a shell command.
4
+ # This includes the exit status (and the helpful #successful? method)
5
+ # as well accessors for the command and stdout / stderr.
6
+ class Result
7
+
8
+ attr_reader :command, :stdout, :stderr, :raw_status
9
+
10
+ # Creates a new result object with the given details.
11
+ def initialize(command, status, stdout, stderr)
12
+ @command = command.dup.freeze
13
+ @raw_status = status
14
+ @environment = @raw_status["environment"] || {}
15
+ @successful = (exit_status == 0)
16
+ @stdout = stdout.freeze
17
+ @stderr = stderr.freeze
18
+ end
19
+
20
+ # Returns the hash of the environment.
21
+ def env
22
+ @environment
23
+ end
24
+
25
+ # Whether or not the command had a successful exit status.
26
+ def successful?
27
+ @successful
28
+ end
29
+
30
+ # Returns a value from the outputs environment.
31
+ def [](key)
32
+ env[key.to_s]
33
+ end
34
+
35
+ # Returns the exit status for the program
36
+ def exit_status
37
+ @exit_status ||= (Integer(@raw_status["exit_status"]) rescue 1)
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,10 @@
1
+ # Prints an epilog to a shell command.
2
+ __rvm_show_command_epilog() {
3
+ local last_command_result="$?"
4
+ echo "---------------RVM-RESULTS-START---------------"
5
+ echo "---"
6
+ echo " exit_status: \"$last_command_result\""
7
+ echo " environment:"
8
+ env | sed "s#'#\\'#" | sed -e 's#"#\\"#' -e "s#\\([^=]*\\)=\\(.*\\)# '\1': \"\2\"#"
9
+ echo "----------------RVM-RESULTS-END----------------"
10
+ }
@@ -0,0 +1,56 @@
1
+ require 'open3'
2
+
3
+ module RVM
4
+ module Shell
5
+ # Implementation of the abstract wrapper class that opens a new
6
+ # instance of bash when a command is run, only keeping it around
7
+ # for the lifetime of the command. Possibly inefficient but for
8
+ # the moment simplest and hence default implementation.
9
+ class SingleShotWrapper < AbstractWrapper
10
+
11
+ attr_accessor :current
12
+
13
+ # Runs a given command in the current shell.
14
+ # Defaults the command to true if empty.
15
+ def run_command(command)
16
+ command = "true" if command.to_s.strip.empty?
17
+ with_shell_instance do
18
+ stdin.puts wrapped_command(command)
19
+ stdin.close
20
+ out, err = stdout.read, stderr.read
21
+ out, status, _ = raw_stdout_to_parts(out)
22
+ return status, out, err
23
+ end
24
+ end
25
+
26
+ # Runs a command, ensuring no output is collected.
27
+ def run_command_silently(command)
28
+ with_shell_instance do
29
+ stdin.puts silent_command(command)
30
+ end
31
+ end
32
+
33
+ protected
34
+
35
+ # yields stdio, stderr and stdin for a shell instance.
36
+ # If there isn't a current shell instance, it will create a new one.
37
+ # In said scenario, it will also cleanup once it is done.
38
+ def with_shell_instance(&blk)
39
+ no_current = @current.nil?
40
+ if no_current
41
+ @current = Open3.popen3(self.shell_executable)
42
+ invoke_setup!
43
+ end
44
+ yield
45
+ ensure
46
+ @current = nil if no_current
47
+ end
48
+
49
+ # Direct access to each of the named descriptors
50
+ def stdin; @current[0]; end
51
+ def stdout; @current[1]; end
52
+ def stderr; @current[2]; end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,37 @@
1
+ module RVM
2
+ module Shell
3
+ module Utility
4
+
5
+ public
6
+
7
+ # Takes an array / number of arguments and converts
8
+ # them to a string useable for passing into a shell call.
9
+ def escape_arguments(*args)
10
+ return '' if args.nil?
11
+ args.flatten.map { |a| escape_argument(a.to_s) }.join(" ")
12
+ end
13
+
14
+ # Given a string, converts to the escaped format. This ensures
15
+ # that things such as variables aren't evaluated into strings
16
+ # and everything else is setup as expected.
17
+ def escape_argument(s)
18
+ return "''" if s.empty?
19
+ s.scan(/('+|[^']+)/).map do |section|
20
+ section = section.first
21
+ if section[0] == ?'
22
+ "\\'" * section.length
23
+ else
24
+ "'#{section}'"
25
+ end
26
+ end.join
27
+ end
28
+
29
+ # From a command, will build up a runnable command. If args isn't provided,
30
+ # it will escape arguments.
31
+ def build_cli_call(command, args = nil)
32
+ "#{command} #{escape_arguments(args)}".strip
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -1,15 +1,19 @@
1
+ require 'yaml'
2
+
1
3
  module RVM
2
4
  module Version
3
5
 
4
- require "yaml"
5
-
6
- YAML = YAML.load_file("#{File.expand_path(File.dirname(__FILE__))}/../VERSION.yml")
7
-
8
- MAJOR = YAML[:major]
9
- MINOR = YAML[:minor]
10
- PATCH = YAML[:patch]
6
+ # YAML of raw version info
7
+ VERSION_YAML = YAML.load_file(File.expand_path("../VERSION.yml", File.dirname(__FILE__)))
11
8
 
12
- STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
9
+ # Current major version of rvm
10
+ MAJOR = VERSION_YAML[:major]
11
+ # Current minor version of rvm
12
+ MINOR = VERSION_YAML[:minor]
13
+ # Current patch level of rvm
14
+ PATCH = VERSION_YAML[:patch]
15
+ # A String with the current rvm version
16
+ STRING = [MAJOR, MINOR, PATCH].join(".").freeze
13
17
 
14
18
  end
15
19
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rvm}
8
- s.version = "0.1.41"
8
+ s.version = "0.1.42"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Wayne E. Seguin"]
12
- s.date = %q{2010-07-08}
12
+ s.date = %q{2010-07-20}
13
13
  s.default_executable = %q{rvm-install}
14
14
  s.description = %q{Manages Ruby interpreter environments and switching between them.}
15
15
  s.email = %q{wayneeseguin@gmail.com}
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
22
22
  "README",
23
23
  "binscripts/rvm",
24
24
  "binscripts/rvm-prompt",
25
+ "binscripts/rvm-shell",
25
26
  "binscripts/rvm-update-head",
26
27
  "binscripts/rvm-update-latest",
27
28
  "binscripts/rvmsudo",
@@ -29,6 +30,7 @@ Gem::Specification.new do |s|
29
30
  "config/known",
30
31
  "config/md5",
31
32
  "contrib/gemset_snapshot",
33
+ "contrib/install-system-wide",
32
34
  "examples/rvmrc",
33
35
  "gemsets/default.gems",
34
36
  "gemsets/global.gems",
@@ -61,9 +63,27 @@ Gem::Specification.new do |s|
61
63
  "install",
62
64
  "lib/VERSION.yml",
63
65
  "lib/rvm.rb",
64
- "lib/rvm/open4.rb",
65
- "lib/rvm/rvm.rb",
66
+ "lib/rvm/capistrano.rb",
67
+ "lib/rvm/environment.rb",
68
+ "lib/rvm/environment/alias.rb",
69
+ "lib/rvm/environment/cleanup.rb",
70
+ "lib/rvm/environment/configuration.rb",
71
+ "lib/rvm/environment/env.rb",
72
+ "lib/rvm/environment/gemset.rb",
73
+ "lib/rvm/environment/info.rb",
74
+ "lib/rvm/environment/list.rb",
75
+ "lib/rvm/environment/rubies.rb",
76
+ "lib/rvm/environment/sets.rb",
77
+ "lib/rvm/environment/tools.rb",
78
+ "lib/rvm/environment/utility.rb",
79
+ "lib/rvm/environment/wrapper.rb",
80
+ "lib/rvm/errors.rb",
66
81
  "lib/rvm/shell.rb",
82
+ "lib/rvm/shell/abstract_wrapper.rb",
83
+ "lib/rvm/shell/result.rb",
84
+ "lib/rvm/shell/shell_wrapper.sh",
85
+ "lib/rvm/shell/single_shot_wrapper.rb",
86
+ "lib/rvm/shell/utility.rb",
67
87
  "lib/rvm/version.rb",
68
88
  "rvm.gemspec",
69
89
  "scripts/alias",
@@ -76,6 +96,7 @@ Gem::Specification.new do |s|
76
96
  "scripts/color",
77
97
  "scripts/completion",
78
98
  "scripts/db",
99
+ "scripts/disk-usage",
79
100
  "scripts/docs",
80
101
  "scripts/env",
81
102
  "scripts/fetch",
@@ -91,6 +112,7 @@ Gem::Specification.new do |s|
91
112
  "scripts/list",
92
113
  "scripts/log",
93
114
  "scripts/maglev",
115
+ "scripts/man",
94
116
  "scripts/manage",
95
117
  "scripts/manpages",
96
118
  "scripts/match",
@@ -105,6 +127,7 @@ Gem::Specification.new do |s|
105
127
  "scripts/rvm-install",
106
128
  "scripts/selector",
107
129
  "scripts/set",
130
+ "scripts/tools",
108
131
  "scripts/update",
109
132
  "scripts/utility",
110
133
  "scripts/version",