Skip to content

Commit

Permalink
Initial Ruby API, written by Darcy!!!
Browse files Browse the repository at this point in the history
  • Loading branch information
wayneeseguin committed Jul 8, 2010
1 parent 0d2e294 commit 567ef6b
Show file tree
Hide file tree
Showing 27 changed files with 1,539 additions and 439 deletions.
157 changes: 156 additions & 1 deletion lib/rvm.rb
Original file line number Diff line number Diff line change
@@ -1 +1,156 @@
Dir.glob("#{File.expand_path(File.dirname(__FILE__))}/rvm/*.rb").each { |file| require file }
# == 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 http://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'

autoload :Shell, 'rvm/shell'
autoload :Environment, 'rvm/environment'
autoload :Version, '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
#
# 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
62 changes: 62 additions & 0 deletions lib/rvm/environment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
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).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

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.
def expanded_name
@expanded_name ||= run(:__rvm_environment_identifier).stdout.strip
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, File.expand_path("~/.rvm"), 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 changes: 69 additions & 0 deletions lib/rvm/environment/alias.rb
Original file line number Diff line number Diff line change
@@ -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 changes: 54 additions & 0 deletions lib/rvm/environment/cleanup.rb
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 567ef6b

Please sign in to comment.