Permalink
Browse files

Implement rvm snapshot {save,load}

  • Loading branch information...
1 parent f3f787f commit 8813db866e0e457f7a45dd504e354c9d2fabac66 @Sutto Sutto committed Jul 21, 2010
Showing with 274 additions and 24 deletions.
  1. +5 −0 README
  2. +51 −0 lib/rvm/install_command_dumper.rb
  3. +10 −14 scripts/cli
  4. +14 −7 scripts/list
  5. +8 −0 scripts/manage
  6. +183 −0 scripts/snapshot
  7. +3 −3 scripts/utility
View
@@ -68,6 +68,9 @@ Action
specified ruby and gemset combination. Used under the hood for
passenger support and the like.
+ cleanup - Lets you remove stale source folders / archives and other miscellaneous
+ data associated with rvm.
+
ruby - runs a named ruby file against specified and/or all rubies
gem - runs a gem command using selected ruby's 'gem'
rake - runs a rake task against specified and/or all rubies
@@ -87,6 +90,8 @@ Action
http://rvm.beginrescueend.com/packages/
notes - Display notes, with operating system specifics.
+ snapshot - Let's your backup / restore an rvm installation in a lightweight manner.
+
Implementation
* ruby - MRI/YARV Ruby (The Gold Standard) {1.8.6,1.8.7,1.9.1,1.9.2...}
@@ -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, :mput, :ree)
+ 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
View
@@ -10,6 +10,12 @@ __rvm_usage() { cat "${rvm_path:-$HOME/.rvm}/README" | ${PAGER:-less} ; }
#fi
#}
+__rvm_run_script() {
+ local rvm_script_name="${1:-"$rvm_action"}"
+ eval "$rvm_scripts_path/$rvm_script_name $rvm_ruby_args"
+ return $?
+}
+
__rvm_parse_args() {
# TODO:
@@ -125,7 +131,7 @@ __rvm_parse_args() {
rvm_parse_break=1
;;
- exec|cleanup|tools|disk-usage)
+ exec|cleanup|tools|disk-usage|snapshot)
rvm_action="$rvm_token"
rvm_ruby_args="$(__rvm_quote_args "$@")"
rvm_parse_break=1
@@ -530,18 +536,8 @@ rvm() {
unset old_rvm_ruby_string
;;
- cleanup)
- eval "$rvm_scripts_path/cleanup $rvm_ruby_args"
- result=$?
- ;;
-
- tools)
- eval "$rvm_scripts_path/tools $rvm_ruby_args"
- result=$?
- ;;
-
- disk-usage)
- eval "$rvm_scripts_path/disk-usage $rvm_ruby_args"
+ cleanup|tools|snapshot|disk-usage)
+ __rvm_run_script "$rvm_action"
result=$?
;;
@@ -620,7 +616,7 @@ rvm() {
if [[ ! -z "$rvm_reload_flag" ]] ; then
source "$rvm_scripts_path/rvm"
# Note: Not using builtin on purpose. Done so we can trigger a reload the rvmrc.
- cd .
+ __rvm_project_rvmrc
fi
if [[ ! -z "$rvm_trace_flag" ]] ; then set +x ; unset rvm_trace_flag ; fi
View
@@ -5,17 +5,19 @@ if [[ "$rvm_trace_flag" -eq 2 ]] ; then set -x ; export rvm_trace_flag ; fi
source "$rvm_scripts_path/utility"
list_gemsets() {
- if [[ "$(echo $rvm_ruby_args | awk '{print $2}')" = "strings" ]]; then
+ if [[ "$1" = "strings" ]]; then
list_gemset_strings
return 0
fi
echo
current_ruby="$(__rvm_environment_identifier)"
+ local all_rubies="$(list_strings)"
printf "rvm gemsets\n"
for version in $(\ls $rvm_gems_path/ 2> /dev/null | awk '/[a-z]*-.*/ {print $NF}') ; do
ruby_version_name="$(echo "$version" | awk -F"$rvm_gemset_separator" '{print $1}')"
+ [[ "$all_rubies" != *"$ruby_version_name"* ]] && continue
if [[ -n "$(echo $version | awk '/^jruby-/')" ]] ; then
string="[ $($rvm_rubies_path/$ruby_version_name/bin/ruby -v | awk '{print $NF}' | sed -e 's/\[//' -e 's/\]//') ]"
elif [[ -n "$(echo $version | awk '/^maglev-|^macruby-/')" ]] ; then
@@ -48,8 +50,7 @@ list_gemsets() {
}
list_default() {
- strings="$(echo $rvm_ruby_args | awk '{print $2}')"
- if [[ "$strings" = "string" ]] ; then
+ if [[ "$1" = "string" ]] ; then
$rvm_scripts_path/alias show default 2>/dev/null | awk -F"$rvm_gemset_separator" '{print $1}' | xargs basename
else
if [[ -L "$rvm_rubies_path/default" ]]; then
@@ -80,7 +81,12 @@ list_strings() {
# This is meant to be used with scripting.
list_gemset_strings() {
- \ls $rvm_gems_path/ 2>/dev/null | xargs -- basename | grep -v '^\(@\|doc$\|cache$\|system$\)' | sort
+ local all_rubies="$(list_strings)"
+ for gemset in $(\ls $rvm_gems_path/ 2>/dev/null | xargs -- basename | grep -v '^\(@\|doc$\|cache$\|system$\)' | sort); do
+ local ruby_name="$(echo "$gemset" | awk -F$rvm_gemset_separator '{print $1}')"
+ [[ "$all_rubies" != *"$ruby_name"* ]] && continue
+ echo "$gemset"
+ done
}
# This is meant to be used with scripting.
@@ -137,18 +143,19 @@ list_rubies() {
# List all rvm installed rubies, default ruby and system ruby.
# Display the rubies, indicate their architecture and indicate which is currently used.
# This is not meant to be used with scripting. This is for interactive mode usage only.
-action="$(echo "$1" | awk '{print $1}')"
+action="$1"
+[[ $# -gt 0 ]] && shift
if [[ "known" = "$action" ]] ; then
list_known
elif [[ "known_strings" = "$action" ]] ; then
list_known_strings
elif [[ "gemsets" = "$action" ]] ; then
- list_gemsets
+ list_gemsets "$@"
elif [[ "default" = "$action" ]] ; then
list_default
elif [[ -z "$action" ]] || [[ "rubies" = "$action" ]] ; then
- list_rubies
+ list_rubies "$@"
elif [[ "strings" = "$action" ]] ; then
list_strings
elif [[ "ruby_svn_tags" = "$action" ]] ; then
View
@@ -1153,6 +1153,10 @@ __rvm_manage_rubies() {
if [[ -n "$rubies_string" ]] ;then
for rvm_ruby_string in $(echo "$rubies_string" | tr ',' ' ') ; do
eval "__rvm_${rvm_action}_ruby"
+ result="$?"
+ if [[ "$result" -gt 0 && "$manage_result" = 0 ]]; then
+ manage_result="$result"
+ fi
__rvm_unset_ruby_variables
done
else # all
@@ -1162,6 +1166,10 @@ __rvm_manage_rubies() {
if [[ -x "$bin_line" ]] ; then
rvm_ruby_string="$(dirname "$bin_line" | xargs dirname | xargs basename)"
eval "__rvm_${rvm_action}_ruby"
+ result="$?"
+ if [[ "$result" -gt 0 && "$manage_result" = 0 ]]; then
+ manage_result="$result"
+ fi
__rvm_unset_ruby_variables
fi
done < <(\ls $rvm_rubies_path/*/bin/ruby 2> /dev/null)
View
@@ -0,0 +1,183 @@
+#!/usr/bin/env bash
+
+unset GREP_COLOR
+unset GREP_OPTIONS
+
+source "$rvm_scripts_path/base"
+
+__error_on_result() {
+ if [[ "$1" -gt 0 ]]; then
+ $rvm_scripts_path/log "fail" "$2 - Aborting now."
+ return 0
+ else
+ return 1
+ fi
+}
+
+snapshot_save() {
+
+ if [[ -z "$1" ]]; then
+ echo "Usage: rvm snapshot save name" >&2
+ echo "Saves a snapshot to <name>.tar.gz in the current directory." >&2
+ return 1
+ fi
+
+ # Create the temporary directory.
+ local snapshot_temp_path="$rvm_tmp_path/$$-snapshot"
+ rm -rf "$snapshot_temp_path"
+ mkdir -p "$snapshot_temp_path"
+
+ $rvm_scripts_path/log "info" "Backing up a list of aliases"
+ cp "$rvm_config_path/alias" "$snapshot_temp_path/"
+
+ $rvm_scripts_path/log "info" "Backing up your user preferences"
+ cp "$rvm_config_path/user" "$snapshot_temp_path/"
+
+ $rvm_scripts_path/log "info" "Backing up your installed packages"
+ cat "$rvm_config_path/packages" | sed -e 's/-//' -e 's/^lib//' | awk -F= '{print $1}' | sort | uniq > "$snapshot_temp_path/packages"
+
+ $rvm_scripts_path/log "info" "Backing up all of your gemsets"
+ mkdir -p "$snapshot_temp_path/gems"
+ __rvm_pushpop "$snapshot_temp_path/gems"
+ for snapshot_gemset in $($rvm_scripts_path/list gemsets strings) ; do
+ __rvm_become "$snapshot_gemset"
+ result="$?"
+ __error_on_result "$result" "Error becoming ruby $snapshot_gemset" && return "$result"
+ $rvm_scripts_path/gemsets export "${snapshot_gemset}.gems" >/dev/null
+ result="$?"
+ __error_on_result "$result" "Error exporting gemset contents for $snapshot_gemset" && return "$result"
+ mkdir -p "./$snapshot_gemset/"
+ [[ -d "$GEM_HOME/cache/" ]] && cp -R "$GEM_HOME/cache/" "./$snapshot_gemset/"
+ done; unset snapshot_gemset
+ __rvm_pushpop
+
+ $rvm_scripts_path/log "info" "Backing up all of your installed rubies"
+ echo '#!/usr/bin/env bash -e' > "$snapshot_temp_path/install-rubies.sh"
+ echo "source \"\$rvm_scripts_path/rvm\" || true" >> "$snapshot_temp_path/install-rubies.sh"
+ local snapshot_ruby_name_file="$rvm_tmp_path/$$-rubies"
+ local snapshot_alias_name_file="$rvm_tmp_path/$$-aliases"
+ local snapshot_installable_file="$rvm_tmp_path/$$-installable"
+
+ $rvm_scripts_path/alias list | awk -F ' => ' '{print $1}' | sort | uniq 2>/dev/null > "$snapshot_alias_name_file"
+ $rvm_scripts_path/list strings | tr ' ' '\n' | sort | uniq > "$snapshot_ruby_name_file"
+ comm -2 -3 "$snapshot_ruby_name_file" "$snapshot_alias_name_file" > "$snapshot_installable_file"
+ rm -rf "$snapshot_ruby_name_file" "$snapshot_alias_name_file"
+
+ local snapshot_primary_ruby="$(cat "$snapshot_installable_file" | grep '^\(ree\|ruby-1.8.7\)' | grep -v '-head$' | sort -r | head -n1)"
+ local snapshot_ruby_order="$snapshot_primary_ruby $(cat "$snapshot_installable_file" | grep -v "$snapshot_primary_ruby")"
+ for snapshot_ruby_name in $snapshot_ruby_order ; do
+ __rvm_become "$snapshot_ruby_name"
+ ruby "$rvm_path/lib/rvm/install_command_dumper.rb" >> "$snapshot_temp_path/install-rubies.sh"
+ done; unset snapshot_ruby_name snapshot_primary_ruby
+
+ rm -rf "$snapshot_installable_file"
+
+ $rvm_scripts_path/log "info" "Compressing snapshotting"
+ local destination_path="$PWD"
+ __rvm_pushpop "$snapshot_temp_path"
+ rm -rf "$destination_path/$1.tar.gz"
+ tar czf "$destination_path/$1.tar.gz" .
+ result="$?"
+ __error_on_result "$result" "Error creating archive $destination_path/$1.tar.gz" && return "$result"
+ __rvm_pushpop
+
+ $rvm_scripts_path/log "info" "Cleaning up"
+ rm -rf "$snapshot_temp_path"
+
+ $rvm_scripts_path/log "info" "Snapshot complete"
+
+}
+
+snapshot_load() {
+ if [[ -z "$1" ]]; then
+ echo "Usage: rvm snapshot load name" >&2
+ echo "Loads a snapshot from <name>.tar.gz in the current directory." >&2
+ return 1
+ fi
+
+ local snapshot_archive="$PWD/$(echo "$1" | sed 's/.tar.gz$//').tar.gz"
+
+ if ! [[ -s "$snapshot_archive" ]]; then
+ echo "The provides snapshot '$(basename "$snapshot_archive")' doesn't exist." >&2
+ return 1
+ fi
+
+ local snapshot_temp_path="$rvm_tmp_path/$$-snapshot"
+
+ rm -rf "$snapshot_temp_path"
+ mkdir -p "$snapshot_temp_path"
+
+ $rvm_scripts_path/log "info" "Extracting snapshot"
+ __rvm_pushpop "$snapshot_temp_path"
+ tar xzf "$snapshot_archive"
+ result="$?"
+ __error_on_result "$result" "Error extracting the archive '$snapshot_archive'" && return "$result"
+ __rvm_pushpop
+
+ $rvm_scripts_path/log "info" "Restoring user settings"
+ cp -f "$snapshot_temp_path/user" "$rvm_config_path/user"
+
+ $rvm_scripts_path/log "info" "Installing rvm-managed packages"
+ for snapshot_package in $(cat "$snapshot_temp_path/packages"); do
+ $rvm_scripts_path/package install "$snapshot_package"
+ result="$?"
+ __error_on_result "$result" "Error installing package '$snapshot_package'" && return "$result"
+ done; unset snapshot_package
+
+ $rvm_scripts_path/log "info" "Installing rubies"
+ chmod +x "$snapshot_temp_path/install-rubies.sh"
+ $snapshot_temp_path/install-rubies.sh
+ result="$?"
+ __error_on_result "$result" "Error importing rubies." && return "$result"
+
+ export rvm_create_flag=1
+ $rvm_scripts_path/log "info" "Setting up gemsets"
+ __rvm_pushpop "$snapshot_temp_path/gems"
+ for snapshot_gemset in $(\ls | grep '\.gems$' | sed 's/.gems$//'); do
+ __rvm_become "$snapshot_gemset"
+ result="$?"
+ __error_on_result "$result" "Error becoming '$snapshot_gemset'" && return "$result"
+ mkdir -p "$GEM_HOME/cache/"
+ cp -Rf "$snapshot_gemset/" "$GEM_HOME/cache/"
+ result="$?"
+ __error_on_result "$result" "Error copying across cache for $snapshot_gemset" && return "$result"
+ $rvm_scripts_path/gemsets import "$snapshot_gemset" >/dev/null 2>&1
+ result="$?"
+ __error_on_result "$result" "Error importing gemset for $snapshot_gemset" && return "$result"
+ done; unset snapshot_gemset
+ __rvm_pushpop
+
+ $rvm_scripts_path/log "info" "Restoring aliases"
+ while read -r package_info; do
+ local alias_name="$(echo "$package_info" | awk -F= '{print $1}')"
+ local alias_ruby="$(echo "$package_info" | awk -F= '{print $2}')"
+ $rvm_scripts_path/alias create "$alias_name" "$alias_ruby"
+ if [[ "$alias_name" = "default" ]]; then
+ (source "$rvm_scripts_path/rvm" && rvm use "$alias_ruby" --default) >/dev/null 2>&1
+ result="$?"
+ __error_on_result "$result" "Error setting default to $alias_ruby" && return "$result"
+ fi
+ done < "$snapshot_temp_path/alias"
+ unset package_info
+
+ $rvm_scripts_path/log "info" "Cleaning up load process"
+ rm -rf "$snapshot_temp_path"
+
+ $rvm_scripts_path/log "info" "Loaded snapshot from $(basename "$snapshot_archive")"
+}
+
+snapshot_usage() {
+ echo "Usage: rvm snapshot {save,load} file" >&2
+ return 1
+}
+
+action="$1"
+[[ "$#" -gt 0 ]] && shift
+
+case "$action" in
+ save) snapshot_save "$@" ;;
+ load) snapshot_load "$@" ;;
+ *) snapshot_usage ;;
+esac
+
+exit $?
Oops, something went wrong. Retry.

0 comments on commit 8813db8

Please sign in to comment.