Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial port of RVM Ruby Gem Library from the core RVM shell epostiory.

  • Loading branch information...
commit 2c0bbf80e8201c89c55d8a2df54a47b48951d5a2 0 parents
@wayneeseguin wayneeseguin authored
Showing with 1,810 additions and 0 deletions.
  1. +2 −0  .gitignore
  2. +5 −0 History.md
  3. +28 −0 Manifest.yml
  4. +16 −0 README.md
  5. +9 −0 Rakefile
  6. +157 −0 lib/rvm.rb
  7. +69 −0 lib/rvm/environment.rb
  8. +69 −0 lib/rvm/environment/alias.rb
  9. +54 −0 lib/rvm/environment/cleanup.rb
  10. +60 −0 lib/rvm/environment/configuration.rb
  11. +65 −0 lib/rvm/environment/env.rb
  12. +222 −0 lib/rvm/environment/gemset.rb
  13. +17 −0 lib/rvm/environment/info.rb
  14. +139 −0 lib/rvm/environment/list.rb
  15. +54 −0 lib/rvm/environment/rubies.rb
  16. +123 −0 lib/rvm/environment/sets.rb
  17. +68 −0 lib/rvm/environment/tools.rb
  18. +176 −0 lib/rvm/environment/utility.rb
  19. +23 −0 lib/rvm/environment/wrapper.rb
  20. +31 −0 lib/rvm/errors.rb
  21. +51 −0 lib/rvm/install_command_dumper.rb
  22. +27 −0 lib/rvm/shell.rb
  23. +145 −0 lib/rvm/shell/abstract_wrapper.rb
  24. +26 −0 lib/rvm/shell/calculate_rvm_path.sh
  25. +42 −0 lib/rvm/shell/result.rb
  26. +9 −0 lib/rvm/shell/shell_wrapper.sh
  27. +56 −0 lib/rvm/shell/single_shot_wrapper.rb
  28. +37 −0 lib/rvm/shell/utility.rb
  29. +3 −0  lib/rvm/version.rb
  30. +25 −0 rvm.gemspec
  31. +2 −0  spec/spec_helper.rb
2  .gitignore
@@ -0,0 +1,2 @@
+.rvmrc
+*.gem
5 History.md
@@ -0,0 +1,5 @@
+=== 1.11.3.1 / 2012-03-26
+
+* Ported RVM Gem Library into it's own repository from the main RVM
+ repostitory. ( https://github.com/wayneeseguin/rvm-gem )
+
28 Manifest.yml
@@ -0,0 +1,28 @@
+- History.md
+- Manifest.yml
+- README.md
+- Rakefile
+- lib/rvm.rb
+- lib/rvm/environment/alias.rb
+- lib/rvm/environment/cleanup.rb
+- lib/rvm/environment/configuration.rb
+- lib/rvm/environment/env.rb
+- lib/rvm/environment/gemset.rb
+- lib/rvm/environment/info.rb
+- lib/rvm/environment/list.rb
+- lib/rvm/environment/rubies.rb
+- lib/rvm/environment/sets.rb
+- lib/rvm/environment/tools.rb
+- lib/rvm/environment/utility.rb
+- lib/rvm/environment/wrapper.rb
+- lib/rvm/environment.rb
+- lib/rvm/errors.rb
+- lib/rvm/install_command_dumper.rb
+- lib/rvm/shell/abstract_wrapper.rb
+- lib/rvm/shell/calculate_rvm_path.sh
+- lib/rvm/shell/result.rb
+- lib/rvm/shell/shell_wrapper.sh
+- lib/rvm/shell/single_shot_wrapper.rb
+- lib/rvm/shell/utility.rb
+- lib/rvm/shell.rb
+- lib/rvm/version.rb
16 README.md
@@ -0,0 +1,16 @@
+# rvm
+
+https://rvm.beginrescueend.com/
+
+## Description
+
+RVM ~ Ruby Environment Manager ~ Ruby Gem Library
+
+## Installation
+
+* gem install rvm
+
+## Development
+
+ $ rake spec
+
9 Rakefile
@@ -0,0 +1,9 @@
+task :default => "spec:run"
+
+namespace :spec do
+ desc "Run the tests."
+ task :run do
+ # TODO: Port over the tests.
+ end
+end
+
157 lib/rvm.rb
@@ -0,0 +1,157 @@
+# == Ruby Version Manager - Ruby API
+#
+# Provides a wrapper around the command line api implemented as part of the api.
+# If you're not familiar with rvm, please read https://rvm.beginrescueend.com/
+# first.
+#
+# == Usage
+#
+# When using the rvm ruby api, you gain access to most of the commands, including the set
+# functionality. As a side node, the RVM module provides access to most of the api
+# both via direct api wrappers (of the form <tt><tool>_<action></tt> - e.g. +alias_create+,
+# +gemset_use+ and +wrapper+).
+#
+# == The Environment Model
+#
+# The RVM ruby api is implemented using an environment model. Each environment maps directly
+# to some ruby string interpretable by rvm (e.g. +ree+, +ruby-1.8.7-p174+, +system+, +rbx@rails+
+# and so on) and is considered a sandboxed environment (for commands like use etc) in which you
+# can deal with rvm. it's worth noting that a single environment can have multiple environment
+# instances and for the most part creating of these instances is best handled by the RVM.environment
+# and RVM.environments methods.
+#
+# Each Environment (and instance of RVM::Environment) provides access to the rvm ruby api (in some
+# cases, the api may not directly be related to the current ruby - but for simplicity / consistency
+# purposes, they are still implemented as methods of RVM::Environment).
+#
+# When you perform an action with side effects (e.g. RVM::Environment#gemset_use or RVM::Environment#use)
+# this will mutate the ruby string of the given environment (hence, an environment is considered mutable).
+#
+# Lastly, for the actual command line work, RVM::Environment works with an instance of RVM::Shell::AbstractWrapper.
+# This performs logic (such as correctly escaping strings, calling the environment and such) in a way that
+# is both reusable and simplified.
+#
+# By default, method_missing is used on the RVM module to proxy method calls to RVM.current (itself
+# calling RVM::Environment.current), meaning things like RVM.gemset_name, RVM.alias_create and the like
+# work. This is considered the 'global' instance and should be avoided unless needed directly.
+#
+# RVM::Environment.current will first attempt to use the current ruby string (determined by
+# +ENV['GEM_HOME']+ but will fall back to using the rubies load path if that isn't available).
+#
+# In many cases, (e.g. +alias+, +list+ and the like) there is a more ruby-like wrapper class,
+# typically available via <tt>RVM::Environment#<action></tt>.
+#
+# == Side Notes
+#
+# In the cases this api differs, see the RVM::Environment class for more information.
+#
+# You can check the name of a given environment in two ways - RVM::Environment#environment_name
+# for the short version / the version set by RVM::Environment#use, RVM::Environment#gemset_use
+# or RVM.environment. If you wish to get the full, expanded string (which has things such as
+# the actual version of the selected ruby), you instead with to use RVM::Environment#expanded_name.
+#
+# Lastly, If you do need to pass environment variables to a specific environment, please use
+# RVM::Environment.new, versus RVM.environment
+#
+module RVM
+ require 'rvm/errors'
+ require 'rvm/shell'
+ require 'rvm/environment'
+ require 'rvm/version'
+
+ class << self
+
+ # Returns the current global environment.
+ def current
+ Environment.current
+ end
+
+ # Reset the current global environment to the default / what it was
+ # when the process first started.
+ def reset_current!
+ Environment.reset_current!
+ end
+
+ # Returns an array of multiple environments. If given
+ # a block, will yield each time with the given environment.
+ #
+ # RVM.environments("ree@rails3,rbx@rails3") do |env|
+ # puts "Full environment: #{env.expanded_name}"
+ # end
+ # # => "ree-1.8.7@rails3"
+ # # => "rbx-1.1.0@rails3" # Suppose that you are installed rbx 1.1.0
+ #
+ # Alternatively, you can use the more ruby-like fashion:
+ #
+ # RVM.environments("ree@rails3", "rbx@rails3") do |env|
+ # puts "Full environment: #{env.expanded_name}"
+ # end
+ #
+ def environments(*names, &blk)
+ # Normalize the names before using them on for the environment.
+ names.flatten.join(",").split(",").uniq.map do |n|
+ environment(n, &blk)
+ end
+ end
+
+ # Returns the environment with the given name.
+ # If passed a block, will yield with that as the single argument.
+ #
+ # RVM.environment("ree@rails3") do |env|
+ # puts "Gemset is #{env.gemset.name}"
+ # end
+ #
+ def environment(name)
+ # TODO: Maintain an Environment cache.
+ # The cache needs to track changes via use etc though.
+ env = Environment.new(name)
+ yield env if block_given?
+ env
+ end
+
+ # Merges items into the default config, essentially
+ # setting environment variables passed to child processes:
+ #
+ # RVM.merge_config!({
+ # :some_shell_variable => "me",
+ # })
+ #
+ def merge_config!(config = {})
+ Environment.merge_config!(config)
+ end
+
+ # Returns the current 'best guess' value for rvm_path.
+ def path
+ Environment.rvm_path
+ end
+
+ # Shortcut to set rvm_path. Will set it on all new instances
+ # but wont affect currently running environments.
+ def path=(value)
+ Environment.rvm_path = value
+ end
+
+ private
+
+ def cache_method_call(name)
+ class_eval <<-END, __FILE__, __LINE__
+ def #{name}(*args, &blk)
+ current.__send__(:#{name}, *args, &blk)
+ end
+ END
+ end
+
+ # Proxies methods to the current environment, creating a
+ # method before dispatching to speed up future calls.
+ def method_missing(name, *args, &blk)
+ if current.respond_to?(name)
+ cache_method_call name
+ current.__send__ name, *args, &blk
+ else
+ super
+ end
+ end
+
+ end
+
+end
69 lib/rvm/environment.rb
@@ -0,0 +1,69 @@
+require 'forwardable'
+
+module RVM
+ # Implements the actual wrapper around the api. For more information
+ # about this design, see the RVM module.
+ class Environment
+ extend Forwardable
+
+ %w(configuration utility alias list gemset rubies cleanup sets env tools info wrapper).each do |key|
+ require File.join("rvm", "environment", key)
+ end
+
+ # The default config has rvm_silence_logging so that log doesn't print anything to stdout.
+ merge_config! :rvm_silence_logging => 1,
+ :rvm_promptless => 1,
+ :rvm_ruby_api => 1
+
+ attr_reader :environment_name, :shell_wrapper
+
+ # Creates a new environment with the given name and optionally
+ # a set of extra environment variables to be set on load.
+ def initialize(environment_name = "default", options = {})
+ merge_config! options
+ @environment_name = environment_name
+ @shell_wrapper = Shell.default_wrapper.new
+ @shell_wrapper.setup do |s|
+ source_rvm_environment
+ use_rvm_environment
+ end
+ end
+
+ def inspect
+ "#<#{self.class.name} environment_name=#{@environment_name.inspect}>"
+ end
+
+ # Returns the expanded name, using the same method as used by the rvm command line.
+ #
+ # Suppose that you are in the 1.9.2 patchlevel Environment.
+ #
+ # env.expanded_name # => "ruby-1.9.2-p0"
+ #
+ def expanded_name
+ @expanded_name ||= tools_identifier.to_s
+ end
+
+ # Actually define methods to interact with the shell wrapper.
+ def_delegators :@shell_wrapper, :run, :run_silently, :run_command_without_output,
+ :run_command, :[], :escape_argument
+
+ protected
+
+ # Automatically load rvm config from the multiple sources.
+ def source_rvm_environment
+ rvm_path = config_value_for(:rvm_path, self.class.default_rvm_path, false)
+ actual_config = defined_config.merge('rvm_path' => rvm_path)
+ config = []
+ actual_config.each_pair do |k, v|
+ config << "#{k}=#{escape_argument(v.to_s)}"
+ end
+ run_silently "export #{config.join(" ")}"
+ run_silently :source, File.join(rvm_path, "scripts", "rvm")
+ end
+
+ def use_rvm_environment
+ rvm :use, @environment_name, :silent => true
+ end
+
+ end
+end
69 lib/rvm/environment/alias.rb
@@ -0,0 +1,69 @@
+module RVM
+ class Environment
+
+ # Returns a hash of aliases.
+ def alias_list
+ lines = normalize_array(rvm(:alias, :list).stdout)
+ lines.inject({}) do |acc, current|
+ alias_name, ruby_string = current.to_s.split(" => ")
+ unless alias_name.empty? || ruby_string.empty?
+ acc[alias_name] = ruby_string
+ end
+ acc
+ end
+ end
+
+ # Shows the full ruby string that a given alias points to.
+ def alias_show(name)
+ normalize rvm(:alias, :show, name.to_s).stdout
+ end
+
+ # Deletes an alias and returns the exit status.
+ def alias_delete(name)
+ rvm(:alias, :delete, name.to_s).successful?
+ end
+
+ # Creates an alias with the given name.
+ def alias_create(name, ruby_string)
+ rvm(:alias, :create, name.to_s, ruby_string.to_s).successful?
+ end
+
+ # Returns an aliases proxy which can be used in a more Ruby-like manner.
+ def aliases
+ @aliases ||= AliasWrapper.new(self)
+ end
+
+ # Provides a Ruby-like wrapper to the alias functionality.
+ class AliasWrapper
+
+ def initialize(parent)
+ @parent = parent
+ end
+
+ # Shows the value of a given alias.
+ def show(name)
+ @parent.alias_show name
+ end
+ alias [] show
+
+ # Deletes the given alias.
+ def delete(name)
+ @parent.alias_delete name
+ end
+
+ # Creates an alias with a given name and ruby string.
+ def create(name, ruby_string)
+ @parent.alias_create name, ruby_string
+ end
+ alias []= create
+
+ # Returns a hash of all aliases.
+ def list
+ @parent.alias_list
+ end
+ alias all list
+
+ end
+
+ end
+end
54 lib/rvm/environment/cleanup.rb
@@ -0,0 +1,54 @@
+module RVM
+ class Environment
+
+ # Batch define common operations.
+ %w(all archives repos sources logs).each do |cleanup_type|
+ define_method(:"cleanup_#{cleanup_type}") do
+ rvm(:cleanup, cleanup_type).successful?
+ end
+ end
+
+ # Returns the ruby-like interface defined by CleanupWrapper
+ def cleanup
+ @cleanup_wrapper ||= CleanupWrapper.new(self)
+ end
+
+ # Implements a Ruby-like interface to cleanup, making it nicer to deal with.
+ class CleanupWrapper
+
+ def initialize(parent)
+ @parent = parent
+ end
+
+ # Cleans up archives, repos, sources and logs
+ def all
+ @parent.cleanup_all
+ end
+ alias everything all
+
+ # Cleans up everything in the archives folder
+ def archives
+ @parent.cleanup_archives
+ end
+
+ # Cleans up everything in the repos path
+ def repos
+ @parent.cleanup_repos
+ end
+ alias repositories repos
+
+ # Cleans up everything in the source folder
+ def sources
+ @parent.cleanup_sources
+ end
+ alias src sources
+
+ # Cleans up all of the logs
+ def logs
+ @parent.cleanup_logs
+ end
+
+ end
+
+ end
+end
60 lib/rvm/environment/configuration.rb
@@ -0,0 +1,60 @@
+module RVM
+ class Environment
+
+ # Define the config accessor, which basically uses config_value_for and
+ # the linke to set the env variable.
+ def self.define_config_accessor(*args)
+ singleton = (class << self; self; end)
+ args.each do |arg|
+ singleton.send(:define_method, arg) { RVM::Environment.config_value_for(arg) }
+ singleton.send(:define_method, :"#{arg}=") { |v| RVM::Environment.merge_config! arg => v }
+ end
+ end
+
+ define_config_accessor :rvm_path, :rvm_config_path, :rvm_bin_path
+
+ # Mixin for a set of configs.
+ module ConfigMixin
+
+ # Returns the current config for this scope
+ def config
+ @config ||= {}
+ end
+
+ # Merge a set of items into the config.
+ def merge_config!(r)
+ r.each_pair { |k, v| config[k.to_s] = v }
+ end
+
+ # Reset this local config to be empty.
+ def clear_config!
+ @config = {}
+ end
+ end
+
+ include ConfigMixin
+ extend ConfigMixin
+
+ # Gets the default option or the current
+ # environment variable for a given env var.
+ def self.config_value_for(value)
+ value = value.to_s
+ config[value] || ENV[value]
+ end
+
+ # Returns the value for a configuration option (mapping to an
+ # environment variable). If check_live is true (which it is
+ # by default), it will also check the environment for a value.
+ def config_value_for(key, default = nil, check_live = true)
+ key = key.to_s
+ value = check_live ? self[key.to_s] : nil
+ value || config[key] || self.class.config_value_for(key) || default
+ end
+
+ # Returns a hash of all of the user defined configuration.
+ def defined_config
+ self.class.config.merge(self.config)
+ end
+
+ end
+end
65 lib/rvm/environment/env.rb
@@ -0,0 +1,65 @@
+module RVM
+ class Environment
+
+ # Returns the contents of the env file.
+ #
+ # env.env_contents # => ['export PATH= ....', ...]
+ #
+ def env_contents
+ rvm(:env, environment_name).stdout.split
+ end
+
+ # Returns the path to the env file
+ # Suppose that you are in the 1.9.2 environment.
+ #
+ # env.env_path # => "~/.rvm/environments/ruby-1.9.2-p0"
+ #
+ def env_path
+ normalize_array rvm(:env, environment_name, :path => true).stdout
+ end
+
+ # Returns a ruby-like wrapper for the env functions
+ def env
+ @env_wrapper ||= EnvWrapper.new(self)
+ end
+
+ # Returns the path for the given command
+ #
+ # Suppose that you are in the 1.9.2 environment.
+ #
+ # env.path_for(:rspec) # => '~/.rvm/gems/ruby-1.9.2-p0/bin/rspec'
+ # env.path_for(:ruby) # => '~/.rvm/rubies/ruby-1.9.2-p0/bin/ruby'
+ #
+ def path_for(command)
+ run(:command, "-v", command).stdout.strip
+ end
+ alias which path_for
+
+ # Simple ruby like wrapper for envs.
+ class EnvWrapper
+
+ def initialize(parent)
+ @parent = parent
+ end
+
+ # Contents of the env file.
+ def contents
+ @parent.env_contents
+ end
+ alias read contents
+ alias to_s contents
+
+ # The path of the env file.
+ def path
+ @parent.env_path
+ end
+
+ # Opens a file on the env file.
+ def to_file
+ File.open(path)
+ end
+
+ end
+
+ end
+end
222 lib/rvm/environment/gemset.rb
@@ -0,0 +1,222 @@
+module RVM
+ class Environment
+
+ # Loads a gemset into the current environment.
+ # If an argument is given, it will load it from
+ # file_prefix.gems
+ def gemset_import(file_prefix = nil)
+ args = [file_prefix].compact
+ rvm(:gemset, :import, *args).successful?
+ end
+ alias gemset_load gemset_import
+
+ # Exports a gemset.
+ def gemset_export(gemset_or_file = nil)
+ args = [gemset_or_file].compact
+ rvm(:gemset, :export, *args).successful?
+ end
+ alias gemset_dump gemset_export
+
+ def gemset_list
+ normalize_array rvm(:gemset, :list).stdout
+ end
+
+ # Creates a new gemset with the given name.
+ def gemset_create(*names)
+ names = names.flatten
+ rvm(:gemset, :create, *names).successful?
+ end
+
+ # Copies the gems between two different gemsets.
+ def gemset_copy(from, to)
+ rvm(:gemset, :copy, from, to).successful?
+ end
+
+ # Deletes the gemset with a given name.
+ def gemset_delete(name)
+ run("echo 'yes' | rvm", :gemset, :delete, name.to_s).successful?
+ end
+
+ # Removes all gem-related stuff from the current gemset.
+ def gemset_empty
+ run("echo 'yes' | rvm", :gemset, :empty).successful?
+ end
+
+ # Resets the current gemset to a pristine state.
+ def gemset_pristine
+ rvm(:gemset, :pristine).successful?
+ end
+
+ # Updates all gems in the current gemset.
+ def gemset_update
+ rvm(@environment_name, :gemset, :update).successful?
+ end
+
+ # Prunes the gem cache for the current ruby.
+ def gemset_prune
+ rvm(:gemset, :prune).successful?
+ end
+
+ # Initializes gemsets for a given ruby.
+ def gemset_initial
+ rvm(:gemset, :initial).successful?
+ end
+
+ # Enable or disable the rvm gem global cache.
+ def gemset_globalcache(enable = true)
+ case enable
+ when "enabled", :enabled
+ run(:__rvm_using_gemset_globalcache).successful?
+ when true, "enable", :enable
+ rvm(:gemset, :globalcache, :enable).successful?
+ when false, "disable", :disable
+ rvm(:gemset, :globalcache, :disable).successful?
+ else
+ false
+ end
+ end
+
+ # Changes the current environments gemset. If :replace_env is passed
+ # and the ruby is compatible, it will attempt to replace the current
+ # processes gem home and path with the one requested.
+ def gemset_use(gemset, options = {})
+ replace_env = options.delete(:replace_env)
+ result = rvm(:gemset, :use, gemset, options)
+ if result.successful?
+ gemset_name = self.class.identifier_to_gemset_name(result[:rvm_env_string])
+ @environment_name = self.class.environment_with_gemset(@environment_name, gemset_name)
+ @expanded_name = nil
+ self.class.reset_current!
+ use_env_from_result! result if replace_env
+ true
+ end
+ end
+
+ # Like gemset_use, but replaces the env by default.
+ def gemset_use!(name, options = {})
+ gemset_use name, {:replace_env => true}.merge(options)
+ end
+
+ %w(gemdir gempath gemhome home path version name string dir).each do |action|
+ define_method(:"gemset_#{action}") do
+ normalize rvm(:gemset, action).stdout
+ end
+ end
+
+ # Returns the Ruby-like wrapper for gemset operations.
+ def gemset
+ @gemset_wrapper ||= GemsetWrapper.new(self)
+ end
+
+ # Wraps the gemset functionality.
+ class GemsetWrapper
+ extend Forwardable
+
+ def initialize(parent)
+ @parent = parent
+ end
+
+ # Import a gemset file.
+ def import(prefix)
+ @parent.gemset_import prefix.to_s.gsub(/\.gems$/, '')
+ end
+ alias load import
+
+ # Export a given gemset or, if the name ends with .gems, the current gemset.
+ def export(path_or_name)
+ @parent.gemset_export path_or_name.to_s
+ end
+ alias dump export
+ alias save export
+
+ # Returns a list of all gemsets belonging to the current ruby.
+ def list
+ @parent.gemset_list
+ end
+ alias all list
+
+ # Creates gemsets with the given names.
+ def create(*names)
+ @parent.gemset_create(*names.flatten)
+ end
+
+ # Delete a given gemset.
+ def delete(name)
+ @parent.gemset_delete(name)
+ end
+
+ # Empty the current gemset.
+ def empty
+ @parent.gemset_empty
+ end
+
+ # Restores the current gemset to a pristine state.
+ def pristine
+ @parent.gemset_pristine
+ end
+
+ # Updates all gems in the current gemset.
+ def update
+ @parent.gemset_update
+ end
+
+ # Prune the current gemset.
+ def prune
+ @parent.gemset_prune
+ end
+
+ # Use a given gemset in this environment
+ def use(name)
+ @parent.gemset_use(name)
+ end
+
+ # Use the given gemset, replacing the current
+ # gem environment if possible.
+ def use!(name)
+ @parent.gemset_use(name, :replace_env => true)
+ end
+
+ # Shortcut to deal with the gemset global cache.
+ def globalcache
+ @globalcache ||= GlobalCacheHelper.new(@parent)
+ end
+
+ # Copy gems from one gemset to another.
+ def copy(from, to)
+ @parent.gemset_copy(from, to)
+ end
+
+ %w(gemdir gempath gemhome home path version name string dir).each do |action|
+ define_method(action) do
+ @parent.send(:"gemset_#{action}")
+ end
+ end
+
+ # A Ruby-like wrapper to manipulate the rvm gem global cache.
+ class GlobalCacheHelper
+
+ def initialize(parent)
+ @parent = parent
+ end
+
+ # Enable the globalcache
+ def enable!
+ @parent.gemset_globalcache :enable
+ end
+
+ # Disable the globalcache
+ def disable!
+ @parent.gemset_globalcache :disable
+ end
+
+ # Returns whether or not the globalcache is enabled.
+ def enabled?
+ @parent.gemset_globalcache :enabled
+ end
+
+ end
+
+ end
+
+ end
+end
17 lib/rvm/environment/info.rb
@@ -0,0 +1,17 @@
+require 'yaml'
+
+module RVM
+ class Environment
+
+ # Return a Hash with the same output that command:
+ #
+ # $ rvm info
+ #
+ def info(*ruby_strings)
+ ruby_string = normalize_ruby_string(ruby_strings)
+ res = rvm(:info, ruby_string)
+ res.successful? ? YAML.load(res.stdout) : {}
+ end
+
+ end
+end
139 lib/rvm/environment/list.rb
@@ -0,0 +1,139 @@
+module RVM
+ class Environment
+
+ # Returns a raw array list of ruby + gemset combinations.
+ #
+ # env.list_gemsets # => ['ruby-1.9.2-p0@my_gemset', 'jruby@my_gemset', ...]
+ #
+ def list_gemsets
+ normalize_listing_output rvm(:list, :gemsets, :strings).stdout
+ end
+
+ # Returns a raw array list of installed ruby strings, including aliases.
+ #
+ # env.list_strings # => ["ruby-1.9.2-p0", "jruby-1.5.3"]
+ #
+ def list_strings
+ normalize_listing_output rvm(:list, :strings).stdout.tr(' ', "\n")
+ end
+
+ # Lists the default ruby (minus gemset)
+ # Suppose that Ruby 1.9.2 patchlevel 0, is the default:
+ #
+ # env.list_default # => "ruby-1.9.2-p0"
+ #
+ def list_default
+ normalize rvm(:list, :default, :string).stdout
+ end
+
+ # Lists all known ruby strings (raw, filtered output)
+ #
+ def list_known
+ normalize_listing_output rvm(:list, :known).stdout
+ end
+
+ # Lists all known ruby strings
+ #
+ def list_known_strings
+ normalize_listing_output rvm(:list, :known_strings).stdout
+ end
+
+ # Lists all known svn tags.
+ #
+ def list_ruby_svn_tags
+ normalize_listing_output rvm(:list, :ruby_svn_tags).stdout
+ end
+
+ # Returns an interface to a more Ruby-like interface for list.
+ #
+ def list
+ @list_helper ||= ListWrapper.new(self)
+ end
+
+ # Provides a ruby-like interface to make listing rubies easier.
+ #
+ class ListWrapper
+
+ def initialize(parent)
+ @parent = parent
+ end
+
+ # Returns an array of ruby + gemset combinations.
+ def gemsets
+ @parent.list_gemsets
+ end
+
+ # Returns an array of installed rubies.
+ def rubies
+ @parent.list_strings
+ end
+ alias installed rubies
+ alias strings rubies
+
+ # Shows the current default. If :gemset is passed in and is
+ # true, it will include the gemset in the output.
+ def default(options = {})
+ options[:gemset] ? @parent.show_alias(:default) : @parent.list_default
+ end
+
+ # A raw list of known rubies.
+ def raw_known
+ @parent.list_known
+ end
+
+ def known_strings
+ @parent.list_known_strings
+ end
+
+ # A list of known ruby strings, minus svn tags.
+ def expanded_known
+ raw_known.map do |raw|
+ expand_variants(raw)
+ end.flatten.uniq.sort
+ end
+
+ # Raw list of svn tagged version
+ def raw_ruby_svn_tags
+ @parent.list_ruby_svn_tags
+ end
+
+ # Normalized list of ruby svn tags.
+ def ruby_svn_tags
+ raw_ruby_svn_tags.map { |t| expand_variants(t) }.flatten.uniq.sort
+ end
+ alias from_svn ruby_svn_tags
+
+ # Most installable ruby strings.
+ def installable
+ (expanded_known + ruby_svn_tags).uniq.sort
+ end
+
+ protected
+
+ # Expands strings to include optional parts (surrounded in brackets),
+ # given a useable string.
+ def expand_variants(s)
+ if s =~ /(\([^\)]+\))/
+ part = $1
+ expand_variants(s.sub(part, "")) + expand_variants(s.sub(part, part[1..-2]))
+ else
+ [s]
+ end
+ end
+
+ end
+
+ protected
+
+ # Takes a list of rubies / items, 1 per line and strips comments and blank lines.
+ def normalize_listing_output(results)
+ lines = []
+ results.each_line do |line|
+ line = line.gsub(/#.*/, '').strip
+ lines << line unless line.empty?
+ end
+ lines.sort
+ end
+
+ end
+end
54 lib/rvm/environment/rubies.rb
@@ -0,0 +1,54 @@
+module RVM
+ class Environment
+
+ # Installs the given ruby
+ def install(rubies, opts = {})
+ rvm(:install, normalize_ruby_string(rubies), opts).successful?
+ end
+
+ # Uninstalls a ruby (remove but keeps src etc)
+ def uninstall(rubies, opts = {})
+ rvm(:uninstall, normalize_ruby_string(rubies), opts).successful?
+ end
+
+ # Removes a given ruby from being managed by rvm.
+ def remove(rubies, opts = {})
+ rvm(:remove, normalize_ruby_string(rubies), opts).successful?
+ end
+
+ # Changes the ruby string for the current environment.
+ #
+ # env.use '1.9.2' # => nil
+ # env.use 'ree' # => nil
+ #
+ def use(ruby_string, opts = {})
+ ruby_string = ruby_string.to_s
+ result = rvm(:use, ruby_string)
+ if result.successful?
+ @environment_name = ruby_string
+ @expanded_name = nil
+ use_env_from_result! result if opts[:replace_env]
+ end
+ end
+
+ # Like use but with :replace_env defaulting to true.
+ def use!(ruby_string, opts = {})
+ use ruby_string, opts.merge(:replace_env => true)
+ end
+
+ # Will get the ruby from the given path. If there
+ # is a compatible ruby found, it will then attempt
+ # to use the associated gemset.
+ # e.g. RVM::Environment.current.use_from_path! Dir.pwd
+ def use_from_path!(path)
+ use! tools.path_identifier(path)
+ end
+
+ protected
+
+ def normalize_ruby_string(rubies)
+ Array(rubies).join(",")
+ end
+
+ end
+end
123 lib/rvm/environment/sets.rb
@@ -0,0 +1,123 @@
+module RVM
+ class Environment
+
+ # Passed either something containing ruby code or
+ # a path to a ruby file, will attempt to exectute
+ # it in the current environment.
+ def ruby(runnable, options = {})
+ if runnable.respond_to?(:path)
+ # Call the path
+ ruby_run runnable.path, options
+ elsif runnable.respond_to?(:to_str)
+ runnable = runnable.to_str
+ File.exist?(runnable) ? ruby_run(runnable, options) : ruby_eval(runnable, options)
+ elsif runnable.respond_to?(:read)
+ ruby_run runnable.read
+ end
+ end
+
+ # Eval the given code within ruby.
+ def ruby_eval(code, options = {})
+ perform_set_operation :ruby, "-e", code.to_s, options
+ end
+
+ # Run the given path as a ruby script.
+ def ruby_run(path, options = {})
+ perform_set_operation :ruby, path.to_s, options
+ end
+
+ # Execute rake (optionally taking the path to a rake file),
+ # then change back.
+ def rake(file = nil, options = {})
+ if file.nil?
+ perform_set_operation :rake, options
+ else
+ file = File.expand_path(file)
+ chdir(File.dirname(file)) do
+ perform_set_operation(:rake, options.merge(:rakefile => file))
+ end
+ end
+ end
+
+ # Use the rvm test runner for unit tests.
+ def tests(options = {})
+ perform_set_operation :tests, options
+ end
+
+ # Use the rvm spec runner for specs.
+ def specs(options = {})
+ perform_set_operation :specs, options
+ end
+
+ # Like Kernel.system, but evaluates it within the environment.
+ # Also note that it doesn't support redirection etc.
+ def system(command, *args)
+ identifier = extract_identifier!(args)
+ args = [identifier, :exec, command, *args].compact
+ rvm(*args).successful?
+ end
+
+ # Executes a command, replacing the current shell.
+ # exec is a bit of an odd ball compared to the others, since
+ # it has to use the Kernel.exec builtin.
+ def exec(command, *args)
+ command = @shell_wrapper.build_cli_call(:exec, [command] + args)
+ Kernel.exec "bash", "-c", "source '#{env_path}'; #{command}"
+ end
+
+ protected
+
+ # Converts the given identifier to a rvm-friendly form.
+ # Unlike using sets directly, a nil identifier is set
+ # to mean the current ruby (not all). :all or "all" will
+ # instead return the a blank identifier / run it against
+ # all rubies.
+ def normalize_set_identifier(identifier)
+ case identifier
+ when nil, ""
+ @environment_name
+ when :all, "all"
+ nil
+ when Array
+ identifier.map { |i| normalize_set_identifier(i) }.uniq.join(",")
+ else
+ identifier.to_s
+ end
+ end
+
+ # From an options hash, extract the environment identifier.
+ def extract_environment!(options)
+ values = []
+ [:environment, :env, :rubies, :ruby].each do |k|
+ values << options.delete(k)
+ end
+ values.compact.first
+ end
+
+ # Shorthand to extra an identifier from args.
+ # Since we
+ def extract_identifier!(args)
+ options = extract_options!(args)
+ identifier = normalize_set_identifier(extract_environment!(options))
+ args << options
+ identifier
+ end
+
+ # Performs a set operation. If the :env or :environment option is given,
+ # it will return a yaml summary (instead of the stdout / stderr etc via
+ # a Result object.
+ def perform_set_operation(*args)
+ options = extract_options!(args)
+ environment = extract_environment!(options)
+ identifier = normalize_set_identifier(environment)
+ # Uses yaml when we have multiple identifiers.
+ uses_yaml = !environment.nil?
+ options.merge!(:yaml => true) if uses_yaml
+ args.unshift(identifier) unless identifier.nil?
+ args << options
+ result = rvm(*args)
+ uses_yaml ? YAML.load(result.stdout) : result
+ end
+
+ end
+end
68 lib/rvm/environment/tools.rb
@@ -0,0 +1,68 @@
+module RVM
+ class Environment
+
+ # Gets the full name for the current env.
+ def tools_identifier
+ normalize rvm(:tools, :identifier).stdout
+ end
+
+ # Gets the identifier after cd'ing to a path, no destructive.
+ def tools_path_identifier(path)
+ path_identifier = rvm(:tools, "path-identifier", path.to_s)
+ if path_identifier.exit_status == 2
+ error_message = "The rvmrc located in '#{path}' could not be loaded, likely due to trust mechanisms."
+ error_message << " Please run 'rvm rvmrc {trust,untrust} \"#{path}\"' to continue, or set rvm_trust_rvmrcs_flag to 1."
+ raise ErrorLoadingRVMRC, error_message
+ end
+ return normalize(path_identifier.stdout)
+ end
+
+ def tools_strings(*rubies)
+ rubies = rubies.flatten.join(",").split(",").uniq
+ names = {}
+ value = rvm(:tools, :strings, *rubies)
+ if value.successful?
+ parts = value.stdout.split
+ rubies.each_with_index do |key, index|
+ names[key] = normalize(parts[index])
+ end
+ end
+ names
+ end
+
+ # Return the tools wrapper.
+ def tools
+ @tools_wrapper ||= ToolsWrapper.new(self)
+ end
+
+ # Ruby like wrapper for tools
+ class ToolsWrapper
+
+ def initialize(parent)
+ @parent = parent
+ end
+
+ # Returns the current envs expanded identifier
+ def identifier
+ @parent.tools_identifier
+ end
+
+ # Returns the identifier for a path, taking into account
+ # things like an rvmrc
+ def path_identifier(path)
+ @parent.tools_path_identifier(File.expand_path(path))
+ end
+ alias identifier_for_path path_identifier
+
+ def strings(*rubies)
+ @parent.tools_strings(*rubies)
+ end
+
+ def expand_string(ruby)
+ strings(ruby)[ruby]
+ end
+
+ end
+
+ end
+end
176 lib/rvm/environment/utility.rb
@@ -0,0 +1,176 @@
+module RVM
+ class Environment
+
+ PREFIX_OPTIONS = [:trace, :json, :yaml]
+
+ def self.default_rvm_path
+ value = `bash '#{File.expand_path('../shell/calculate_rvm_path.sh', File.dirname(__FILE__))}'`.strip
+ $?.success? && !value.empty? ? File.expand_path(value) : nil
+ end
+
+ # Returns the environment identifier for the current environment,
+ # as determined from the GEM_HOME.
+ def self.current_environment_id
+ @current_environment_id ||= begin
+ gem_home = ENV['GEM_HOME'].to_s.strip
+ if !gem_home.empty? && gem_home =~ /rvm\/gems\//
+ File.basename(gem_home)
+ else
+ matching_path = $:.select { |item| item =~ /rvm\/rubies/ }.first
+ matching_path.to_s.gsub(/^.*rvm\/rubies\//, '').split('/')[0] || "system"
+ end
+ end
+ end
+
+ # Returns the ruby string that represents the current environment.
+ def self.current_ruby_string
+ identifier_to_ruby_string(current_environment_id)
+ end
+
+ # Converts a ruby identifier (string + gemset) to just the ruby string.
+ def self.identifier_to_ruby_string(identifier)
+ identifier.gsub(/@.*$/, '')
+ end
+
+ def self.identifier_to_gemset_name(identifier)
+ identifier.gsub(/^.*@/, '')
+ end
+
+ # Returns the currentl environment.
+ # Note that when the ruby is changed, this is reset - Also,
+ # if the gemset is changed it will also be reset.
+ def self.current
+ @current_environment ||= Environment.new(current_environment_id)
+ end
+
+ # Sets the current environment back to the currently running ruby
+ # or the system env (if it can't be determined from GEM_HOME).
+ def self.reset_current!
+ @current_environment = nil
+ end
+
+ # Lets you build a command up, without needing to see the output.
+ # As an example,
+ #
+ # rvm :use, "ree@rails3", :install => true
+ #
+ # Will call the following:
+ #
+ # rvm use ree@rails3 --install
+ #
+ def rvm(*args)
+ options = extract_options!(args)
+ silent = options.delete(:silent)
+ rearrange_options!(args, options)
+ args += hash_to_options(options)
+ args.map! { |a| a.to_s }
+
+ if silent
+ run_silently('rvm', *args)
+ else
+ run('rvm', *args)
+ end
+ end
+
+ # Run commands inside the given directory.
+ def chdir(dir)
+ run_silently :pushd, dir.to_s
+ result = Dir.chdir(dir) { yield }
+ run_silently :popd
+ result
+ end
+
+ protected
+
+ # Moves certain options (e.g. yaml, json etc) to the front
+ # of the arguments list, making stuff like sets work.
+ def rearrange_options!(args, options)
+ prefix_options = {}
+ (PREFIX_OPTIONS + PREFIX_OPTIONS.map { |o| o.to_s }).each do |k|
+ if options.has_key?(k)
+ value = options.delete(k)
+ prefix_options[k.to_sym] = value
+ end
+ end
+ hash_to_options(prefix_options).reverse.each { |o| args.unshift(o) }
+ end
+
+ def ruby_string(result)
+ if result && result[:rvm_env_string]
+ Environment.identifier_to_ruby_string result[:rvm_env_string]
+ else
+ self.class.identifier_to_ruby_string(expanded_name)
+ end
+ end
+
+ # Checks whether the given environment is compatible with the current
+ # ruby interpeter.
+ def compatible_with_current?(result)
+ ruby_string(result) == self.class.current_ruby_string
+ end
+
+ # Given an environment identifier, it will add the the given
+ # gemset to the end to form a qualified identifier name.
+ def self.environment_with_gemset(environment, gemset)
+ environment_name, gemset_name = environment.split("@", 2)
+ environment_name = "default" if environment_name.to_s.empty?
+ environment_name << "@#{gemset}" unless gemset.to_s.empty?
+ environment_name
+ end
+
+ # Returns a value, or nil if it is blank.
+ def normalize(value)
+ value = value.to_s.strip
+ value.empty? ? nil : value
+ end
+
+ # Normalizes an array, removing blank lines.
+ def normalize_array(value)
+ value.split("\n").map { |line| line.strip }.reject { |line| line.empty? }
+ end
+
+ # Extract options from a hash.
+ def extract_options!(args)
+ args.last.is_a?(Hash) ? args.pop : {}
+ end
+
+ # Converts a hash of options to an array of command line argumets.
+ # If the value is false, it wont be added but if it is true only the
+ # key will be added. Lastly, when the value is neither true or false,
+ # to_s will becalled on it and it shall be added to the array.
+ def hash_to_options(options)
+ result = []
+ options.each_pair do |key, value|
+ real_key = "--#{key.to_s.gsub("_", "-")}"
+ if value == true
+ result << real_key
+ elsif value != false
+ result << real_key
+ result << value.to_s
+ end
+ end
+ result
+ end
+
+ # Recursively normalize options.
+ def normalize_option_value(value)
+ case value
+ when Array
+ value.map { |option| normalize_option_value(option) }.join(",")
+ else
+ value.to_s
+ end
+ end
+
+ def use_env_from_result!(result)
+ if compatible_with_current?(result)
+ ENV['GEM_HOME'] = result[:GEM_HOME]
+ ENV['GEM_PATH'] = result[:GEM_PATH]
+ Gem.clear_paths if defined?(Gem)
+ else
+ raise IncompatibleRubyError.new(result, "The given ruby environment requires #{ruby_string(result)} (versus #{self.class.current_ruby_string})")
+ end
+ end
+
+ end
+end
23 lib/rvm/environment/wrapper.rb
@@ -0,0 +1,23 @@
+module RVM
+ class Environment
+
+ # Generates wrappers with the specified prefix, pointing
+ # to ruby_string.
+ def wrapper(ruby_string, wrapper_prefix, *binaries)
+ rvm(:wrapper, ruby_string, wrapper_prefix, *binaries).successful?
+ end
+
+ # Generates the default wrappers.
+ def default_wrappers(ruby_string, *binaries)
+ wrapper ruby_string, '', *binaries
+ end
+
+ # If available, return the path to the wrapper for
+ # the given executable. Will return ni if the wrapper
+ # is unavailable.
+ def wrapper_path_for(executable)
+ raise NotImplementedError
+ end
+
+ end
+end
31 lib/rvm/errors.rb
@@ -0,0 +1,31 @@
+module RVM
+
+ # Generic error in RVM
+ class Error < StandardError; end
+
+ # Generic error with the shell command output attached.
+ # The RVM::Shell::Result instance is available via +#result+.
+ class ErrorWithResult < Error
+ attr_reader :result
+
+ def initialize(result, message = nil)
+ @result = result
+ super message
+ end
+
+ end
+
+ # Something occurred while processing the command and RVM couldn't parse the results.
+ class IncompleteCommandError < Error; end
+
+ # The given action can't replace the env for the current process.
+ # Typically raised by RVM::Environment#gemset_use when the gemset
+ # is for another, incompatible ruby interpreter.
+ #
+ # Provides access to the output of the shell command via +#result+.
+ class IncompatibleRubyError < ErrorWithResult; end
+
+ # Called when tools.path_identifier is called on a dir with an untrusted rvmrc.
+ class ErrorLoadingRVMRC < Error; end
+
+end
51 lib/rvm/install_command_dumper.rb
@@ -0,0 +1,51 @@
+# Prints out the rvm command (minus rvm install) to install this ruby.
+
+RUBY_NAME = File.basename(ENV['MY_RUBY_HOME'])
+RVM_HOME = ENV['rvm_path']
+
+def ruby?(*names)
+ names.map { |n| n.to_s }.include?(RUBY_NAME.split("-").first)
+end
+
+def quote(value)
+ value = value.to_s.strip
+ value.empty? ? "" : "'#{value.gsub("'", "'\'\'")}'"
+end
+
+def normalize_argument(arg)
+ real_value, arg_value = arg.split("=", 2)
+ if !arg_value.nil?
+ real_value << "=#{quote(arg_value)}"
+ end
+ real_value.gsub("'#{RVM_HOME}", "'\"$rvm_path\"'")
+end
+
+def arguments_for_install
+ if ruby?(:ruby, :ree, :goruby, :tcs)
+ begin
+ require 'rbconfig'
+ require 'shellwords'
+ # Get the full arguments
+ config_args = Shellwords.shellwords(Config::CONFIG['configure_args'].to_s.strip)
+ real_arguments = []
+ config_args.each do |arg|
+ if ruby?(:ree) && arg == "--enable-mbari-api"
+ next
+ elsif arg =~ /^--prefix/
+ next
+ elsif arg =~ /^[^\-]/
+ next
+ else
+ real_arguments << normalize_argument(arg)
+ end
+ end
+ config_args = real_arguments.join(",")
+ return "-C #{quote(config_args)}" unless config_args.strip.empty?
+ rescue LoadError
+ end
+ end
+ return ""
+end
+
+# Finally, print the string to install it.
+puts "rvm install #{RUBY_NAME} #{arguments_for_install.gsub(/''+/, "'")}".strip
27 lib/rvm/shell.rb
@@ -0,0 +1,27 @@
+module RVM
+ # Provides Generic access to a more ruby-like shell interface.
+ # For more details, see AbstractWrapper.
+ module Shell
+
+ require 'rvm/shell/utility'
+ require 'rvm/shell/abstract_wrapper'
+ require 'rvm/shell/single_shot_wrapper'
+
+ # Current unimplemented
+ #require 'rvm/shell/persisting_wrapper'
+ # File missing
+ #require 'rvm/shell/test_wrapper'
+ require 'rvm/shell/result'
+
+ # Returns the default shell wrapper class to use
+ def self.default_wrapper
+ @@default_wrapper ||= SingleShotWrapper
+ end
+
+ # Sets the default shell wrapper class to use.
+ def self.default_wrapper=(wrapper)
+ @@default_wrapper = wrapper
+ end
+
+ end
+end
145 lib/rvm/shell/abstract_wrapper.rb
@@ -0,0 +1,145 @@
+require 'yaml'
+
+module RVM
+ module Shell
+ # Provides the most common functionality expected of a shell wrapper.
+ # Namely, implements general utility methods and tools to extract output
+ # from a given command but doesn't actually run any commands itself,
+ # leaving that up to concrete implementations.
+ #
+ # == Usage
+ #
+ # Commands are run inside of a shell (usually bash) and can either be exectuted in
+ # two situations (each with wrapper methods available) - silently or verbosely.
+ #
+ # Silent commands (via run_silently and run_command) do exactly as
+ # they say - that can modify the environment etc but anything they print (to stdout
+ # or stderr) will be discarded.
+ #
+ # Verbose commands will run the command and then print the command epilog (which
+ # contains the output stastus and the current env in yaml format). This allows us
+ # to not only capture all output but to also return the exit status and environment
+ # variables in a way that makes persisted shell sessions possible.
+ #
+ # Under the hood, #run and run_silently are the preferred ways of invoking commands - if
+ # passed a single command, they'll run it as is (much like system in ruby) but when
+ # given multiple arguments anything after the first will be escaped (e.g. you can
+ # hence pass code etc). #run will also parse the results of this epilog into a usable
+ # RVM::Shell::Result object.
+ #
+ # run_command and run_command_silently do the actual hard work for these behind the scenes,
+ # running a string as the shell command. Hence, these two commands are what must be
+ # implemented in non-abstract wrappers.
+ #
+ # For an example of the shell wrapper functionality in action, see RVM::Environment
+ # which delegates most of the work to a shell wrapper.
+ class AbstractWrapper
+
+ # Used the mark the end of a commands output and the start of the rvm env.
+ COMMAND_EPILOG_START = "---------------RVM-RESULTS-START---------------"
+ # Used to mark the end of the commands epilog.
+ COMMAND_EPILOG_END = "----------------RVM-RESULTS-END----------------"
+ # The location of the shell file with the epilog function definition.
+ WRAPPER_LOCATION = File.expand_path('./shell_wrapper.sh', File.dirname(__FILE__))
+
+ # Defines the shell exectuable.
+ attr_reader :shell_executable
+
+ # Initializes a new shell wrapper, including setting the
+ # default setup block. Implementations must override this method
+ # but must ensure that they call super to perform the expected
+ # standard setup.
+ def initialize(sh = 'bash', &setup_block)
+ setup &setup_block
+ @shell_executable = sh
+ end
+
+ # Defines a setup block to be run when initiating a wrapper session.
+ # Usually used for doing things such as sourcing the rvm file. Please note
+ # that the wrapper file is automatically source.
+ #
+ # The setup block should be automatically run by wrapper implementations.
+ def setup(&blk)
+ @setup_block = blk
+ end
+
+ # Runs the gives command (with optional arguments), returning an
+ # RVM::Shell::Result object, including stdout / stderr streams.
+ # Under the hood, uses run_command to actually process it all.
+ def run(command, *arguments)
+ expanded_command = build_cli_call(command, arguments)
+ status, out, err = run_command(expanded_command)
+ Result.new(expanded_command, status, out, err)
+ end
+
+ # Wrapper around run_command_silently that correctly escapes arguments.
+ # Essentially, #run but using run_command_silently.
+ def run_silently(command, *arguments)
+ run_command_silently build_cli_call(command, arguments)
+ end
+
+ # Given a command, it will execute it in the current wrapper
+ # and once done, will return:
+ # - the hash from the epilog output.
+ # - a string representing stdout.
+ # - a string representing stderr.
+ def run_command(full_command)
+ raise NotImplementedError.new("run_command is only available in concrete implementations")
+ end
+
+ # Like run_command, but doesn't care about output.
+ def run_command_silently(full_command)
+ raise NotImplementedError.new("run_command_silently is only available in concrete implementations")
+ end
+
+ # Returns a given environment variables' value.
+ def [](var_name)
+ run(:true)[var_name]
+ end
+
+ protected
+
+ # When called, will use the current environment to source the wrapper scripts
+ # as well as invoking the current setup block. as defined on initialization / via #setup.
+ def invoke_setup!
+ source_command_wrapper
+ @setup_block.call(self) if @setup_block
+ end
+
+ # Uses run_silently to source the wrapper file.
+ def source_command_wrapper
+ run_silently :source, WRAPPER_LOCATION
+ end
+
+ # Returns a command followed by the call to show the epilog.
+ def wrapped_command(command)
+ "#{command}; __rvm_show_command_epilog"
+ end
+
+ # Wraps a command in a way that it prints no output.
+ def silent_command(command)
+ "{ #{command}; } >/dev/null 2>&1"
+ end
+
+ # Checks whether the given command includes a epilog, marked by
+ # epilog start and end lines.
+ def command_complete?(c)
+ start_index, end_index = c.index(COMMAND_EPILOG_START), c.index(COMMAND_EPILOG_END)
+ start_index && end_index && start_index < end_index
+ end
+
+ # Takes a raw string from a processes STDIO and returns three things:
+ # 1. The actual stdout, minus epilogue.
+ # 2. YAML output of the process results.
+ # 3. Any left over from the STDIO text.
+ def raw_stdout_to_parts(c)
+ raise IncompleteCommandError if !command_complete?(c)
+ before, after = c.split(COMMAND_EPILOG_START, 2)
+ epilog, after = after.split(COMMAND_EPILOG_END, 2)
+ return before, YAML.load(epilog.strip), after
+ end
+
+ include RVM::Shell::Utility
+ end
+ end
+end
26 lib/rvm/shell/calculate_rvm_path.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Calculates a default rvm path
+
+# Check first.
+if [[ -n "$rvm_path" ]]; then
+ echo "$rvm_path"
+ exit
+fi
+
+# Load extra files.
+
+[[ -s ~/.rvmrc ]] && source ~/.rvmrc >/dev/null 2>&1
+[[ -s /etc/.rvmrc ]] && source /etc/rvmrc >/dev/null 2>&1
+
+if [[ -n "$rvm_path" ]]; then
+ echo "$rvm_path"
+elif [[ -d ~/.rvm ]]; then
+ echo "~/.rvm"
+elif [[ -d /usr/local/rvm ]]; then
+ echo "/usr/local/rvm"
+else
+ exit 1
+fi
+
+exit 0
42 lib/rvm/shell/result.rb
@@ -0,0 +1,42 @@
+module RVM
+ module Shell
+ # Represents the output of a shell command.
+ # This includes the exit status (and the helpful #successful? method)
+ # as well accessors for the command and stdout / stderr.
+ class Result
+
+ attr_reader :command, :stdout, :stderr, :raw_status
+
+ # Creates a new result object with the given details.
+ def initialize(command, status, stdout, stderr)
+ @command = command.dup.freeze
+ @raw_status = status
+ @environment = (@raw_status ? (@raw_status["environment"] || {}) : {})
+ @successful = (exit_status == 0)
+ @stdout = stdout.freeze
+ @stderr = stderr.freeze
+ end
+
+ # Returns the hash of the environment.
+ def env
+ @environment
+ end
+
+ # Whether or not the command had a successful exit status.
+ def successful?
+ @successful
+ end
+
+ # Returns a value from the outputs environment.
+ def [](key)
+ env[key.to_s]
+ end
+
+ # Returns the exit status for the program
+ def exit_status
+ @exit_status ||= (Integer(@raw_status["exit_status"]) rescue 1)
+ end
+
+ end
+ end
+end
9 lib/rvm/shell/shell_wrapper.sh
@@ -0,0 +1,9 @@
+# Prints an epilog to a shell command.
+__rvm_show_command_epilog() {
+ local _code="$?"
+ echo "---------------RVM-RESULTS-START---------------"
+ ruby -rrubygems -ryaml -e \
+ "puts YAML.dump({'environment' => ENV.to_hash, 'exit_status' => '${_code}'})"
+ echo "----------------RVM-RESULTS-END----------------"
+}
+
56 lib/rvm/shell/single_shot_wrapper.rb
@@ -0,0 +1,56 @@
+require 'open3'
+
+module RVM
+ module Shell
+ # Implementation of the abstract wrapper class that opens a new
+ # instance of bash when a command is run, only keeping it around
+ # for the lifetime of the command. Possibly inefficient but for
+ # the moment simplest and hence default implementation.
+ class SingleShotWrapper < AbstractWrapper
+
+ attr_accessor :current
+
+ # Runs a given command in the current shell.
+ # Defaults the command to true if empty.
+ def run_command(command)
+ command = "true" if command.to_s.strip.empty?
+ with_shell_instance do
+ stdin.puts wrapped_command(command)
+ stdin.close
+ out, err = stdout.read, stderr.read
+ out, status, _ = raw_stdout_to_parts(out)
+ return status, out, err
+ end
+ end
+
+ # Runs a command, ensuring no output is collected.
+ def run_command_silently(command)
+ with_shell_instance do
+ stdin.puts silent_command(command)
+ end
+ end
+
+ protected
+
+ # yields stdio, stderr and stdin for a shell instance.
+ # If there isn't a current shell instance, it will create a new one.
+ # In said scenario, it will also cleanup once it is done.
+ def with_shell_instance(&blk)
+ no_current = @current.nil?
+ if no_current
+ @current = Open3.popen3(self.shell_executable)
+ invoke_setup!
+ end
+ yield
+ ensure
+ @current = nil if no_current
+ end
+
+ # Direct access to each of the named descriptors
+ def stdin; @current[0]; end
+ def stdout; @current[1]; end
+ def stderr; @current[2]; end
+
+ end
+ end
+end
37 lib/rvm/shell/utility.rb
@@ -0,0 +1,37 @@
+module RVM
+ module Shell
+ module Utility
+
+ public
+
+ # Takes an array / number of arguments and converts
+ # them to a string useable for passing into a shell call.
+ def escape_arguments(*args)
+ return '' if args.nil?
+ args.flatten.map { |a| escape_argument(a.to_s) }.join(" ")
+ end
+
+ # Given a string, converts to the escaped format. This ensures
+ # that things such as variables aren't evaluated into strings
+ # and everything else is setup as expected.
+ def escape_argument(s)
+ return "''" if s.empty?
+ s.scan(/('+|[^']+)/).map do |section|
+ section = section.first
+ if section[0] == ?'
+ "\\'" * section.length
+ else
+ "'#{section}'"
+ end
+ end.join
+ end
+
+ # From a command, will build up a runnable command. If args isn't provided,
+ # it will escape arguments.
+ def build_cli_call(command, args = nil)
+ "#{command} #{escape_arguments(args)}".strip
+ end
+
+ end
+ end
+end
3  lib/rvm/version.rb
@@ -0,0 +1,3 @@
+module RVM
+ Version = "1.11.3.1"
+end
25 rvm.gemspec
@@ -0,0 +1,25 @@
+lib = File.expand_path('../lib/', __FILE__)
+
+$:.unshift lib unless $:.include?(lib)
+
+require 'rvm/version'
+require 'yaml'
+
+Gem::Specification.new do |spec|
+ spec.name = 'rvm'
+ spec.version = ::RVM::Version
+ spec.platform = Gem::Platform::RUBY
+ spec.authors = ['Wayne E. Seguin', '"Michał Papis, ']
+ spec.email = ['wayneeseguin@gmail.com','mpapis@gmail.com']
+ spec.homepage = 'https://rvm.beginrescueend.com/'
+ spec.summary = 'RVM Ruby Gem Library'
+ spec.description = 'RVM ~ Ruby Environment Manager ~ Ruby Gem Library.'
+
+ spec.add_development_dependency 'rake'
+ spec.add_development_dependency 'minitest'
+
+ spec.require_path = 'lib'
+ spec.files = YAML.load_file('Manifest.yml')
+ spec.test_files = Dir.glob('spec/**/*.rb')
+end
+
2  spec/spec_helper.rb
@@ -0,0 +1,2 @@
+require 'minitest'
+require 'minitest/spec'
Please sign in to comment.
Something went wrong with that request. Please try again.