Skip to content
This repository
Browse code

Implement rvm snapshot {save,load}

  • Loading branch information...
commit 8813db866e0e457f7a45dd504e354c9d2fabac66 1 parent f3f787f
Darcy Laycock authored July 21, 2010
5  README
@@ -68,6 +68,9 @@ Action
68 68
               specified ruby and gemset combination. Used under the hood for
69 69
               passenger support and the like.
70 70
 
  71
+  cleanup   - Lets you remove stale source folders / archives and other miscellaneous
  72
+              data associated with rvm.
  73
+
71 74
   ruby      - runs a named ruby file against specified and/or all rubies
72 75
   gem       - runs a gem command using selected ruby's 'gem'
73 76
   rake      - runs a rake task against specified and/or all rubies
@@ -87,6 +90,8 @@ Action
87 90
               http://rvm.beginrescueend.com/packages/
88 91
   notes     - Display notes, with operating system specifics.
89 92
 
  93
+  snapshot  - Let's your backup / restore an rvm installation in a lightweight manner.
  94
+
90 95
 Implementation
91 96
 
92 97
   * ruby    - MRI/YARV Ruby (The Gold Standard) {1.8.6,1.8.7,1.9.1,1.9.2...}
51  lib/rvm/install_command_dumper.rb
... ...
@@ -0,0 +1,51 @@
  1
+# Prints out the rvm command (minus rvm install) to install this ruby.
  2
+
  3
+RUBY_NAME = File.basename(ENV['MY_RUBY_HOME'])
  4
+RVM_HOME  = ENV['rvm_path']
  5
+
  6
+def ruby?(*names)
  7
+  names.map { |n| n.to_s }.include?(RUBY_NAME.split("-").first)
  8
+end
  9
+
  10
+def quote(value)
  11
+  value = value.to_s.strip
  12
+  value.empty? ? "" : "'#{value.gsub("'", "'\'\'")}'"
  13
+end
  14
+
  15
+def normalize_argument(arg)
  16
+  real_value, arg_value = arg.split("=", 2)
  17
+  if !arg_value.nil?
  18
+    real_value << "=#{quote(arg_value)}"
  19
+  end
  20
+  real_value.gsub("'#{RVM_HOME}", "'\"$rvm_path\"'")
  21
+end
  22
+
  23
+def arguments_for_install
  24
+  if ruby?(:ruby, :mput, :ree)
  25
+    begin
  26
+      require 'rbconfig'
  27
+      require 'shellwords'
  28
+      # Get the full arguments
  29
+      config_args = Shellwords.shellwords(Config::CONFIG['configure_args'].to_s.strip)
  30
+      real_arguments = []
  31
+      config_args.each do |arg|
  32
+        if ruby?(:ree) && arg == "--enable-mbari-api"
  33
+          next
  34
+        elsif arg =~ /^--prefix/
  35
+          next
  36
+        elsif arg =~ /^[^\-]/
  37
+          next
  38
+        else
  39
+          real_arguments << normalize_argument(arg)
  40
+        end
  41
+      end
  42
+      config_args = real_arguments.join(",")
  43
+      return "-C #{quote(config_args)}" unless config_args.strip.empty?
  44
+    rescue LoadError
  45
+    end
  46
+  end
  47
+  return ""
  48
+end
  49
+
  50
+# Finally, print the string to install it.
  51
+puts "rvm install #{RUBY_NAME} #{arguments_for_install.gsub(/''+/, "'")}".strip
24  scripts/cli
@@ -10,6 +10,12 @@ __rvm_usage() { cat "${rvm_path:-$HOME/.rvm}/README" | ${PAGER:-less} ; }
10 10
   #fi
11 11
 #}
12 12
 
  13
+__rvm_run_script() {
  14
+  local rvm_script_name="${1:-"$rvm_action"}"
  15
+  eval "$rvm_scripts_path/$rvm_script_name $rvm_ruby_args"
  16
+  return $?
  17
+}
  18
+
13 19
 __rvm_parse_args() {
14 20
 
15 21
   # TODO:
@@ -125,7 +131,7 @@ __rvm_parse_args() {
125 131
         rvm_parse_break=1
126 132
       ;;
127 133
 
128  
-      exec|cleanup|tools|disk-usage)
  134
+      exec|cleanup|tools|disk-usage|snapshot)
129 135
         rvm_action="$rvm_token"
130 136
         rvm_ruby_args="$(__rvm_quote_args "$@")"
131 137
         rvm_parse_break=1
@@ -530,18 +536,8 @@ rvm() {
530 536
       unset old_rvm_ruby_string
531 537
     ;;
532 538
 
533  
-    cleanup)
534  
-      eval "$rvm_scripts_path/cleanup $rvm_ruby_args"
535  
-      result=$?
536  
-    ;;
537  
-
538  
-    tools)
539  
-      eval "$rvm_scripts_path/tools $rvm_ruby_args"
540  
-      result=$?
541  
-    ;;
542  
-
543  
-    disk-usage)
544  
-      eval "$rvm_scripts_path/disk-usage $rvm_ruby_args"
  539
+    cleanup|tools|snapshot|disk-usage)
  540
+      __rvm_run_script "$rvm_action"
545 541
       result=$?
546 542
     ;;
547 543
 
@@ -620,7 +616,7 @@ rvm() {
620 616
   if [[ ! -z "$rvm_reload_flag" ]] ; then
621 617
     source "$rvm_scripts_path/rvm"
622 618
     # Note: Not using builtin on purpose. Done so we can trigger a reload the rvmrc.
623  
-    cd .
  619
+    __rvm_project_rvmrc
624 620
   fi
625 621
 
626 622
   if [[ ! -z "$rvm_trace_flag" ]] ; then set +x ; unset rvm_trace_flag ; fi
21  scripts/list
@@ -5,17 +5,19 @@ if [[ "$rvm_trace_flag" -eq 2 ]] ; then set -x ; export rvm_trace_flag ; fi
5 5
 source "$rvm_scripts_path/utility"
6 6
 
7 7
 list_gemsets() {
8  
-  if [[ "$(echo $rvm_ruby_args | awk '{print $2}')" = "strings" ]]; then
  8
+  if [[ "$1" = "strings" ]]; then
9 9
     list_gemset_strings
10 10
     return 0
11 11
   fi
12 12
   echo
13 13
 
14 14
   current_ruby="$(__rvm_environment_identifier)"
  15
+  local all_rubies="$(list_strings)"
15 16
 
16 17
   printf "rvm gemsets\n"
17 18
   for version in $(\ls $rvm_gems_path/ 2> /dev/null | awk '/[a-z]*-.*/ {print $NF}') ; do
18 19
     ruby_version_name="$(echo "$version" | awk -F"$rvm_gemset_separator" '{print $1}')"
  20
+    [[ "$all_rubies" != *"$ruby_version_name"* ]] && continue
19 21
     if [[ -n "$(echo $version | awk '/^jruby-/')" ]] ; then
20 22
       string="[ $($rvm_rubies_path/$ruby_version_name/bin/ruby -v | awk '{print $NF}' | sed -e 's/\[//' -e 's/\]//') ]"
21 23
     elif [[ -n "$(echo $version | awk '/^maglev-|^macruby-/')" ]] ; then
@@ -48,8 +50,7 @@ list_gemsets() {
48 50
 }
49 51
 
50 52
 list_default() {
51  
-  strings="$(echo $rvm_ruby_args | awk '{print $2}')"
52  
-  if [[ "$strings" = "string" ]] ; then
  53
+  if [[ "$1" = "string" ]] ; then
53 54
     $rvm_scripts_path/alias show default 2>/dev/null | awk -F"$rvm_gemset_separator" '{print $1}' | xargs basename
54 55
   else
55 56
     if [[ -L "$rvm_rubies_path/default" ]]; then
@@ -80,7 +81,12 @@ list_strings() {
80 81
 
81 82
 # This is meant to be used with scripting.
82 83
 list_gemset_strings() {
83  
-  \ls $rvm_gems_path/ 2>/dev/null | xargs -- basename | grep -v '^\(@\|doc$\|cache$\|system$\)' | sort
  84
+  local all_rubies="$(list_strings)"
  85
+  for gemset in $(\ls $rvm_gems_path/ 2>/dev/null | xargs -- basename | grep -v '^\(@\|doc$\|cache$\|system$\)' | sort); do
  86
+    local ruby_name="$(echo "$gemset" | awk -F$rvm_gemset_separator '{print $1}')"
  87
+    [[ "$all_rubies" != *"$ruby_name"* ]] && continue
  88
+    echo "$gemset"
  89
+  done
84 90
 }
85 91
 
86 92
 # This is meant to be used with scripting.
@@ -137,18 +143,19 @@ list_rubies() {
137 143
 # List all rvm installed rubies, default ruby and system ruby.
138 144
 # Display the rubies, indicate their architecture and indicate which is currently used.
139 145
 # This is not meant to be used with scripting. This is for interactive mode usage only.
140  
-action="$(echo "$1" | awk '{print $1}')"
  146
+action="$1"
  147
+[[ $# -gt 0 ]] && shift
141 148
 
142 149
 if [[ "known" = "$action" ]] ; then
143 150
   list_known
144 151
 elif [[ "known_strings" = "$action" ]] ; then
145 152
   list_known_strings
146 153
 elif [[ "gemsets" = "$action" ]] ; then
147  
-  list_gemsets
  154
+  list_gemsets "$@"
148 155
 elif [[ "default" = "$action" ]] ; then
149 156
   list_default
150 157
 elif [[ -z "$action" ]] || [[ "rubies" = "$action" ]] ; then
151  
-  list_rubies
  158
+  list_rubies "$@"
152 159
 elif [[ "strings" = "$action" ]] ; then
153 160
   list_strings
154 161
 elif [[ "ruby_svn_tags" = "$action" ]] ; then
8  scripts/manage
@@ -1153,6 +1153,10 @@ __rvm_manage_rubies() {
1153 1153
   if [[ -n "$rubies_string" ]] ;then
1154 1154
     for rvm_ruby_string in $(echo "$rubies_string" | tr ',' ' ') ; do
1155 1155
       eval "__rvm_${rvm_action}_ruby"
  1156
+      result="$?"
  1157
+      if [[ "$result" -gt 0 && "$manage_result" = 0 ]]; then
  1158
+        manage_result="$result"
  1159
+      fi
1156 1160
       __rvm_unset_ruby_variables
1157 1161
     done
1158 1162
   else # all
@@ -1162,6 +1166,10 @@ __rvm_manage_rubies() {
1162 1166
         if [[ -x "$bin_line" ]] ; then
1163 1167
           rvm_ruby_string="$(dirname "$bin_line" | xargs dirname | xargs basename)"
1164 1168
           eval "__rvm_${rvm_action}_ruby"
  1169
+          result="$?"
  1170
+          if [[ "$result" -gt 0 && "$manage_result" = 0 ]]; then
  1171
+            manage_result="$result"
  1172
+          fi
1165 1173
           __rvm_unset_ruby_variables
1166 1174
         fi
1167 1175
       done < <(\ls $rvm_rubies_path/*/bin/ruby 2> /dev/null)
183  scripts/snapshot
... ...
@@ -0,0 +1,183 @@
  1
+#!/usr/bin/env bash
  2
+
  3
+unset GREP_COLOR
  4
+unset GREP_OPTIONS
  5
+
  6
+source "$rvm_scripts_path/base"
  7
+
  8
+__error_on_result() {
  9
+  if [[ "$1" -gt 0 ]]; then
  10
+    $rvm_scripts_path/log "fail" "$2 - Aborting now."
  11
+    return 0
  12
+  else
  13
+    return 1
  14
+  fi
  15
+}
  16
+
  17
+snapshot_save() {
  18
+
  19
+  if [[ -z "$1" ]]; then
  20
+    echo "Usage: rvm snapshot save name" >&2
  21
+    echo "Saves a snapshot to <name>.tar.gz in the current directory." >&2
  22
+    return 1
  23
+  fi
  24
+
  25
+  # Create the temporary directory.
  26
+  local snapshot_temp_path="$rvm_tmp_path/$$-snapshot"
  27
+  rm -rf "$snapshot_temp_path"
  28
+  mkdir -p "$snapshot_temp_path"
  29
+
  30
+  $rvm_scripts_path/log "info" "Backing up a list of aliases"
  31
+  cp "$rvm_config_path/alias" "$snapshot_temp_path/"
  32
+
  33
+  $rvm_scripts_path/log "info" "Backing up your user preferences"
  34
+  cp "$rvm_config_path/user" "$snapshot_temp_path/"
  35
+
  36
+  $rvm_scripts_path/log "info" "Backing up your installed packages"
  37
+  cat "$rvm_config_path/packages" | sed -e 's/-//' -e 's/^lib//' | awk -F= '{print $1}' | sort | uniq > "$snapshot_temp_path/packages"
  38
+
  39
+  $rvm_scripts_path/log "info" "Backing up all of your gemsets"
  40
+  mkdir -p "$snapshot_temp_path/gems"
  41
+  __rvm_pushpop "$snapshot_temp_path/gems"
  42
+  for snapshot_gemset in $($rvm_scripts_path/list gemsets strings) ; do
  43
+    __rvm_become "$snapshot_gemset"
  44
+    result="$?"
  45
+    __error_on_result "$result" "Error becoming ruby $snapshot_gemset" && return "$result"
  46
+    $rvm_scripts_path/gemsets export "${snapshot_gemset}.gems" >/dev/null
  47
+    result="$?"
  48
+    __error_on_result "$result" "Error exporting gemset contents for $snapshot_gemset" && return "$result"
  49
+    mkdir -p "./$snapshot_gemset/"
  50
+    [[ -d "$GEM_HOME/cache/" ]] && cp -R "$GEM_HOME/cache/" "./$snapshot_gemset/"
  51
+  done; unset snapshot_gemset
  52
+  __rvm_pushpop
  53
+
  54
+  $rvm_scripts_path/log "info" "Backing up all of your installed rubies"
  55
+  echo '#!/usr/bin/env bash -e' > "$snapshot_temp_path/install-rubies.sh"
  56
+  echo "source \"\$rvm_scripts_path/rvm\" || true" >> "$snapshot_temp_path/install-rubies.sh"
  57
+  local snapshot_ruby_name_file="$rvm_tmp_path/$$-rubies"
  58
+  local snapshot_alias_name_file="$rvm_tmp_path/$$-aliases"
  59
+  local snapshot_installable_file="$rvm_tmp_path/$$-installable"
  60
+  
  61
+  $rvm_scripts_path/alias list | awk -F ' => ' '{print $1}' | sort | uniq 2>/dev/null > "$snapshot_alias_name_file"
  62
+  $rvm_scripts_path/list strings | tr ' ' '\n' | sort | uniq > "$snapshot_ruby_name_file"  
  63
+  comm -2 -3 "$snapshot_ruby_name_file" "$snapshot_alias_name_file" > "$snapshot_installable_file"
  64
+  rm -rf "$snapshot_ruby_name_file" "$snapshot_alias_name_file"
  65
+  
  66
+  local snapshot_primary_ruby="$(cat "$snapshot_installable_file" | grep '^\(ree\|ruby-1.8.7\)' | grep -v '-head$' | sort -r | head -n1)"
  67
+  local snapshot_ruby_order="$snapshot_primary_ruby $(cat "$snapshot_installable_file" | grep -v "$snapshot_primary_ruby")"
  68
+  for snapshot_ruby_name in $snapshot_ruby_order ; do
  69
+    __rvm_become "$snapshot_ruby_name"
  70
+    ruby "$rvm_path/lib/rvm/install_command_dumper.rb" >> "$snapshot_temp_path/install-rubies.sh"
  71
+  done; unset snapshot_ruby_name snapshot_primary_ruby
  72
+  
  73
+  rm -rf "$snapshot_installable_file"
  74
+
  75
+  $rvm_scripts_path/log "info" "Compressing snapshotting"
  76
+  local destination_path="$PWD"
  77
+  __rvm_pushpop "$snapshot_temp_path"
  78
+  rm -rf "$destination_path/$1.tar.gz"
  79
+  tar czf "$destination_path/$1.tar.gz" .
  80
+  result="$?"
  81
+  __error_on_result "$result" "Error creating archive $destination_path/$1.tar.gz" && return "$result"
  82
+  __rvm_pushpop
  83
+
  84
+  $rvm_scripts_path/log "info" "Cleaning up"
  85
+  rm -rf "$snapshot_temp_path"
  86
+
  87
+  $rvm_scripts_path/log "info" "Snapshot complete"
  88
+
  89
+}
  90
+
  91
+snapshot_load() {
  92
+  if [[ -z "$1" ]]; then
  93
+    echo "Usage: rvm snapshot load name" >&2
  94
+    echo "Loads a snapshot from <name>.tar.gz in the current directory." >&2
  95
+    return 1
  96
+  fi
  97
+
  98
+  local snapshot_archive="$PWD/$(echo "$1" | sed 's/.tar.gz$//').tar.gz"
  99
+
  100
+  if ! [[ -s "$snapshot_archive" ]]; then
  101
+    echo "The provides snapshot '$(basename "$snapshot_archive")' doesn't exist." >&2
  102
+    return 1
  103
+  fi
  104
+
  105
+  local snapshot_temp_path="$rvm_tmp_path/$$-snapshot"
  106
+
  107
+  rm -rf "$snapshot_temp_path"
  108
+  mkdir -p "$snapshot_temp_path"
  109
+
  110
+  $rvm_scripts_path/log "info" "Extracting snapshot"
  111
+  __rvm_pushpop "$snapshot_temp_path"
  112
+  tar xzf "$snapshot_archive"
  113
+  result="$?"
  114
+  __error_on_result "$result" "Error extracting the archive '$snapshot_archive'" && return "$result"
  115
+  __rvm_pushpop
  116
+
  117
+  $rvm_scripts_path/log "info" "Restoring user settings"
  118
+  cp -f "$snapshot_temp_path/user" "$rvm_config_path/user"
  119
+
  120
+  $rvm_scripts_path/log "info" "Installing rvm-managed packages"
  121
+  for snapshot_package in $(cat "$snapshot_temp_path/packages"); do
  122
+    $rvm_scripts_path/package install "$snapshot_package"
  123
+    result="$?"
  124
+    __error_on_result "$result" "Error installing package '$snapshot_package'" && return "$result"
  125
+  done; unset snapshot_package
  126
+
  127
+  $rvm_scripts_path/log "info" "Installing rubies"
  128
+  chmod +x "$snapshot_temp_path/install-rubies.sh"
  129
+  $snapshot_temp_path/install-rubies.sh
  130
+  result="$?"
  131
+  __error_on_result "$result" "Error importing rubies." && return "$result"
  132
+
  133
+  export rvm_create_flag=1
  134
+  $rvm_scripts_path/log "info" "Setting up gemsets"
  135
+  __rvm_pushpop "$snapshot_temp_path/gems"
  136
+  for snapshot_gemset in $(\ls | grep '\.gems$' | sed 's/.gems$//'); do
  137
+    __rvm_become "$snapshot_gemset"
  138
+    result="$?"
  139
+    __error_on_result "$result" "Error becoming '$snapshot_gemset'" && return "$result"
  140
+    mkdir -p "$GEM_HOME/cache/"
  141
+    cp -Rf "$snapshot_gemset/" "$GEM_HOME/cache/"
  142
+    result="$?"
  143
+    __error_on_result "$result" "Error copying across cache for $snapshot_gemset" && return "$result"
  144
+    $rvm_scripts_path/gemsets import "$snapshot_gemset" >/dev/null 2>&1
  145
+    result="$?"
  146
+    __error_on_result "$result" "Error importing gemset for $snapshot_gemset" && return "$result"
  147
+  done; unset snapshot_gemset
  148
+  __rvm_pushpop
  149
+
  150
+  $rvm_scripts_path/log "info" "Restoring aliases"
  151
+  while read -r package_info; do
  152
+    local alias_name="$(echo "$package_info" | awk -F= '{print $1}')"
  153
+    local alias_ruby="$(echo "$package_info" | awk -F= '{print $2}')"
  154
+    $rvm_scripts_path/alias create "$alias_name" "$alias_ruby"
  155
+    if [[ "$alias_name" = "default" ]]; then
  156
+      (source "$rvm_scripts_path/rvm" && rvm use "$alias_ruby" --default) >/dev/null 2>&1
  157
+      result="$?"
  158
+      __error_on_result "$result" "Error setting default to $alias_ruby" && return "$result"
  159
+    fi
  160
+  done < "$snapshot_temp_path/alias"
  161
+  unset package_info
  162
+
  163
+  $rvm_scripts_path/log "info" "Cleaning up load process"
  164
+  rm -rf "$snapshot_temp_path"
  165
+
  166
+  $rvm_scripts_path/log "info" "Loaded snapshot from $(basename "$snapshot_archive")"
  167
+}
  168
+
  169
+snapshot_usage() {
  170
+  echo "Usage: rvm snapshot {save,load} file" >&2
  171
+  return 1
  172
+}
  173
+
  174
+action="$1"
  175
+[[ "$#" -gt 0 ]] && shift
  176
+
  177
+case "$action" in
  178
+  save) snapshot_save "$@" ;;
  179
+  load) snapshot_load "$@" ;;
  180
+  *)    snapshot_usage ;;
  181
+esac
  182
+
  183
+exit $?
6  scripts/utility
@@ -217,9 +217,9 @@ __rvm_ensure_has_18_compat_ruby() {
217 217
   if [[ -z "$(__rvm_18_compat_ruby)" ]]; then
218 218
     # TODO: install currently doesn't return the correct status.
219 219
     local compat_result=0
220  
-    if ! ( rvm install 1.8.7 ); then
221  
-      $rvm_scripts_path/log "fatal" "To proceed rvm requires a 1.8-compatible ruby is installed. We attempted to install 1.8.7 automatically but it failed."
222  
-      $rvm_scripts_path/log "fatal" "Please install it manually (or a compatible alternative) to proceed."
  220
+    if ! ( $rvm_scripts_path/manage install 1.8.7 ); then
  221
+      $rvm_scripts_path/log "fail" "To proceed rvm requires a 1.8-compatible ruby is installed. We attempted to install 1.8.7 automatically but it failed."
  222
+      $rvm_scripts_path/log "fail" "Please install it manually (or a compatible alternative) to proceed."
223 223
       compat_result=1
224 224
     fi
225 225
     unset original_ruby

0 notes on commit 8813db8

Please sign in to comment.
Something went wrong with that request. Please try again.