Quick Tip: Installing ruby 1.8.7 and rubygems 1.8.30 with RVM

MAR 22, 2018 • Written by M. Scott Ford

At Corgibytes, we frequently work on projects where it’s best to start out with an older version of ruby. Keeping an old version of ruby around forever is not something that we recommend. Keeping your tools updated is something we advocate strongly for. That said, it’s often required to start with the version in production, so that you have something to baseline against.

Getting older version of Ruby to install correctly feels like a dark art sometimes. Here’s a quick series of steps that I had to follow to get Ruby 1.8.7 using RubyGems 1.8.30 installed via RVM.

And if you’re wondering why I needed that specific version of RubyGems, I ran into a compatibility error with some of the gems that one of our client projects was depending on. Again, using a newer version would be ideal, and I’ll get it there eventually.

But first things first.

Just give me the code!

Here’s the TL;DR version of this post:

# Update the RubyGems download URL in RVM's DB
echo "rubygems_url=https://github.com/rubygems/rubygems/releases/download/v1.8.30/" \
  >> $rvm_path/user/db
# Install RubyGems without verifying the download
rvm rubygems --force 1.8.30 --verify-downloads 2

Enjoy!

Wait?! How did you figure that out?

Continue reading if you’re interested about how I got to that point.

I started out trying to run:

rvm rubygems --force 1.8.30

But that gave me output that looked like this. Skim the output and look out for 403. That’s the issue.

curl: (22) The requested URL returned error: 403 Forbidden
The requested url does not exist(22): 'https://rubygems.org/rubygems/rubygems-1.8.30.tgz'
Checking fallback: https://github.com/rubygems/rubygems/archive/v1.8.30.tar.gz
No fallback URL could be found, try increasing timeout with:

    echo \"export rvm_max_time_flag=20\" >> ~/.rvmrc

There has been an error while trying to fetch rubygems.
Halting the installation

Sure enough, when we tried to manually check those URLs they don’t work. After doing some Googling for “rvm rubygems curl: (22) The requested URL returned error: 403 Forbidden,” I discovered an conversation which suggested that dowloading the file directly in the the RVM archives directory would work. So, I tried this curl command.

curl -o ~/.rvm/archives/rubygems-1.8.30.tgz \
  https://github.com/rubygems/rubygems/releases/download/v1.8.30/rubygems-1.8.30.tgz

And I tried to install RubyGems 1.8.30 again:

rvm rubygems --force 1.8.30

This time I got a slightly different error:

No checksum for downloaded archive, recording checksum in user configuration.
Error running '__rvm_package_extract /home/vagrant/.rvm/archives/rubygems-1.8.30.tgz /home/vagrant/.rvm/src',
please read /home/vagrant/.rvm/log/1521567008_ruby-1.8.7-head/rubygems.extract.log
There has been an error while trying to extract rubygems.
Halting the installation.

Ugh. I did a bunch more Googling, starting with “rubygems 1.8.30 signature asc” to see if I could find a corresponding checksum for that file. I gave up on that after about 15 minutes.

After little more Googling, this time with “rvm rubygems no checksum for downloaded archive,” I decided to give this a try:

rvm rubygems --force 1.8.30 --verify-downloads 2

But that gave me a different error:

Error running '__rvm_package_extract /home/vagrant/.rvm/archives/rubygems-1.8.30.tgz /home/vagrant/.rvm/src',
please read /home/vagrant/.rvm/log/1521575233_ruby-1.8.7-head/rubygems.extract.log
There has been an error while trying to extract rubygems.
Halting the installation.

My first thought was that maybe me attempting to download the file directly into ~/.rvm/archives was the reason that the file wasn’t being parsed correctly. So I dug around to see if I could find a way to alter the url that RVM uses when downloading RubyGems. To figure that out, I dug through the RVM source code.

That’s when I noticed that RVM grabs the base of the URL from a config file which is referenced by calling __rvm_db.

So now I just needed to figure out how to set that value. More Googling. This time for “__rvm_db settings”.

That’s when I decided to give this a try.

echo "rubygems_url=https://github.com/rubygems/rubygems/releases/download/v1.8.30" \
  >> $rvm_path/user/db

And then I ran

rvm rubygems --force 1.8.30 --verify-downloads 2

But I still got an error…

Error running '__rvm_package_extract /home/vagrant/.rvm/archives/rubygems-1.8.30.tgz /home/vagrant/.rvm/src',
please read /home/vagrant/.rvm/log/1521575233_ruby-1.8.7-head/rubygems.extract.log
There has been an error while trying to extract rubygems.
Halting the installation.

So I took a peek at that log file:

cat /home/vagrant/.rvm/log/1521575620_ruby-1.8.7-head/rubygems.extract.log

and found the output below. Caution, don’t read all of this, just skim it and look for “gzip”. That’s the line that tells us what we need to know.

[2018-03-20 19:53:40] __rvm_package_extract
__rvm_package_extract ()
{
    rvm_debug __rvm_package_extract:$#: "$@";
    \typeset __tempdir __path __file __return;
    __return=0;
    __tempdir="$( TMPDIR="${rvm_tmp_path}" mktemp -d -t rvm-tmp.XXXXXXXXX )";
    __rvm_package_extract_run "$1" "$__tempdir" || __return=$?;
    if (( __return == 0 )); then
        for __path in "$__tempdir"/*;
        do
            __file="${__path##*/}";
            if [[ -n "${__file}" && -e "$2/${__file}" ]]; then
                \command \rm -rf "$2/${__file}" || __return=$?;
            fi;
            \command \mv -f "${__path}" "$2/" || __return=$?;
        done;
    fi;
    if [[ -n "$__tempdir" ]]; then
        \command \rm -rf "$__tempdir";
    fi;
    return $__return
}
current path: /home/vagrant
GEM_HOME=/home/vagrant/.rvm/gems/ruby-1.8.7-head
PATH=/home/vagrant/.rvm/gems/ruby-1.8.7-head/bin:/home/vagrant/.rvm/gems/ruby-1.8.7-head@global/bin:/home/vagrant/.rvm/rubies/ruby-1.8.7-head/bin:/home/vagrant/.rvm/bin:/home/vagrant/bin:/home/vagrant/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
GEM_PATH=/home/vagrant/.rvm/gems/ruby-1.8.7-head:/home/vagrant/.rvm/gems/ruby-1.8.7-head@global
command(3): __rvm_package_extract /home/vagrant/.rvm/archives/rubygems-1.8.30.tgz /home/vagrant/.rvm/src
+ rvm_debug __rvm_package_extract:2: /home/vagrant/.rvm/archives/rubygems-1.8.30.tgz /home/vagrant/.rvm/src
+ ((  0  ))
+ return 0
+ typeset __tempdir __path __file __return
+ __return=0
++ TMPDIR=/home/vagrant/.rvm/tmp
++ mktemp -d -t rvm-tmp.XXXXXXXXX
+ __tempdir=/home/vagrant/.rvm/tmp/rvm-tmp.JDCtF96Y0
+ __rvm_package_extract_run /home/vagrant/.rvm/archives/rubygems-1.8.30.tgz /home/vagrant/.rvm/tmp/rvm-tmp.JDCtF96Y0
+ [[    != *\ \-\-\n\o\-\s\a\m\e\-\o\w\n\e\r\ * ]]
+ __rvm_grep -- --no-same-owner
+ GREP_OPTIONS=
+ command grep -- --no-same-owner
+ grep -- --no-same-owner
+ __rvm_tar --help
+ rvm_tar_options=--no-same-owner
+ [[ -d /home/vagrant/.rvm/tmp/rvm-tmp.JDCtF96Y0 ]]
+ case "$1" in
+ [[ -n '' ]]
+ __rvm_tar xzf /home/vagrant/.rvm/archives/rubygems-1.8.30.tgz -C /home/vagrant/.rvm/tmp/rvm-tmp.JDCtF96Y0 --no-same-owner
+ tar xzf /home/vagrant/.rvm/archives/rubygems-1.8.30.tgz -C /home/vagrant/.rvm/tmp/rvm-tmp.JDCtF96Y0 --no-same-owner

gzip: stdin: not in gzip format
tar: Child returned status 1
tar: Error is not recoverable: exiting now
+ return 2
+ return 2
+ __return=2
+ ((  __return == 0  ))
+ [[ -n /home/vagrant/.rvm/tmp/rvm-tmp.JDCtF96Y0 ]]
+ command rm -rf /home/vagrant/.rvm/tmp/rvm-tmp.JDCtF96Y0
+ rm -rf /home/vagrant/.rvm/tmp/rvm-tmp.JDCtF96Y0
+ return 2

Reading through that it looked like gzip was complaining that the file was downloaded wasn’t a valid gzip archive file. That got me wondering what exactly was in there.

cat /home/vagrant/.rvm/archives/rubygems-1.8.30.tgz

And that’s when I saw: (formatted for easier viewing)

<html>
  <body>
    You are being
    <a href="https://github-production-release-asset-2e65be.s3.amazonaws.com/614070/983b0342-890e-11e4-9fd4-137a1a0e0d6d?X-Amz-Algorithm=AWS4-HMAC-SHA256&amp;X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20180320%2Fus-east-1%2Fs3%2Faws4_request&amp;X-Amz-Date=20180320T192226Z&amp;X-Amz-Expires=300&amp;X-Amz-Signature=ae8c0947b49e8e8a8c14963cecba4db507cfbd1d36095890e59919539bb359da&amp;X-Amz-SignedHeaders=host&amp;actor_id=0&amp;response-content-disposition=attachment%3B%20filename%3Drubygems-1.8.30.tgz&amp;response-content-type=application%2Foctet-stream">
      redirected
    </a>
    .
  </body>
</html>

Doh! It looks like curl isn’t following redirects, which seems like something that you should be able to control via RVM. So, I dove back into the source to track down the exact curl command that RVM uses for its downloads.

But reading and looking up those options in curl’s documentation was confusing, because one of the options explicitly specifies that redirects should be followed.

This is when some head scratching started…

That’s when I remembered that it was me who created that file by running:

curl -o ~/.rvm/archives/rubygems-1.8.30.tgz https://github.com/rubygems/rubygems/releases/download/v1.8.30/rubygems-1.8.30.tgz

And it was me who left off the option to follow redirects. So, I removed the file:

rm ~/.rvm/archives/rubygems-1.8.30.tgz

And then tried again:

echo "rubygems_url=https://github.com/rubygems/rubygems/releases/download/v1.8.30/" \
  >> $rvm_path/user/db
rvm rubygems --force 1.8.30 --verify-downloads 2

Yay! It worked!

After going through all of that, I suspect that calling curl directly, but making sure to specify --location (or -L) as one of the options would have done the trick as well.

It took me about two hours to complete this journey. You could look at all of that effort and see it as a waste of time. I choose not to look at it that way. Because now I know a lot more about the internals of RVM, and if you read this far, so do you. :)