diff --git a/.gitignore b/.gitignore index ac15852a54..4eef6b3901 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ site/.sass-cache/ site/tmp/dependencies/ site/tmp/ tags +.*.swp +tmp/ diff --git a/README b/README index 3e77b0bf96..ac7207ef68 100644 --- a/README +++ b/README @@ -1,7 +1,46 @@ Usage - rvm Action [Implementation] [Flags] [Options] + rvm [Flags] [Options] Action [Implementation[,Implementation[,...]] + +Flags + + --head - with update, updates rvm to git head version. + --rubygems - with update, updates rubygems for selected ruby + --default - with ruby select, sets a default ruby for new shells. + --debug - Toggle debug mode on for very verbose output. + --trace - Toggle trace mode on to see EVERYTHING rvm is doing. + --force - Force install, removes old install & source before install. + --summary - Used with rubydo to print out a summary of the commands run. + --latest - with gemset --dump skips version strings for latest gem. + --gems - with uninstall/remove removes gems with the interpreter. + --docs - with install, attempt to generate ri after installation. + --reconfigure - Force ./configure on install even if Makefile already exists. + + +Options + + -v|--version - Emit rvm version loaded for current shell + -l|--level - patch level to use with rvm use / install + --prefix - path for all rvm files (~/.rvm/), with trailing slash! + --bin - path for binaries to be placed (~/.rvm/bin/) + --source - src directory to use (~/.rvm/src/) + --archives - directory for downladed files (~/.rvm/archives/) + -S - Specify a script file to attempt to load and run (rubydo) + -e - Execute code from the command line. + -G - root gem path to use + --gems - Used to set the 'gems_flag', use with 'remove' to remove gems + --archive - Used to set the 'archive_flag', use with 'remove' to remove archive + --patch - With MRI Rubies you may specify one or more full paths to patches + for multiple, specify comma separated: + --patch /.../.../a.patch[%prefix],/.../.../.../b.patch + 'prefix' is an optional argument, which will be bypassed + to the '-p' argument of the 'patch' command. It is separated + from patch file name with '%' symbol. + -C|--configure - custom configure options. If you need to pass several configure + options then append them comma separated: -C --...,--...,--... + --nice - process niceness (for slow computers, default 0) + --ree-options - Options passed directly to ree's './installer' on the command line. Action @@ -9,18 +48,26 @@ Action version - show the rvm version installed in rvm_path use - setup current shell to use a specific ruby version reload - reload rvm source itself (useful after changing rvm source) - implode - removes rvm completely, i.e. everything in ~/.rvm + implode - (seppuku) removes the rvm installation completely. + This means everything in $rvm_path (~/.rvm). + This does not touch your profiles, which is why + there is an if around the sourcing scripts/rvm. update - upgrades rvm to the latest version. (If you experience bugs try this first with --head) reset - remove current and stored default & system settings. (If you experience odd behavior try this second) - info - show information for current ruby - debug - show environment & configuration information for *current* ruby + info - show the *current* environment information for current ruby + debug - show info plus additional information for common issues install - install one or many ruby versions + See also: http://rvm.beginrescueend.com/rubies/installing/ uninstall - uninstall one or many ruby versions, leaves their sources remove - uninstall one or many ruby versions and remove their sources + wrapper - generates a set of wrapper executables for a given ruby with the + specified ruby and gemset combination. Used under the hood for + passenger support and the like. + 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 @@ -35,63 +82,26 @@ Action fetch - Performs an archive / src fetch only of the selected ruby. list - show currently installed rubies, interactive output. - http://rvm.beginrescueend.com/listing/ + http://rvm.beginrescueend.com/rubies/list/ package - Install a dependency package {readline,iconv,zlib,openssl} http://rvm.beginrescueend.com/packages/ notes - Display notes, with operating system specifics. Implementation - * ruby - MRI/YARV Ruby (The Standard) {1.8.6,1.8.7,1.9.1,1.9.2...} - jruby - JRuby {1.3.1,1.4.0} - rbx - rubinius - ree - ruby Enterprise Edition - macruby - MacRuby (Mac OS X Only) - maglev - GemStone Ruby - ironruby - IronRuby - mput - shyouhei(mput)'s github repository + * ruby - MRI/YARV Ruby (The Gold Standard) {1.8.6,1.8.7,1.9.1,1.9.2...} + jruby - JRuby, Ruby interpreter on the Java Virtual Machine. + rbx - Rubinius + ree - Ruby Enterprise Edition, MRI Ruby with several custom + patches for performance, stability, and memory. + macruby - MacRuby, insanely fast, can make real apps (Mac OS X Only). + maglev - GemStone Ruby, awesome persistent ruby object store. + ironruby - IronRuby, NOT supported yet. Looking for volunteers to help. + mput - shyouhei(mput)'s github repository, popular in Japan :) system - use the system ruby (eg. pre-rvm state) default - use rvm set default ruby and system if it hasn't been set. + http://rvm.beginrescueend.com/rubies/default/ -Flags - - --head - with update, updates rvm to git head version. - --rubygems - with update, updates rubygems for selected ruby - --default - with ruby select, sets a default ruby for new shells. - --debug - Toggle debug mode on for very verbose output. - --force - Force install, removes old install & source before install. - --dump - Used with gemset to dump the current ruby's gemset. - --load - Used with gemset to load a specified gemset file - --summary - Used with rubydo to print out a summary of the commands run. - --jit - Used with rubinius install to build with JIT - --latest - with gemset --dump skips version strings for latest gem. - --reconfigure - Force ./configure on install even if Makefile already exists. - - -Options - - -v|--version - Emit rvm version loaded for current shell - -h|--help - Emit this output and exit - -l|--level - patch level to use with rvm use / install - --tag - subersion tag to use - --rev - repository revision # to use or 'head' for - - --prefix - path for all rvm files (~/.rvm/), with trailing slash! - --bin - path for binaries to be placed (~/.rvm/bin/) - --source - src directory to use (~/.rvm/src/) - --archives - directory for downladed files (~/.rvm/archives/) - -S - Specify a script file to attempt to load and run (rubydo) - -e - Execute code from the command line. - -G|--gems - root gem path to use - -C|--configure - custom configure options, comma separated - default: --enable-shared=true - --reconfigure - Force installer to re-run configure if already run - --make - custom make command - --make-install - custom make install command - --nice - process niceness (for slow computers, default 0) - -m|--gem-set - use a named gem set, instead of the default set. - --rm-gem-set - Remove a named gem set - --ree-options - Options passed directly to ree's './installer' on the command line. Resources: diff --git a/Rakefile b/Rakefile index 379042b5f0..6c32ff4755 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,5 @@ +require "rubygems" + task :default => ["test"] task :test do exec "bash -l -c \"./test/suite\"" ; end @@ -39,7 +41,7 @@ begin gemspec.date = Time.now.strftime("%Y-%m-%d") gemspec.description = "Manages Ruby interpreter environments and switching between them." gemspec.platform = Gem::Platform::RUBY - gemspec.files = ["install", "README", "sha1", "LICENCE", "rvm.gemspec", "bash/*", "binscripts/*", "scripts/*", "examples/*", "config/*", Dir::glob("lib/**/**")].flatten + gemspec.files = ["install", "README", "sha1", "LICENCE", "rvm.gemspec", "bash/*", "binscripts/*", "scripts/*", "examples/*", "config/*", "help/**", "gemsets/*", "contrib/*", Dir::glob("lib/**/**")].flatten gemspec.executables = Dir::glob("bin/rvm-*").map{ |script| File::basename script } gemspec.require_path = "lib" gemspec.has_rdoc = File::exist?("doc") @@ -63,6 +65,6 @@ begin end rescue LoadError - puts "Jeweler not available. Install it with: gem install jeweler -s http://gemcutter.org/" + puts "Jeweler not available. Install it with: gem install jeweler" end diff --git a/binscripts/rvm b/binscripts/rvm index 948b77d81e..30e24f8bd7 100644 --- a/binscripts/rvm +++ b/binscripts/rvm @@ -1,15 +1,24 @@ #!/usr/bin/env bash -if [[ -f /etc/rvmrc ]] ; then source /etc/rvmrc ; fi -if [[ -f "$HOME/.rvmrc" ]] ; then source "$HOME/.rvmrc" ; fi +for rvmrc in /etc/rvmrc $HOME/.rvmrc ; do + if [[ -f "$rvmrc" ]] ; then + if grep -q '^\s*rvm .*$' $rvmrc ; then + printf "\nError: $rvmrc is for rvm settings only.\nrvm CLI may NOT be called from within $rvmrc. \nSkipping the loading of $rvmrc" + exit 1 + else + source "$rvmrc" + fi + fi +done + if [[ -z "$rvm_prefix" ]] ; then unset rvm_prefix ; fi if [[ -z "$rvm_path" ]] ; then unset rvm_path ; fi -if [[ -z "$rvm_prefix" ]] ; then +if [[ -z "$rvm_prefix" ]] ; then if [[ "root" = "$(whoami)" ]] ; then - rvm_prefix="/usr/local" + rvm_prefix="/usr/local" else - rvm_prefix="$HOME" + rvm_prefix="$HOME/." fi fi @@ -33,4 +42,4 @@ source $rvm_scripts_path/rvm unset rvm_interactive -rvm "$*" +rvm $* diff --git a/binscripts/rvm-prompt b/binscripts/rvm-prompt index 253b133ac8..d7e62e03db 100755 --- a/binscripts/rvm-prompt +++ b/binscripts/rvm-prompt @@ -10,7 +10,9 @@ add(){ fi } -if [[ ! -z "$(which ruby 2>/dev/null | awk '/rvm/{print}')" ]] ; then +rvm_gemset_separator=${rvm_gemset_separator:-"+"} +ruby=$(command -v ruby) +if [[ ! -z "$ruby" ]] && [[ ! -z "$(echo "$ruby" | awk '/rvm/{print}')" ]] ; then unset format while [[ $# -gt 0 ]] ; do token="$1" ; shift @@ -20,6 +22,9 @@ if [[ ! -z "$(which ruby 2>/dev/null | awk '/rvm/{print}')" ]] ; then p|patchlevel) add "patchlevel" ;; r|revision) add "revision" ;; a|architecture) add "architecture" ;; + g|gemset) add "gemset" ;; + u|unicode) add "unicode" ;; + s|system) add "system" ;; *) echo "Unrecognized command line option '$token' for $0" ; exit 1 ;; esac done @@ -28,26 +33,69 @@ if [[ ! -z "$(which ruby 2>/dev/null | awk '/rvm/{print}')" ]] ; then add "interpreter" add "version" add "patchlevel" + add "gemset" fi - ruby_string=$(dirname "$(which ruby 2>/dev/null)" | xargs dirname | xargs basename) - if [[ ! -z "$interpreter_flag" ]] ; then + ruby_string=$(dirname "$ruby" | xargs dirname | xargs basename) + + if [[ ! -z "$interpreter_flag" ]] || [[ ! -z "$unicode_flag" ]] ; then interpreter="$(echo $ruby_string | awk -F'-' '{print $1}')" fi - if [[ ! -z "$version_flag" ]] ; then + + if [[ ! -z "$version_flag" ]] || [[ ! -z "$unicode_flag" ]] ; then version="$(echo $ruby_string | awk -F'-' '{print $2}')" fi + if [[ ! -z "$patchlevel_flag" ]] ; then patchlevel=$(echo $ruby_string | awk -F'-' '{print $3}') fi + if [[ ! -z "$architecture_flag" ]] ; then architecture="$(echo "$(ruby -v)" | sed 's/^.*\[//' | sed 's/\].*$//')" fi + if [[ ! -z "$gemset_flag" ]] ; then + gemset="$(echo $GEM_HOME | awk -F${rvm_gemset_separator} '{print $2}')" + if [[ ! -z "$gemset" ]] ; then gemset="${rvm_gemset_separator}$gemset" ; fi + fi + + if [[ ! -z "$unicode_flag" ]] ; then + case "$interpreter" in + jruby) unicode="☯" ;; + rbx) unicode="☃" ;; + ree) unicode="✈" ;; + macruby) unicode="⌘" ;; + maglev) unicode="㎖" ;; + ironruby) unicode="♭" ;; + mput) unicode="⎈" ;; + system) unicode="➆" ;; + ruby) + case "$version" in + 1.8.6) unicode="❻" ;; + 1.8.7) unicode="❼" ;; + 1.9.1) unicode="❶" ;; + 1.9.2) unicode="❷" ;; + *) unicode="♢" ;; + esac ;; + *) unicode="♢" ;; + esac + + if [[ ! -z "$(echo $ruby_string | awk '/-head/')" ]] ; then + unicode="${unicode}〠" + fi + fi + command="prompt=\"$format\"" eval "$command" - echo "${prompt/-]/]}" + echo "$prompt" | sed -e 's#^[[:space:]]*-*##g' -e 's#--*#-#g' -e 's#-*[[:space:]]*$##' -e 's#-'${rvm_gemset_separator}'#'${rvm_gemset_separator}'#' + +else + while [[ $# -gt 0 ]] ; do + token="$1" ; shift + case "$token" in + s|system) echo "system" ;; + esac + done fi exit 0 - diff --git a/binscripts/rvm-shell b/binscripts/rvm-shell new file mode 100755 index 0000000000..712f06b53f --- /dev/null +++ b/binscripts/rvm-shell @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +__rvm_shell_lookup_script() { + local relative_scripts_dir="$(dirname -- "$(dirname -- "$0")")/scripts" + for directory in "$rvm_scripts_path" "$HOME/.rvm/scripts" "/usr/local/rvm/scripts" "$relative_scripts_dir"; do + if [[ -d "$directory" && -s "$directory/rvm" ]]; then + echo "$directory/rvm" + return + fi + done +} + +# If the first argument isn't -c, remove it and set +# it to the ruby string value. +if [[ -n "$1" && -n "$(echo "$1" | grep -v '^-')" ]]; then + rvm_shell_ruby_string="$1" + shift +fi + +if [[ -n "$rvm_shell_ruby_string" ]]; then + rvm_shell_rvm_path="$(__rvm_shell_lookup_script)" + if [[ -n "$rvm_shell_rvm_path" ]]; then + source "$rvm_shell_rvm_path" + rvm "$rvm_shell_ruby_string" + if [[ "$?" -gt 0 ]]; then + echo "Error: RVM was unable to use '#$rvm_shell_ruby_string'" 1>&2 + exit 1 + fi + fi +fi + +exec bash "$@" diff --git a/binscripts/rvm-update-head b/binscripts/rvm-update-head new file mode 100755 index 0000000000..bae0ba048f --- /dev/null +++ b/binscripts/rvm-update-head @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +if [[ -f /etc/rvmrc ]] ; then source /etc/rvmrc ; fi +if [[ -f "$HOME/.rvmrc" ]] ; then source "$HOME/.rvmrc" ; fi +rvm_path="${rvm_path:-$HOME/.rvm}" +mkdir -p $rvm_path/src/ +cd $rvm_path/src + +rm -rf ./rvm/ && git clone --depth 1 git://github.com/wayneeseguin/rvm.git +cd rvm +# v v v This is a godo idea however it does not preserve the executible bit. +# Needs more thought, perhaps a simple sed instead. +# dos2unix scripts/* >/dev/null 2>&1 +bash scripts/install diff --git a/binscripts/rvm-update-latest b/binscripts/rvm-update-latest new file mode 100755 index 0000000000..9f31e315c5 --- /dev/null +++ b/binscripts/rvm-update-latest @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +if [[ -f /etc/rvmrc ]] ; then source /etc/rvmrc ; fi +if [[ -f "$HOME/.rvmrc" ]] ; then source "$HOME/.rvmrc" ; fi +rvm_path="${rvm_path:-$HOME/.rvm}" +mkdir -p $rvm_path/src/ +cd $rvm_path/src + +stable_version=$(curl -B http://rvm.beginrescueend.com/releases/stable-version.txt 2>/dev/null) + +echo "rvm-${stable_version}" + +curl -L "http://rvm.beginrescueend.com/releases/rvm-${stable_version}.tar.gz" -o "rvm-${stable_version}.tar.gz" + +tar zxf "rvm-${stable_version}.tar.gz" + +cd "rvm-${stable_version}" + +# v v v This is a godo idea however it does not preserve the executible bit. +# Needs more thought, perhaps a simple sed instead. +#dos2unix scripts/* >/dev/null 2>&1 + +bash scripts/install diff --git a/binscripts/rvmsudo b/binscripts/rvmsudo index dd4fd413b3..859f7e3d5a 100755 --- a/binscripts/rvmsudo +++ b/binscripts/rvmsudo @@ -1,8 +1,3 @@ #!/usr/bin/env bash -prefix="PATH='$PATH'" -if [[ ! -z "$BUNDLE_PATH" ]] ; then prefix="BUNDLE_PATH='$BUNDLE_PATH' $prefix" ; fi -if [[ ! -z "$GEM_HOME" ]] ; then prefix="GEM_HOME='$GEM_HOME' $prefix" ; fi -if [[ ! -z "$GEM_PATH" ]] ; then prefix="GEM_PATH='$GEM_PATH' $prefix" ; fi - -eval "sudo" "/usr/bin/env $prefix $@" +exec sudo -E "$@" diff --git a/config/db b/config/db index ad678480be..1563b4d4d4 100644 --- a/config/db +++ b/config/db @@ -1,39 +1,69 @@ +#General niceness=0 -ruby_repo_url=http://svn.ruby-lang.org/repos/ruby -ruby_configure=--enable-shared +# Rubies interpreter=ruby -ruby_version=1.8.6 -ruby_patchlevel=383 -rubygems_version=1.3.6 +ruby_version=1.8.7 +ruby_configure_flags=--enable-shared +ruby_patchlevel=299 +ruby_configure=--enable-shared +ruby_repo_url=http://svn.ruby-lang.org/repos/ruby +ruby_1.0_url=ftp://ftp.ruby-lang.org/pub/ruby/1.0 +ruby_1.2_url=ftp://ftp.ruby-lang.org/pub/ruby/1.2 +ruby_1.3_url=ftp://ftp.ruby-lang.org/pub/ruby/1.3 +ruby_1.4_url=ftp://ftp.ruby-lang.org/pub/ruby/1.4 +ruby_1.5_url=ftp://ftp.ruby-lang.org/pub/ruby/1.5 +ruby_1.6_url=ftp://ftp.ruby-lang.org/pub/ruby/1.6 +ruby_1.7_url=ftp://ftp.ruby-lang.org/pub/ruby/1.7 +ruby_1.8_url=ftp://ftp.ruby-lang.org/pub/ruby/1.8 +ruby_1.9_url=ftp://ftp.ruby-lang.org/pub/ruby/1.9 +ruby_2.0_url=ftp://ftp.ruby-lang.org/pub/ruby/2.0 +ruby_1.9.1_patch_level=378 +ruby_1.9.2_patch_level=rc2 +ruby_1.8.5_patch_level=231 +ruby_1.8.6_patch_level=399 +ruby_1.8.7_patch_level=299 +rubygems_version=1.3.7 rubygems_1.3.5_url=http://rubyforge.org/frs/download.php/60718 rubygems_1.3.6_url=http://rubyforge.org/frs/download.php/69365 -rbx_version=1.0.0 -rbx_patch_level=rc2 -rbx_url=http://asset.rubini.us/rubinius-1.0.0-rc2-20100104.tar.gz +rubygems_1.3.7_url=http://rubyforge.org/frs/download.php/70696 +rbx_version=1.0.1 +rbx_1.0.0_patch_level=20100514 +rbx_1.0.1_patch_level=20100603 +rbx_url=http://asset.rubini.us +rubinius_repo_url=git://github.com/evanphx/rubinius.git ree_version=1.8.7 +ree_configure_flags=--dont-install-useful-gems ree_1.8.6_patch_level=20090610 ree_1.8.6_url=http://rubyforge.org/frs/download.php/58677 ree_1.8.6_repo_url=git://github.com/FooBarWidget/rubyenterpriseedition.git -ree_1.8.7_url=http://rubyforge.org/frs/download.php/68719 +ree_1.8.7_url=http://rubyforge.org/frs/download.php/71096 ree_1.8.7_repo_url=git://github.com/FooBarWidget/rubyenterpriseedition187.git -ree_1.8.7_patch_level=2010.01 -ruby_1.9.1_patch_level=378 -ruby_1.9.2_patch_level=preview1 -ruby_1.8.5_patch_level=231 -ruby_1.8.6_patch_level=399 -ruby_1.8.7_patch_level=249 -jruby_version=1.4.0 +ree_1.8.7_patch_level=2010.02 +jruby_version=1.5.1 jruby_repo_url=git://github.com/jruby/jruby.git -jruby_url=http://jruby.kenai.com/downloads -macruby_version=0.5 +jruby_url=http://jruby.org.s3.amazonaws.com/downloads +macruby_version=0.6 macruby_url=http://www.macruby.org/files macruby_repo_url=git://git.macruby.org/macruby/MacRuby.git -macruby_nightly_url=http://macruby.icoretech.org/latest/macruby_nightly-latest.pkg -maglev_version=22907 +macruby_nightly_url=http://www.macruby.org/files/nightlies/macruby_nightly-latest.pkg +maglev_version=23832 maglev_url=http://glass-downloads.gemstone.com/maglev maglev_repo_url=git://github.com/MagLev/maglev.git -rubinius_repo_url=git://github.com/evanphx/rubinius.git shyouhei_repo_url=git://github.com/shyouhei/ruby.git -ironruby_version=1.0-rc2 +ironruby_version=1.0 ironruby_repo_url=git://github.com/ironruby/ironruby.git -ironruby_url=http://github.com/ironruby/ironruby/tarball/ +ironruby_1.0_url=http://rubyforge.org/frs/download.php/70179/ +# Packages +readline_url=ftp://ftp.gnu.org/gnu/readline +libiconv_url=http://ftp.gnu.org/pub/gnu/libiconv +curl_url=http://curl.haxx.se/download +openssl_url=http://www.openssl.org/source +zlib_url=http://www.zlib.net +autoconf_url=ftp.gnu.org/gnu/autoconf +ncurses_url=http://ftp.gnu.org/pub/gnu/ncurses +pkg-config_url=http://pkgconfig.freedesktop.org/releases +gettext_url=ftp://ftp.gnu.org/pub/gnu/gettext +libxml2_url=ftp://xmlsoft.org/libxml2/ +glib_url=http://ftp.gnome.org/pub/gnome/sources/glib/2.23 +mono_url=http://ftp.novell.com/pub/mono/sources/mono/ +llvm_url=https://llvm.org/svn/llvm-project/llvm/trunk diff --git a/config/known b/config/known new file mode 100644 index 0000000000..27b87be259 --- /dev/null +++ b/config/known @@ -0,0 +1,48 @@ +# MRI Rubies +(ruby-)1.8.6(-p399) +(ruby-)1.8.6-head +(ruby-)1.8.7(-p299) +(ruby-)1.8.7-head +(ruby-)1.9.1-p243 +(ruby-)1.9.1-p376 +(ruby-)1.9.1(-p429) +(ruby-)1.9.1-head +(ruby-)1.9.2-preview1 +(ruby-)1.9.2-preview3 +(ruby-)1.9.2(-rc2) +(ruby-)1.9.2-head +ruby-head + +# JRuby +jruby-1.2.0 +jruby-1.3.1 +jruby-1.4.0 +jruby(-1.5.1) +jruby-head + +# Rubinius +rbx(-1.0.1) +rbx-head + +# Ruby Enterprise Edition +ree-1.8.6 +ree(-1.8.7) +ree-1.8.6-head +ree-1.8.7-head + +# MagLev +maglev(-23832) +maglev-head + +# Shyouhei head, the default mput +mput(-head) + +# Mac OS X Snow Leopard Only +macruby(-nightly) # the default macruby +macruby-head # Build from the macruby git repository + +# IronRuby -- Not implemented yet. +ironruby-0.9.3 +ironruby-1.0-rc2 +ironruby-head + diff --git a/config/md5 b/config/md5 index b7f227fa51..670159c484 100644 --- a/config/md5 +++ b/config/md5 @@ -1,4 +1,8 @@ rubinius-1.0.0-rc1-20091125.tar.gz=c1cf037f05caf1bc962c09e220b435f4 +rubinius-1.0.0-rc4-20100331.tar.gz=c631131cc9542c548b4fc3791d8aa6b2 +rubinius-1.0.0-rc5-20100510.tar.gz=d4fbb5b01aaeee3948cbe1cd38236524 +rubinius-1.0.0-20100514.tar.gz=b05f4e791d3712c5a50b3d210dac6eb0 +rubinius-1.0.1-20100603.tar.gz=eb185703c7ae0c0210e8dcb7f783ee8e ruby-1.8.5-p115.tar.gz=20ca6cc87eb077296806412feaac0356 ruby-1.8.5-p231.tar.gz=e900cf225d55414bffe878f00a85807c ruby-1.8.6-p286.tar.gz=797ea136fe43e4286c9362ee4516674e @@ -11,45 +15,32 @@ ruby-1.8.7-p160.tar.gz=945398f97e2de6dd8ab6df68d10bb1a1 ruby-1.8.7-p174.tar.gz=18dcdfef761a745ac7da45b61776afa5 ruby-1.8.7-p248.tar.gz=60a65374689ac8b90be54ca9c61c48e3 ruby-1.8.7-p249.tar.gz=d7db7763cffad279952eb7e9bbfc221c +ruby-1.8.7-p299.tar.gz=43533980ee0ea57381040d4135cf9677 ruby-1.9.1-p129.tar.gz=c71f413514ee6341c627be2957023a5c ruby-1.9.1-p243.tar.gz=515bfd965814e718c0943abf3dde5494 ruby-1.9.1-p376.tar.gz=ebb20550a11e7f1a2fbd6fdec2a3e0a3 ruby-1.9.1-p376.tar.gz=ebb20550a11e7f1a2fbd6fdec2a3e0a3 ruby-1.9.1-p378.tar.gz=9fc5941bda150ac0a33b299e1e53654c +ruby-1.9.1-p429.tar.gz=0f6d7630f26042e00bc59875755cf879 ruby-1.9.2-preview1.tar.gz=e2b8cdbf300f53472be09699a5837fd1 +ruby-1.9.2-preview3.tar.gz=209e59f3495a5503fa948c2732f1d705 +ruby-1.9.2-rc1.tar.gz=fdedd5b42ae89a9a46797823ad2d9acf +ruby-1.9.2-rc2.tar.gz=d12cd39eee4d99bc54b52aba5a0ba4e1 ruby-enterprise-1.8.6-20090610.tar.gz=0bf66ee626918464a6eccdd83c99d63a ruby-enterprise-1.8.7-2009.10.tar.gz=3727eef7b6b1b2f31db7d091328d966e ruby-enterprise-1.8.7-20090928.tar.gz=ae00018ce89d95419dfde370fcd485ac +ruby-enterprise-1.8.7-2010.02.tar.gz=4df7b09c01adfd711b0ab76837611542 rubygems-1.3.5.tgz=6e317335898e73beab15623cdd5f8cff -MagLev-22683.Darwin-i386.tar.gz=bf58b17bc2ca62ac0ca9304e8909985c -MagLev-22725.Darwin-i386.tar.gz=31f615a51c1bd02b002ba502d3af6b9b -MagLev-22725.Linux-x86_64.tar.gz=b20d1ccf2071537c66d382079db947ae -MagLev-22780.Darwin-i386.tar.gz=e0a23dff3a9c67a6873faf4b82727bd9 -MagLev-22780.Linux-x86_64.tar.gz=63e3acc32ef49c8198c811fcc29c52de -GemStone-22725.Linux-x86_64.tar.gz=41747ab3ff3207a007026a8161e286bc -GemStone-22683.Darwin-i386.tar.gz=62ff6be1a99ae708e97d6d43eb044e5a -GemStone-22725.Darwin-i386.tar.gz=a183fd8dc593258a0ca067283414227a -GemStone-22780.Darwin-i386.tar.gz=54d5c92153f9473e4f892f583706106c -GemStone-22780.Linux-x86_64.tar.gz=97a511b4f4d835653d4a2c6ccef3e9e1 -GemStone-22804.Darwin-i386.tar.gz=0963cce504839169a601e27f916d101f -GemStone-22804.Linux-x86_64.tar.gz=95058982c5d09a2ef77f4999a6683fbb -MagLev-22804.Darwin-i386.tar.gz=930a85c821f8d80d22f2b53b03c18181 -MagLev-22804.Linux-x86_64.tar.gz=047d5b6404a5fbfad1c9a9243e6e67a7 -GemStone-22816.Darwin-i386.tar.gz=b12426c17b3925f1c8c7086a3285f15f -GemStone-22816.Linux-x86_64.tar.gz=21d1e8e7a4b10ac8a1c199eb0cbfaec1 -MagLev-22816.Darwin-i386.tar.gz=b1b3e6530e90d7dcf36f81e097776643 -MagLev-22816.Linux-x86_64.tar.gz=424ca92c34cfce6d0da63170755b000c -MagLev-22891.Darwin-i386.tar.gz=d8d3a8aaff1473422d6a30ecd2b2e9ff -GemStone-22891.Darwin-i386.tar.gz=84080bda40c640aac9f19f5ea48403bf -MagLev-22891.Linux-x86_64.tar.gz=f91f1bec1f3defb49323a70ec25504ef -GemStone-22891.Linux-x86_64.tar.gz=5fd0d341a0eb586c9f804976cc290810 -GemStone-22907.Darwin-i386.tar.gz=c55d586da20dc4dd65da2e7f731f1d74 -GemStone-22907.Linux-x86_64.tar.gz=47c2d4527e3ea04715808048669d69ce -MagLev-22907.Darwin-i386.tar.gz=8b7b351581611d076c7c9c1f90a04160 -MagLev-22907.Linux-x86_64.tar.gz=9f88d6bf8f607f5fdc1c476f7a6ab851 +rubygems-1.3.6.tgz=789ca8e9ad1d4d3fe5f0534fcc038a0d +rubygems-1.3.7.tgz=e85cfadd025ff6ab689375adbf344bbe MacRuby%200.5.zip=675454a8c7bc19d606d90a726e08427c +MacRuby%200.6.zip=a80afd3700c88cf95c539fc63b272faf jruby-bin-1.3.1.tar.gz=4a95db8fc93ed7219663fbede98b6117 jruby-bin-1.4.0.tar.gz=f37322c18e9134e91e064aebb4baa4c7 +jruby-bin-1.5.0.RC1.tar.gz=47b4ca2a21659d36a2775ade0a2534c4 +jruby-bin-1.5.0.RC3.tar.gz=9c2758600de903b8ca07cb1341f4f1b3 +jruby-bin-1.5.0.tar.gz=ee2b4e326e8b87858e5dd0c8e94102e6 +jruby-bin-1.5.1.tar.gz=0196dcfb17354f12253eaddc1166a0ee libiconv-1.13.1.tar.gz=7ab33ebd26687c744a37264a330bbe9a ncurses.tar.gz=cce05daf61a64501ef6cd8da1f727ec6 openssl-0.9.8k.tar.gz=e555c6d58d276aec7fdc53363e338ab3 @@ -58,5 +49,8 @@ readline-6.0.tar.gz=b7f65a48add447693be6e86f04a63019 zlib-1.2.3.tar.gz=debc62758716a169df9f62e6ab2bc634 curl-7.19.7.tar.gz=ecb2e37e45c9933e2a963cabe03670ab pkg-config-0.23.tar.gz=d922a88782b64441d06547632fd85744 -rubygems-1.3.6.tgz=789ca8e9ad1d4d3fe5f0534fcc038a0d -ironruby-ironruby-c912e86.tar.gz=80708c23577ff9bf557f63f0f716fe26 +ironruby-1.0.zip=7a92888837b3507355ed391dbfc0ab83 +GemStone-23832.Darwin-i386.tar.gz=2e5d34c21a064b04103def63d0221149 +GemStone-23832.Linux-x86_64.tar.gz=429f81c5c0ec4c8d7188f176b1dc3374 +MagLev-23832.Darwin-i386.tar.gz=d9925605f27a2b454aede7b410d99b8b +MagLev-23832.Linux-x86_64.tar.gz=f3f7048a353e1b1724adcecb56d50766 diff --git a/contrib/gemset_snapshot b/contrib/gemset_snapshot new file mode 100755 index 0000000000..423fbc70da --- /dev/null +++ b/contrib/gemset_snapshot @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +echo "Snapshotting the current environment gem list into snapshot.gems" +file_name="snapshot.gems" +echo '# system snapshot gemset file' > snapshot.gems +for gem in $(gem list | sed 's#[\(|\)]##g' | sed 's#, #,#g' | tr ' ' ';') ; do + name="$(echo $gem | awk -F';' '{print $1}')" + versions="$(echo $gem | awk -F';' '{print $2}' | sed 's#,# #g')" + for version in $versions ; do + echo "$name -v$version" >> $file_name + done ; unset version versions +done ; unset file_name + +exit $? diff --git a/contrib/install-system-wide b/contrib/install-system-wide new file mode 100644 index 0000000000..10f1deb9b6 --- /dev/null +++ b/contrib/install-system-wide @@ -0,0 +1,81 @@ +#!/usr/bin/env bash + +# Require root to install it. +if [[ "$(whoami)" != "root" ]]; then + echo "Please rerun this installer as root." >&2 + exit 1 +fi + +# Check for the presence of git. +if ! command -v git >/dev/null 2>&1 ; then + echo "Please ensure git is installed and available in PATH to continue." >&2 + exit 1 +fi + +# Load the rvm config. +[[ -s /etc/rvmrc ]] && source /etc/rvmrc +[[ -s "$HOME/.rvmrc" ]] && source "$HOME/.rvmrc" + +rvm_path="${rvm_path:-"/usr/local/rvm"}" + +mkdir -p "$rvm_path/src/" +builtin cd "$rvm_path/src" + +rm -rf ./rvm/ + +git clone --depth 1 git://github.com/wayneeseguin/rvm.git + +builtin cd rvm + +"Running the install script." +bash ./scripts/install + +rvm_group_name="${rvm_group_name:-"rvm"}" + +if cat /etc/group | cut -d: -f1 | grep -q "^${rvm_group_name}$"; then + echo "Group exists, proceeding with installation." +else + echo "Creating the group '$rvm_group_name'" + groupadd -f "$rvm_group_name" +fi +echo "Adding root the '$rvm_group_name'" +usermod -a -G "$rvm_group_name" "$(whoami)" + +echo "Setting up group permissions" +for dir in rvm bin share/man; do + chown -R root:"$rvm_group_name" /usr/local/$dir + chmod -R g+w /usr/local/$dir +done; unset dir + +echo "Generating system wide rvmrc" +rm -f /etc/rvmrc +touch /etc/rvmrc +cat > /etc/rvmrc < /usr/local/lib/rvm < /dev/null` ]] || (echo "'asciidoc' is not installed on your system, exiting..."; exit 1) +[[ `which docbook2man 2> /dev/null` ]] || (echo "'docbook2x' is not installed on your system, exiting..."; exit 1) + +DIRNAME=$(dirname $0) +rvm_base_dir=$(cd $DIRNAME/../; pwd) +rvm_docs_src_dir=${rvm_base_dir}/docs +rvm_tmp_dir=${rvm_base_dir}/tmp +rvm_docs_target_man_dir=${rvm_base_dir}/man + +mkdir -p ${rvm_tmp_dir} +mkdir -p ${rvm_docs_target_man_dir} + +echo "Starting doc generation run through." + +# processing manpages +find ${rvm_docs_src_dir} -type f -name *.txt | while read rvm_manpage_file; do + + # trying to detect manpage name automatically + # (just for fun, I don't think, that rvm will ever have more then one manpage :) + # The name of the generated manpage is initially specified within the source file in asciidoc format, + # so we'll do some simple parsing + # We assume, that it will be specified at one of the 3 (three) first lines + # of the source file. + + # it should be something like 'RVM(1)' + rvm_manpage_name_full="$(cat ${rvm_manpage_file} | head -n 3 | grep -o '^[^(]*[(][^)]*[)]$')" + + if [[ -z "${rvm_manpage_name_full}" ]]; then + echo "Unable to detect manpage name, stopping build process..." 1>&2 + exit 1 + fi + + # we need smth like 'rvm.1' + rvm_manpage_name="$(echo "$rvm_manpage_name_full" | sed "s|(|.|;s|)||" | tr '[[:upper:]]' '[[:lower:]]')" + # we need '1' + rvm_manpage_name_part=$(echo "$rvm_manpage_name" | cut -d '.' -f 2) + # So, the manpage directory will be the following: + rvm_manpage_dir="$rvm_docs_target_man_dir/man$rvm_manpage_name_part" + mkdir -p "$rvm_manpage_dir" + + echo "Generating manpage format from source file for $rvm_manpage_name" + a2x -d manpage -f manpage -D "$rvm_manpage_dir" "$rvm_manpage_file" > /dev/null 2>&1 + if [[ "$?" -gt 0 ]]; then + echo "Unable to generate manpage for $rvm_manpage_name_full" + else + rm -f "$( echo "$rvm_manpage_file" | sed 's/.txt$/.xml/')" + # compression is optional, but gzip check added for neatness + if command -v gzip >/dev/null 2>&1; then + echo "gzip compressing the manpage" + gzip < "$rvm_manpage_dir/$rvm_manpage_name" > "$rvm_manpage_dir/$rvm_manpage_name.gz" + fi + fi +done + +# vim: ft=sh diff --git a/docs/rvm.txt b/docs/rvm.txt new file mode 100644 index 0000000000..af3c6003d5 --- /dev/null +++ b/docs/rvm.txt @@ -0,0 +1,266 @@ +RVM(1) +====== + + +NAME +---- +rvm - The Ruby Version Manager + + +SYNOPSIS +-------- +*rvm* ['FLAGS'] ['OPTIONS'] 'ACTION' ['IMPLEMENTATION'[,'IMPLEMENTATION'[,'...']] + + +DESCRIPTION +----------- +RVM is a command line tool which allows us to easily install, manage and work +with multiple ruby environments from interpreters to sets of gems. + + +FLAGS +----- + +*--head*:: + with update, updates rvm to git head version. + +*--rubygems*:: + with update, updates rubygems for selected ruby + +*--default*:: + with ruby select, sets a default ruby for new shells. + +*--debug*:: + Toggle debug mode on for very verbose output. + +*--trace*:: + Toggle trace mode on to see EVERYTHING rvm is doing. + +*--force*:: + Force install, removes old install & source before install. + +*--summary*:: + Used with rubydo to print out a summary of the commands run. + +*--latest*:: + with gemset --dump skips version strings for latest gem. + +*--gems*:: + with uninstall/remove removes gems with the interpreter. + +*--docs*:: + with install, attempt to generate ri after installation. + +*--reconfigure*:: + Force ./configure on install even if Makefile already exists. + + + +OPTIONS +------- + +*-v, --version*:: + Emit rvm version loaded for current shell. + +*-l, --level*:: + patch level to use with rvm use / install + +*--prefix*:: + path for all rvm files ('~/.rvm/'), with trailing slash! + +*--bin*:: + path for binaries to be placed ('~/.rvm/bin/') + +*--source*:: + src directory to use ('~/.rvm/src/') + +*--archives*:: + directory for downladed files ('~/.rvm/archives/') + +*-S*:: + Specify a script file to attempt to load and run (rubydo). + +*-e*:: + Execute code from the command line. + +*-G*:: + root gem path to use + +*--gems*:: + Used to set the 'gems_flag', use with 'remove' to remove gems. + +*--archive*:: + Used to set the 'archive_flag', use with 'remove' to remove archive. + +*--patch*, *--patches*:: + With any ruby build from source, allows you to specify patch paths + and patch names to be applied prior to building. Values should + be a relative / absolute path to a patch or the name of known + patch / patchset. Optionally, paths or names may be followed by + '%someinteger' - e.g. '--patches mypatch%2' - where the number + following the % specifies the value of the -p argument to patch, + defaulting to two. + +*-C, --configure*:: + custom configure options. If you need to pass several configure + options then append them comma separated: '-C --...,--...,--...'. + +*--nice*:: + process niceness (for slow computers, default 0) + +*--ree-options*:: + Options passed directly to ree's './installer' on the command line. + + +ACTIONS +------- + +*usage*:: + Show this usage information. + +*version*:: + Show the rvm version installed in rvm_path. + +*use*:: + Setup current shell to use a specific ruby version. + +*reload*:: + Reload rvm source itself (useful after changing rvm source). + +*env*:: + Displays information about an environment specified but the + given ruby string. Useful for getting a sourceable path or an + evaluatable set of shell variable declarations. + +*implode*:: + (seppuku) removes the rvm installation completely. + This means everything in $rvm_path ('~/.rvm'). + This does not touch your profiles, which is why + there is an if around the sourcing 'scripts/rvm'. + +*update*:: + Upgrades rvm to the latest version. + (If you experience bugs try this first with --head). + +*reset*:: + Remove current and stored default & system settings. + (If you experience odd behavior try this second). + +*info*:: + Show the *current* environment information for current ruby. + +*debug*:: + Show info plus additional information for common issues. + + +*install*:: + Install one or many ruby versions. + http://rvm.beginrescueend.com/rubies/installing/ + +*uninstall*:: + Uninstall one or many ruby versions, leaves their sources. + +*remove*:: + Uninstall one or many ruby versions and remove their sources. + +*wrapper*:: + Generates a set of wrapper executables for a given ruby with the + specified ruby and gemset combination. Used under the hood for + passenger support and the like. + +*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. + +*tests*:: + Runs 'rake test' across selected ruby versions. + +*specs*:: + Runs 'rake spec' across selected ruby versions. + +*monitor*:: + Monitor cwd for testing, run 'rake {spec,test}' on changes. + +*gemset*:: + gemsets: http://rvm.beginrescueend.com/gemsets/ + +*gemdir*:: + Display the path to the current gem directory ('$GEM_HOME'). + +*srcdir*:: + Display the path to rvm source directory (may be yanked). + +*fetch*:: + Performs an archive / src fetch only of the selected ruby. + +*list*:: + Show currently installed rubies, interactive output. + http://rvm.beginrescueend.com/rubies/list/ + +*package*:: + Install a dependency package {readline,iconv,zlib,openssl}. + http://rvm.beginrescueend.com/packages/ + +*notes*:: + Display notes, with operating system specifics. + + +IMPLEMENTATION +-------------- + +*ruby*:: + MRI/YARV Ruby (The Gold Standard) {1.8.6,1.8.7,1.9.1,1.9.2...} + +*jruby*:: + JRuby, Ruby interpreter on the Java Virtual Machine. + +*rbx*:: + Rubinius + +*ree*:: + Ruby Enterprise Edition, MRI Ruby with several custom + patches for performance, stability, and memory. + +*macruby*:: + MacRuby, insanely fast, can make real apps (Mac OS X Only). + +*maglev*:: + GemStone Ruby, awesome persistent ruby object store. + +*ironruby*:: + IronRuby, NOT supported yet. Looking for volunteers to help. + +*mput*:: + shyouhei(mput)'s github repository, popular in Japan :) + +*system*:: + Use the system ruby (eg. pre-rvm state). + +*default*:: + Use rvm set default ruby and system if it hasn't been set. + http://rvm.beginrescueend.com/rubies/default/ + + +RESOURCES +--------- + +http://rvm.beginrescueend.com/[Main web site] + +https://www.pivotaltracker.com/projects/26822[Online issue-tracker] + + +COPYING +------- + +Copyright (c) 2009 Wayne E. Seguin + +See LICENCE file for details. + +//// +# vim:ft=asciidoc +//// diff --git a/examples/rvmrc b/examples/rvmrc index d3b90e07ba..3b5340d65e 100644 --- a/examples/rvmrc +++ b/examples/rvmrc @@ -27,7 +27,7 @@ # Bin Path # This is where rvm places all of it's executable/wrapper scripts. -#export rvm_bin_path="${$rvm_path}/bin" +#export rvm_bin_path="${rvm_path}/bin" # Gem Path # This is where rvm installs all gems to for each ruby diff --git a/gemsets/default.gems b/gemsets/default.gems new file mode 100644 index 0000000000..3a06708226 --- /dev/null +++ b/gemsets/default.gems @@ -0,0 +1,2 @@ +rake +rdoc diff --git a/gemsets/global.gems b/gemsets/global.gems new file mode 100644 index 0000000000..3a06708226 --- /dev/null +++ b/gemsets/global.gems @@ -0,0 +1,2 @@ +rake +rdoc diff --git a/gemsets/jruby/global.gems b/gemsets/jruby/global.gems new file mode 100644 index 0000000000..fcd46ffdd7 --- /dev/null +++ b/gemsets/jruby/global.gems @@ -0,0 +1 @@ +jruby-openssl diff --git a/help/alias b/help/alias new file mode 100644 index 0000000000..bf0304f7ee --- /dev/null +++ b/help/alias @@ -0,0 +1,46 @@ +Alias + + RVM allows you to alias your rubies for your convenience and pleasure. + +Usage + rvm [options] alias source destination + + Source and Destination must be an RVM + ruby string representing an RVM installed ruby. + + A gemset may be optionally included. + +Creating Aliases + + First select an RVM ruby. + + ∴ rvm alias create php ree-1.8.7-p2010.01 + +Using Aliases + + Now that you have created an alias, you can use the alias in place of the longer rvm selector string. + + ∴ rvm use php + ∴ ruby -v + ruby 1.8.7 (2009-12-24 patchlevel 248) [i686-darwin10.3.0], MBARI 0x6770, Ruby Enterprise Edition 2010.01 + +If you use any aliases that are rather funny, please hop in #rvm and let us know :) + +Deleting Aliases + + If you wish to delete an alias + + ∴ rvm alias delete dotnet + Listing Aliases + +You can also list all current aliases + + ∴ rvm alias list + php => ree-1.8.7-p2010.01 + lisp => maglev-head + python => rbx-head + +Documentation: + + http://rvm.beginrescueend.com/rubies/alias/ + diff --git a/help/benchmark b/help/benchmark new file mode 100644 index 0000000000..b0ac7651d0 --- /dev/null +++ b/help/benchmark @@ -0,0 +1,17 @@ +Benchmark + +If you have a bit of code that you would like to benchmark across several versions of ruby all at once you can now do this easily with RVM. Given: + + ∴ cat increment.rb + y=0 + 1000.times do |x| + y = x + 1 + end +We can benchmark this code against multiple ruby versions very easily: + + ∴ rvm 1.8.6,1.8.7,1.9.1,ree benchmark increment.rb + + +Documentation: + +http://rvm.beginrescueend.com/set/benchmark/ diff --git a/help/debug b/help/debug new file mode 100644 index 0000000000..02a5f3d241 --- /dev/null +++ b/help/debug @@ -0,0 +1,8 @@ +Debug + + TODO + +Documentation: + + TODO + diff --git a/help/fetch b/help/fetch new file mode 100644 index 0000000000..c402695d64 --- /dev/null +++ b/help/fetch @@ -0,0 +1,5 @@ +Fetch + + Performs an archive / src fetch of the current selected ruby. + +Usage: ∴ rvm fetch \ No newline at end of file diff --git a/test/rvm/hash_test b/help/gem similarity index 100% rename from test/rvm/hash_test rename to help/gem diff --git a/help/gemdir b/help/gemdir new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/gemset b/help/gemset new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/implode b/help/implode new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/info b/help/info new file mode 100644 index 0000000000..b5cb63c50d --- /dev/null +++ b/help/info @@ -0,0 +1,64 @@ + +∴ rvm info [ruby_string[,ruby_string[,...] [section,[section[,...] + +where sections are one of: + + system rvm ruby homes binaries environment debug + +Both ruby strings and sections are optional arguments. + +By default with no parameters rvm info will output all sections except debug. + +To display system rvm debug information: + + ∴ rvm debug + +which will display all sections including debug for the current or specified interpreters. + +Example: + + ∴ rvm info 1.9.2-head,1.8.7 homes,binaries,environment + + ruby-1.9.2-head: + + homes: + gem: "/Users/wayne/.rvm/gems/ruby-1.9.2-head" + ruby: "/Users/wayne/.rvm/rubies/ruby-1.9.2-head" + + binaries: + ruby: "/Users/wayne/.rvm/rubies/ruby-1.9.2-head/bin/ruby" + irb: "/Users/wayne/.rvm/rubies/ruby-1.9.2-head/bin/irb" + gem: "/Users/wayne/.rvm/rubies/ruby-1.9.2-head/bin/gem" + rake: "/Users/wayne/.rvm/gems/ruby-1.9.2-head/bin/rake" + + environment: + GEM_HOME: "/Users/wayne/.rvm/gems/ruby-1.9.2-head" + GEM_PATH: "/Users/wayne/.rvm/gems/ruby-1.9.2-head:/Users/wayne/.rvm/gems/ruby-1.9.2-head@global" + BUNDLE_PATH: "/Users/wayne/.rvm/gems/ruby-1.9.2-head" + MY_RUBY_HOME: "/Users/wayne/.rvm/rubies/ruby-1.9.2-head" + IRBRC: "/Users/wayne/.rvm/rubies/ruby-1.9.2-head/.irbrc" + RUBYOPT: "" + gemset: "" + + ruby-1.8.7-p249: + + homes: + gem: "/Users/wayne/.rvm/gems/ruby-1.8.7-p249" + ruby: "/Users/wayne/.rvm/rubies/ruby-1.8.7-p249" + + binaries: + ruby: "/Users/wayne/.rvm/rubies/ruby-1.8.7-p249/bin/ruby" + irb: "/Users/wayne/.rvm/rubies/ruby-1.8.7-p249/bin/irb" + gem: "/Users/wayne/.rvm/rubies/ruby-1.8.7-p249/bin/gem" + rake: "/Users/wayne/.rvm/gems/ruby-1.8.7-p249/bin/rake" + + environment: + GEM_HOME: "/Users/wayne/.rvm/gems/ruby-1.8.7-p249" + GEM_PATH: "/Users/wayne/.rvm/gems/ruby-1.8.7-p249:/Users/wayne/.rvm/gems/ruby-1.8.7-p249@global" + BUNDLE_PATH: "/Users/wayne/.rvm/gems/ruby-1.8.7-p249" + MY_RUBY_HOME: "/Users/wayne/.rvm/rubies/ruby-1.8.7-p249" + IRBRC: "/Users/wayne/.rvm/rubies/ruby-1.8.7-p249/.irbrc" + RUBYOPT: "" + gemset: "" + + diff --git a/help/install b/help/install new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/list b/help/list new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/monitor b/help/monitor new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/notes b/help/notes new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/package b/help/package new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/rake b/help/rake new file mode 100644 index 0000000000..6fca983cbb --- /dev/null +++ b/help/rake @@ -0,0 +1,14 @@ +Rake + + RVM allows you to run rake tasks across multiple ruby versions, for example: + + ∴ rvm 1.8.6,1.9.1 rake spec + +JSON Summary + + Adding a --json flag prior to the word 'rake' and a JSON summary will be printed out at the end of the run. + +YAML Summary + + Adding a --yaml flag prior to the word 'rake' and a YAML summary will be printed out at the end of the run. + diff --git a/help/remove b/help/remove new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/reset b/help/reset new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/ruby b/help/ruby new file mode 100644 index 0000000000..b2d7a5b9cf --- /dev/null +++ b/help/ruby @@ -0,0 +1,84 @@ +'rvm ruby' + +Given: + +∴ cat test.rb + puts "patchlevel: #{RUBY_PATCHLEVEL}, release_date: #{RUBY_RELEASE_DATE}, ruby_version: #{RUBY_VERSION}, ruby_platform: #{RUBY_PLATFORM}" + +∴ rvm list + + ruby: + + ruby-1.8.6-p383 [x86_64] + ruby-1.8.7-p174 [x86_64] + ruby-1.9.1-head [x86_64] + => ruby-1.9.1-p243 [x86_64] + ruby-1.9.2-preview3 [x86_64] + + jruby: + + jruby-1.3.1 [x86_64] + jruby-1.4.0RC3 [x86_64] + + ree: + + ree-1.8.6-20090610 [x86_64] + ree-1.8.7-20090928 [x86_64] + + +We can run the ruby program 'test.rb' against all versions of ruby installed by RVM very simply: + +∴ rvm ruby test.rb + + jruby-1.3.1: jruby 1.3.1 (ruby 1.8.6p287) (2009-06-15 2fd6c3d) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_15) [x86_64-java] + + patchlevel: 287, release_date: 2009-06-15, ruby_version: 1.8.6, ruby_platform: java + + + jruby-1.4.0RC3: jruby 1.4.0RC3 (ruby 1.8.7 patchlevel 174) (2009-09-30 80c263b) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_15) [x86_64-java] + + patchlevel: 174, release_date: 2009-09-30, ruby_version: 1.8.7, ruby_platform: java + + + ree-1.8.6-20090610: ruby 1.8.6 (2008-08-11 patchlevel 287) [i686-darwin10.0.0] Ruby Enterprise Edition 20090610 + + patchlevel: 287, release_date: 2008-08-11, ruby_version: 1.8.6, ruby_platform: i686-darwin10.0.0 + + + ree-1.8.7-20090928: ruby 1.8.7 (2009-06-12 patchlevel 174) [i686-darwin10.0.0], MBARI 0x6770, Ruby Enterprise Edition 20090928 + + patchlevel: 174, release_date: 2009-06-12, ruby_version: 1.8.7, ruby_platform: i686-darwin10.0.0 + + + ruby-1.8.6-p383: ruby 1.8.6 (2009-08-04 patchlevel 383) [i686-darwin10.0.0] + + patchlevel: 383, release_date: 2009-08-04, ruby_version: 1.8.6, ruby_platform: i686-darwin10.0.0 + + + ruby-1.8.7-p174: ruby 1.8.7 (2009-06-12 patchlevel 174) [i686-darwin10.0.0] + + patchlevel: 174, release_date: 2009-06-12, ruby_version: 1.8.7, ruby_platform: i686-darwin10.0.0 + + + ruby-1.9.1-head: ruby 1.9.2dev (2009-09-26 trunk 25103) [x86_64-darwin10.0.0] + + patchlevel: -1, release_date: 2009-09-26, ruby_version: 1.9.2, ruby_platform: x86_64-darwin10.0.0 + + + ruby-1.9.1-p243: ruby 1.9.1p243 (2009-07-16 revision 24175) [i386-darwin10.0.0] + + patchlevel: 243, release_date: 2009-07-16, ruby_version: 1.9.1, ruby_platform: i386-darwin10.0.0 + + + ruby-1.9.2-preview3: ruby 1.9.2dev (2010-05-31 revision 28117) [x86_64-darwin10.3.0] + + patchlevel: -1, release_date: 2010-05-31, ruby_version: 1.9.2, ruby_platform: x86_64-darwin10.3.0 + + ree-1.8.7-20090928: ruby 1.8.7 (2009-06-12 patchlevel 174) [i686-darwin10.0.0], MBARI 0x6770, Ruby Enterprise Edition 20090928 + + patchlevel: 174, release_date: 2009-06-12, ruby_version: 1.8.7, ruby_platform: i686-darwin10.0.0 + +If we want we can also restrict the above to a subset of named top level selections: + + ∴ rvm 1.9.1,1.8.7,jruby test.rb + ... diff --git a/help/rvmrc b/help/rvmrc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/specs b/help/specs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/srcdir b/help/srcdir new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/tests b/help/tests new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/uninstall b/help/uninstall new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/update b/help/update new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/use b/help/use new file mode 100644 index 0000000000..e69de29bb2 diff --git a/help/wrapper b/help/wrapper new file mode 100644 index 0000000000..820ac4cdad --- /dev/null +++ b/help/wrapper @@ -0,0 +1,41 @@ + +∴ rvm wrapper [ruby_string] [wrapper_prefix] [binary[ binary[ ...]]] + +Where ruby_string is the ruby version and gemset combination to wrap, +wrapper prefix is what to prepend to the name of the generated wrapper +binaries and binaries is the names of the binaries you wish to provide +a wrapper for (e.g. gem). + +When no binaries are provided, rvm will by default generate wrappers for +ruby, gem, rake, irb, rdoc, ri, and testrb. + +Examples: + +If you wish to provide an environment-specific wrapper for rspec with a +rails 3 gemset, you could do: + + ∴ rvm --create ree@rails3 + ∴ rvm wrapper ree@rails3 r3 spec + +Which would add r3_spec with the specified environment to your the bin +directory where you installed rvm. + +Alternatively, if you do: + + ∴ rvm wrapper ruby-1.9.2-head + +It will create binaries named ruby,gem, rake, irb, rdoc, ri and tesrb +in the rvm bin directory. + +Finally, to show another real and common use, you can use wrapper +to generate ruby executables and gems for passenger to use. Namely: + + ∴ rvm use ree@rails3 --passenger + +is equivelant to: + + ∴ rvm use ree@rails3 + ∴ rvm wrapper ree@rails3 passenger + +Which creates passenger_* binaries in the rvm bin directory using +ree and the rails3 gemset. diff --git a/lib/VERSION.yml b/lib/VERSION.yml index 681eb0acbb..299eb833b7 100644 --- a/lib/VERSION.yml +++ b/lib/VERSION.yml @@ -1,4 +1,4 @@ --- :major: 0 :minor: 1 -:patch: 22 +:patch: 42 diff --git a/lib/rvm.rb b/lib/rvm.rb index 6eb284c68d..761432d3d0 100644 --- a/lib/rvm.rb +++ b/lib/rvm.rb @@ -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 _ - 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 RVM::Environment#. +# +# == 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 diff --git a/lib/rvm/capistrano.rb b/lib/rvm/capistrano.rb new file mode 100644 index 0000000000..8443b54ce8 --- /dev/null +++ b/lib/rvm/capistrano.rb @@ -0,0 +1,45 @@ +# Recipes for using RVM on a server with capistrano. + +unless Capistrano::Configuration.respond_to?(:instance) + abort "rvm/capistrano requires Capistrano >= 2." +end + +Capistrano::Configuration.instance(true).load do + + # Taken from the capistrano code. + def _cset(name, *args, &block) + unless exists?(name) + set(name, *args, &block) + end + end + + set :default_shell do + shell = File.join(rvm_bin_path, "rvm-shell") + ruby = rvm_ruby_string.to_s.strip + shell = "#{shell} '#{ruby}'" unless ruby.empty? + shell + end + + # Let users set the type of their rvm install. + _cset(:rvm_type, :system) + + # Let users override the rvm_bin_path + _cset(:rvm_bin_path) do + case rvm_type + when :system_wide, :root, :system + "/usr/local/bin" + when :local, :user, :default + "$HOME/.rvm/bin" + end + end + + # Use the default ruby. + _cset(:rvm_ruby_string, "default") + +end + +# E.g, to use ree and rails 3: +# +# require 'rvm/capistrano' +# set :rvm_ruby_string, "ree@rails3" +# diff --git a/lib/rvm/environment.rb b/lib/rvm/environment.rb new file mode 100644 index 0000000000..95822913b2 --- /dev/null +++ b/lib/rvm/environment.rb @@ -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 tools info).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 ||= 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, 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 diff --git a/lib/rvm/environment/alias.rb b/lib/rvm/environment/alias.rb new file mode 100644 index 0000000000..0c86a420e5 --- /dev/null +++ b/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 diff --git a/lib/rvm/environment/cleanup.rb b/lib/rvm/environment/cleanup.rb new file mode 100644 index 0000000000..1de95689d7 --- /dev/null +++ b/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 diff --git a/lib/rvm/environment/configuration.rb b/lib/rvm/environment/configuration.rb new file mode 100644 index 0000000000..ac3124e506 --- /dev/null +++ b/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 diff --git a/lib/rvm/environment/env.rb b/lib/rvm/environment/env.rb new file mode 100644 index 0000000000..445e8bcce2 --- /dev/null +++ b/lib/rvm/environment/env.rb @@ -0,0 +1,52 @@ +module RVM + class Environment + + # Returns the contents of the env file. + def env_contents + rvm(:env).stdout + end + + # Returns the path to the env file + def env_path + rvm(:env, :path => true).stdout.strip + 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 + 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 diff --git a/lib/rvm/environment/gemset.rb b/lib/rvm/environment/gemset.rb new file mode 100644 index 0000000000..3ceecb1aa9 --- /dev/null +++ b/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_intial + 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 = result[:rvm_gemset_name] + @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_export 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 diff --git a/lib/rvm/environment/info.rb b/lib/rvm/environment/info.rb new file mode 100644 index 0000000000..c3f81cf91c --- /dev/null +++ b/lib/rvm/environment/info.rb @@ -0,0 +1,13 @@ +require 'yaml' + +module RVM + class Environment + + 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 diff --git a/lib/rvm/environment/list.rb b/lib/rvm/environment/list.rb new file mode 100644 index 0000000000..96773663d6 --- /dev/null +++ b/lib/rvm/environment/list.rb @@ -0,0 +1,124 @@ +module RVM + class Environment + + # Returns a raw array list of ruby + gemset combinations. + def list_gemsets + normalize_listing_output rvm(:list, :gemsets, :strings).stdout + end + + # Returns a raw array list of installed ruby strings, including aliases. + def list_strings + normalize_listing_output rvm(:list, :strings).stdout.tr(' ', "\n") + end + + # Lists the default ruby (minus gemset) + 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 diff --git a/lib/rvm/environment/rubies.rb b/lib/rvm/environment/rubies.rb new file mode 100644 index 0000000000..7fa924c578 --- /dev/null +++ b/lib/rvm/environment/rubies.rb @@ -0,0 +1,50 @@ +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. + 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 diff --git a/lib/rvm/environment/sets.rb b/lib/rvm/environment/sets.rb new file mode 100644 index 0000000000..1ffb1328b0 --- /dev/null +++ b/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 diff --git a/lib/rvm/environment/tools.rb b/lib/rvm/environment/tools.rb new file mode 100644 index 0000000000..0800e099ff --- /dev/null +++ b/lib/rvm/environment/tools.rb @@ -0,0 +1,41 @@ +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) + normalize rvm(:tools, "path-identifier", path.to_s).stdout + 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 + + end + + end +end diff --git a/lib/rvm/environment/utility.rb b/lib/rvm/environment/utility.rb new file mode 100644 index 0000000000..e2e0353778 --- /dev/null +++ b/lib/rvm/environment/utility.rb @@ -0,0 +1,167 @@ +module RVM + class Environment + + PREFIX_OPTIONS = [:trace, :json, :yaml] + + # 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 + + # 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_ruby_string] + result[:rvm_ruby_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 { |l| l.strip }.reject { |l| l.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 { |v| normalize_option_value(v) }.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] + ENV['BUNDLE_PATH'] = result[:BUNDLE_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 diff --git a/lib/rvm/environment/wrapper.rb b/lib/rvm/environment/wrapper.rb new file mode 100644 index 0000000000..c2df318b78 --- /dev/null +++ b/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 diff --git a/lib/rvm/errors.rb b/lib/rvm/errors.rb new file mode 100644 index 0000000000..93e8d5df05 --- /dev/null +++ b/lib/rvm/errors.rb @@ -0,0 +1,28 @@ +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 occured 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 + +end diff --git a/lib/rvm/open4.rb b/lib/rvm/open4.rb deleted file mode 100644 index 3452472e7a..0000000000 --- a/lib/rvm/open4.rb +++ /dev/null @@ -1,395 +0,0 @@ -# vim: ts=2:sw=2:sts=2:et:fdm=marker -# Author: Ara T. Howard -# Gem: open4 -require 'fcntl' -require 'timeout' -require 'thread' - -module Open4 -#--{{{ - VERSION = '0.9.6' - def self.version() VERSION end - - class Error < ::StandardError; end - - def popen4(*cmd, &b) -#--{{{ - pw, pr, pe, ps = IO.pipe, IO.pipe, IO.pipe, IO.pipe - - verbose = $VERBOSE - begin - $VERBOSE = nil - ps.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) - - cid = fork { - pw.last.close - STDIN.reopen pw.first - pw.first.close - - pr.first.close - STDOUT.reopen pr.last - pr.last.close - - pe.first.close - STDERR.reopen pe.last - pe.last.close - - STDOUT.sync = STDERR.sync = true - - begin - exec(*cmd) - raise 'forty-two' - rescue Exception => e - Marshal.dump(e, ps.last) - ps.last.flush - end - ps.last.close unless (ps.last.closed?) - exit! - } - ensure - $VERBOSE = verbose - end - - [pw.first, pr.last, pe.last, ps.last].each{|fd| fd.close} - - begin - e = Marshal.load ps.first - raise(Exception === e ? e : "unknown failure!") - rescue EOFError # If we get an EOF error, then the exec was successful - 42 - ensure - ps.first.close - end - - pw.last.sync = true - - pi = [pw.last, pr.first, pe.first] - - if b - begin - b[cid, *pi] - Process.waitpid2(cid).last - ensure - pi.each{|fd| fd.close unless fd.closed?} - end - else - [cid, pw.last, pr.first, pe.first] - end -#--}}} - end - alias open4 popen4 - module_function :popen4 - module_function :open4 - - class SpawnError < Error -#--{{{ - attr 'cmd' - attr 'status' - attr 'signals' - def exitstatus - @status.exitstatus - end - def initialize cmd, status - @cmd, @status = cmd, status - @signals = {} - if status.signaled? - @signals['termsig'] = status.termsig - @signals['stopsig'] = status.stopsig - end - sigs = @signals.map{|k,v| "#{ k }:#{ v.inspect }"}.join(' ') - super "cmd <#{ cmd }> failed with status <#{ exitstatus.inspect }> signals <#{ sigs }>" - end -#--}}} - end - - class ThreadEnsemble -#--{{{ - attr 'threads' - - def initialize cid - @cid, @threads, @argv, @done, @running = cid, [], [], Queue.new, false - @killed = false - end - - def add_thread *a, &b - @running ? raise : (@argv << [a, b]) - end - -# -# take down process more nicely -# - def killall - c = Thread.critical - return nil if @killed - Thread.critical = true - (@threads - [Thread.current]).each{|t| t.kill rescue nil} - @killed = true - ensure - Thread.critical = c - end - - def run - @running = true - - begin - @argv.each do |a, b| - @threads << Thread.new(*a) do |*a| - begin - b[*a] - ensure - killall rescue nil if $! - @done.push Thread.current - end - end - end - rescue - killall - raise - ensure - all_done - end - - @threads.map{|t| t.value} - end - - def all_done - @threads.size.times{ @done.pop } - end -#--}}} - end - - def to timeout = nil -#--{{{ - Timeout.timeout(timeout){ yield } -#--}}} - end - module_function :to - - def new_thread *a, &b -#--{{{ - cur = Thread.current - Thread.new(*a) do |*a| - begin - b[*a] - rescue Exception => e - cur.raise e - end - end -#--}}} - end - module_function :new_thread - - def getopts opts = {} -#--{{{ - lambda do |*args| - keys, default, ignored = args - catch('opt') do - [keys].flatten.each do |key| - [key, key.to_s, key.to_s.intern].each do |key| - throw 'opt', opts[key] if opts.has_key?(key) - end - end - default - end - end -#--}}} - end - module_function :getopts - - def relay src, dst = nil, t = nil -#--{{{ - unless src.nil? - if src.respond_to? :gets - while buf = to(t){ src.gets } - dst << buf if dst - end - - elsif src.respond_to? :each - q = Queue.new - th = nil - - timer_set = lambda do |t| - th = new_thread{ to(t){ q.pop } } - end - - timer_cancel = lambda do |t| - th.kill if th rescue nil - end - - timer_set[t] - begin - src.each do |buf| - timer_cancel[t] - dst << buf if dst - timer_set[t] - end - ensure - timer_cancel[t] - end - - elsif src.respond_to? :read - buf = to(t){ src.read } - dst << buf if dst - - else - buf = to(t){ src.to_s } - dst << buf if dst - end - end -#--}}} - end - module_function :relay - - def spawn arg, *argv -#--{{{ - argv.unshift(arg) - opts = ((argv.size > 1 and Hash === argv.last) ? argv.pop : {}) - argv.flatten! - cmd = argv.join(' ') - - - getopt = getopts opts - - ignore_exit_failure = getopt[ 'ignore_exit_failure', getopt['quiet', false] ] - ignore_exec_failure = getopt[ 'ignore_exec_failure', !getopt['raise', true] ] - exitstatus = getopt[ %w( exitstatus exit_status status ) ] - stdin = getopt[ %w( stdin in i 0 ) << 0 ] - stdout = getopt[ %w( stdout out o 1 ) << 1 ] - stderr = getopt[ %w( stderr err e 2 ) << 2 ] - pid = getopt[ 'pid' ] - timeout = getopt[ %w( timeout spawn_timeout ) ] - stdin_timeout = getopt[ %w( stdin_timeout ) ] - stdout_timeout = getopt[ %w( stdout_timeout io_timeout ) ] - stderr_timeout = getopt[ %w( stderr_timeout ) ] - status = getopt[ %w( status ) ] - cwd = getopt[ %w( cwd dir ) ] - - exitstatus = - case exitstatus - when TrueClass, FalseClass - ignore_exit_failure = true if exitstatus - [0] - else - [*(exitstatus || 0)].map{|i| Integer i} - end - - stdin ||= '' if stdin_timeout - stdout ||= '' if stdout_timeout - stderr ||= '' if stderr_timeout - - started = false - - status = - begin - chdir(cwd) do - Timeout::timeout(timeout) do - popen4(*argv) do |c, i, o, e| - started = true - - %w( replace pid= << push update ).each do |msg| - break(pid.send(msg, c)) if pid.respond_to? msg - end - - te = ThreadEnsemble.new c - - te.add_thread(i, stdin) do |i, stdin| - relay stdin, i, stdin_timeout - i.close rescue nil - end - - te.add_thread(o, stdout) do |o, stdout| - relay o, stdout, stdout_timeout - end - - te.add_thread(e, stderr) do |o, stderr| - relay e, stderr, stderr_timeout - end - - te.run - end - end - end - rescue - raise unless(not started and ignore_exec_failure) - end - - raise SpawnError.new(cmd, status) unless - (ignore_exit_failure or (status.nil? and ignore_exec_failure) or exitstatus.include?(status.exitstatus)) - - status -#--}}} - end - module_function :spawn - - def chdir cwd, &block - return(block.call Dir.pwd) unless cwd - Dir.chdir cwd, &block - end - module_function :chdir - - def background arg, *argv -#--{{{ - require 'thread' - q = Queue.new - opts = { 'pid' => q, :pid => q } - case argv.last - when Hash - argv.last.update opts - else - argv.push opts - end - thread = Thread.new(arg, argv){|arg, argv| spawn arg, *argv} - sc = class << thread; self; end - sc.module_eval { - define_method(:pid){ @pid ||= q.pop } - define_method(:spawn_status){ @spawn_status ||= value } - define_method(:exitstatus){ @exitstatus ||= spawn_status.exitstatus } - } - thread -#--}}} - end - alias bg background - module_function :background - module_function :bg - - def maim pid, opts = {} -#--{{{ - getopt = getopts opts - sigs = getopt[ 'signals', %w(SIGTERM SIGQUIT SIGKILL) ] - suspend = getopt[ 'suspend', 4 ] - pid = Integer pid - existed = false - sigs.each do |sig| - begin - Process.kill sig, pid - existed = true - rescue Errno::ESRCH - return(existed ? nil : true) - end - return true unless alive? pid - sleep suspend - return true unless alive? pid - end - return(not alive?(pid)) -#--}}} - end - module_function :maim - - def alive pid -#--{{{ - pid = Integer pid - begin - Process.kill 0, pid - true - rescue Errno::ESRCH - false - end -#--}}} - end - alias alive? alive - module_function :alive - module_function :'alive?' -#--}}} -end - -def open4(*cmd, &b) cmd.size == 0 ? Open4 : Open4::popen4(*cmd, &b) end diff --git a/lib/rvm/rvm.rb b/lib/rvm/rvm.rb deleted file mode 100644 index 5e64573f4e..0000000000 --- a/lib/rvm/rvm.rb +++ /dev/null @@ -1,14 +0,0 @@ -module RVM - module InstanceMethods - def rvm(command, options = {}) - result = RVM::Shell.new(command) - [result.output, result.errors] - end - end - - def self.included(receiver) - receiver.send(:include, InstanceMethods) - end -end - -include RVM diff --git a/lib/rvm/shell.rb b/lib/rvm/shell.rb index 9d67d5186a..eb2f247c45 100644 --- a/lib/rvm/shell.rb +++ b/lib/rvm/shell.rb @@ -1,14 +1,25 @@ module RVM - class Shell - attr_reader :errors, :output - - def initialize(command) - @command = (command =~ /^rvm /) ? command : "rvm #{command}" - Open4::popen4("/bin/bash -l -c '#{@command.tr("'","\\'")}'") do |pid, stdin, stdout, stderr| - stdin.close - @output = stdout.readlines.join - @errors = stderr.readlines.join - end + # Provides Generic access to a more ruby-like shell interface. + # For more details, see AbstractWrapper. + module Shell + + autoload :AbstractWrapper, 'rvm/shell/abstract_wrapper' + autoload :SingleShotWrapper, 'rvm/shell/single_shot_wrapper' + # Current unimplemented + #autoload :PersistingWrapper, 'rvm/shell/persisting_wrapper' + autoload :TestWrapper, 'rvm/shell/test_wrapper' + autoload :Utility, 'rvm/shell/utility' + autoload :Result, '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 diff --git a/lib/rvm/shell/abstract_wrapper.rb b/lib/rvm/shell/abstract_wrapper.rb new file mode 100644 index 0000000000..61e58e25cd --- /dev/null +++ b/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 diff --git a/lib/rvm/shell/result.rb b/lib/rvm/shell/result.rb new file mode 100644 index 0000000000..280f917b8a --- /dev/null +++ b/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["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 diff --git a/lib/rvm/shell/shell_wrapper.sh b/lib/rvm/shell/shell_wrapper.sh new file mode 100644 index 0000000000..ff18e844b1 --- /dev/null +++ b/lib/rvm/shell/shell_wrapper.sh @@ -0,0 +1,10 @@ +# Prints an epilog to a shell command. +__rvm_show_command_epilog() { + local last_command_result="$?" + echo "---------------RVM-RESULTS-START---------------" + echo "---" + echo " exit_status: \"$last_command_result\"" + echo " environment:" + env | sed "s#'#\\'#" | sed -e 's#"#\\"#' -e "s#\\([^=]*\\)=\\(.*\\)# '\1': \"\2\"#" + echo "----------------RVM-RESULTS-END----------------" +} diff --git a/lib/rvm/shell/single_shot_wrapper.rb b/lib/rvm/shell/single_shot_wrapper.rb new file mode 100644 index 0000000000..74e9be93f7 --- /dev/null +++ b/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 diff --git a/lib/rvm/shell/utility.rb b/lib/rvm/shell/utility.rb new file mode 100644 index 0000000000..6cb197159f --- /dev/null +++ b/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 diff --git a/lib/rvm/version.rb b/lib/rvm/version.rb index dbcd3702aa..0b896e2b0c 100644 --- a/lib/rvm/version.rb +++ b/lib/rvm/version.rb @@ -1,15 +1,19 @@ +require 'yaml' + module RVM module Version - require "yaml" - - YAML = YAML.load_file("#{File.expand_path(File.dirname(__FILE__))}/../VERSION.yml") - - MAJOR = YAML[:major] - MINOR = YAML[:minor] - PATCH = YAML[:patch] + # YAML of raw version info + VERSION_YAML = YAML.load_file(File.expand_path("../VERSION.yml", File.dirname(__FILE__))) - STRING = "#{MAJOR}.#{MINOR}.#{PATCH}" + # Current major version of rvm + MAJOR = VERSION_YAML[:major] + # Current minor version of rvm + MINOR = VERSION_YAML[:minor] + # Current patch level of rvm + PATCH = VERSION_YAML[:patch] + # A String with the current rvm version + STRING = [MAJOR, MINOR, PATCH].join(".").freeze end end diff --git a/man/man1/rvm.1 b/man/man1/rvm.1 new file mode 100644 index 0000000000..4dca920219 --- /dev/null +++ b/man/man1/rvm.1 @@ -0,0 +1,385 @@ +'\" t +.\" Title: rvm +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.75.2 +.\" Date: 07/16/2010 +.\" Manual: [FIXME: manual] +.\" Source: [FIXME: source] +.\" Language: English +.\" +.TH "RVM" "1" "07/16/2010" "[FIXME: source]" "[FIXME: manual]" +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +rvm \- The Ruby Version Manager +.SH "SYNOPSIS" +.sp +\fBrvm\fR [\fIFLAGS\fR] [\fIOPTIONS\fR] \fIACTION\fR [\fIIMPLEMENTATION\fR[,\fIIMPLEMENTATION\fR[,\fI\&...\fR]] +.SH "DESCRIPTION" +.sp +RVM is a command line tool which allows us to easily install, manage and work with multiple ruby environments from interpreters to sets of gems\&. +.SH "FLAGS" +.PP +\fB\-\-head\fR +.RS 4 +with update, updates rvm to git head version\&. +.RE +.PP +\fB\-\-rubygems\fR +.RS 4 +with update, updates rubygems for selected ruby +.RE +.PP +\fB\-\-default\fR +.RS 4 +with ruby select, sets a default ruby for new shells\&. +.RE +.PP +\fB\-\-debug\fR +.RS 4 +Toggle debug mode on for very verbose output\&. +.RE +.PP +\fB\-\-trace\fR +.RS 4 +Toggle trace mode on to see EVERYTHING rvm is doing\&. +.RE +.PP +\fB\-\-force\fR +.RS 4 +Force install, removes old install & source before install\&. +.RE +.PP +\fB\-\-summary\fR +.RS 4 +Used with rubydo to print out a summary of the commands run\&. +.RE +.PP +\fB\-\-latest\fR +.RS 4 +with gemset \-\-dump skips version strings for latest gem\&. +.RE +.PP +\fB\-\-gems\fR +.RS 4 +with uninstall/remove removes gems with the interpreter\&. +.RE +.PP +\fB\-\-docs\fR +.RS 4 +with install, attempt to generate ri after installation\&. +.RE +.PP +\fB\-\-reconfigure\fR +.RS 4 +Force \&./configure on install even if Makefile already exists\&. +.RE +.SH "OPTIONS" +.PP +\fB\-v, \-\-version\fR +.RS 4 +Emit rvm version loaded for current shell\&. +.RE +.PP +\fB\-l, \-\-level\fR +.RS 4 +patch level to use with rvm use / install +.RE +.PP +\fB\-\-prefix\fR +.RS 4 +path for all rvm files (\fI~/\&.rvm/\fR), with trailing slash! +.RE +.PP +\fB\-\-bin\fR +.RS 4 +path for binaries to be placed (\fI~/\&.rvm/bin/\fR) +.RE +.PP +\fB\-\-source\fR +.RS 4 +src directory to use (\fI~/\&.rvm/src/\fR) +.RE +.PP +\fB\-\-archives\fR +.RS 4 +directory for downladed files (\fI~/\&.rvm/archives/\fR) +.RE +.PP +\fB\-S\fR +.RS 4 +Specify a script file to attempt to load and run (rubydo)\&. +.RE +.PP +\fB\-e\fR +.RS 4 +Execute code from the command line\&. +.RE +.PP +\fB\-G\fR +.RS 4 +root gem path to use +.RE +.PP +\fB\-\-gems\fR +.RS 4 +Used to set the +\fIgems_flag\fR, use with +\fIremove\fR +to remove gems\&. +.RE +.PP +\fB\-\-archive\fR +.RS 4 +Used to set the +\fIarchive_flag\fR, use with +\fIremove\fR +to remove archive\&. +.RE +.PP +\fB\-\-patch\fR, \fB\-\-patches\fR +.RS 4 +With any ruby build from source, allows you to specify patch paths and patch names to be applied prior to building\&. Values should be a relative / absolute path to a patch or the name of known patch / patchset\&. Optionally, paths or names may be followed by +\fI%someinteger\fR +\- e\&.g\&. +\fI\-\-patches mypatch%2\fR +\- where the number following the % specifies the value of the \-p argument to patch, defaulting to two\&. +.RE +.PP +\fB\-C, \-\-configure\fR +.RS 4 +custom configure options\&. If you need to pass several configure options then append them comma separated: +\fI\-C \-\-\&...,\-\-\&...,\-\-\&...\fR\&. +.RE +.PP +\fB\-\-nice\fR +.RS 4 +process niceness (for slow computers, default 0) +.RE +.PP +\fB\-\-ree\-options\fR +.RS 4 +Options passed directly to ree\(cqs +\fI\&./installer\fR +on the command line\&. +.RE +.SH "ACTIONS" +.PP +\fBusage\fR +.RS 4 +Show this usage information\&. +.RE +.PP +\fBversion\fR +.RS 4 +Show the rvm version installed in rvm_path\&. +.RE +.PP +\fBuse\fR +.RS 4 +Setup current shell to use a specific ruby version\&. +.RE +.PP +\fBreload\fR +.RS 4 +Reload rvm source itself (useful after changing rvm source)\&. +.RE +.PP +\fBenv\fR +.RS 4 +Displays information about an environment specified but the given ruby string\&. Useful for getting a sourceable path or an evaluatable set of shell variable declarations\&. +.RE +.PP +\fBimplode\fR +.RS 4 +(seppuku) removes the rvm installation completely\&. This means everything in $rvm_path (\fI~/\&.rvm\fR)\&. This does not touch your profiles, which is why there is an if around the sourcing +\fIscripts/rvm\fR\&. +.RE +.PP +\fBupdate\fR +.RS 4 +Upgrades rvm to the latest version\&. (If you experience bugs try this first with \-\-head)\&. +.RE +.PP +\fBreset\fR +.RS 4 +Remove current and stored default & system settings\&. (If you experience odd behavior try this second)\&. +.RE +.PP +\fBinfo\fR +.RS 4 +Show the +\fBcurrent\fR +environment information for current ruby\&. +.RE +.PP +\fBdebug\fR +.RS 4 +Show info plus additional information for common issues\&. +.RE +.PP +\fBinstall\fR +.RS 4 +Install one or many ruby versions\&. +http://rvm\&.beginrescueend\&.com/rubies/installing/ +.RE +.PP +\fBuninstall\fR +.RS 4 +Uninstall one or many ruby versions, leaves their sources\&. +.RE +.PP +\fBremove\fR +.RS 4 +Uninstall one or many ruby versions and remove their sources\&. +.RE +.PP +\fBwrapper\fR +.RS 4 +Generates a set of wrapper executables for a given ruby with the specified ruby and gemset combination\&. Used under the hood for passenger support and the like\&. +.RE +.PP +\fBruby\fR +.RS 4 +Runs a named ruby file against specified and/or all rubies\&. +.RE +.PP +\fBgem\fR +.RS 4 +Runs a gem command using selected ruby\(cqs +\fIgem\fR\&. +.RE +.PP +\fBrake\fR +.RS 4 +Runs a rake task against specified and/or all rubies\&. +.RE +.PP +\fBtests\fR +.RS 4 +Runs +\fIrake test\fR +across selected ruby versions\&. +.RE +.PP +\fBspecs\fR +.RS 4 +Runs +\fIrake spec\fR +across selected ruby versions\&. +.RE +.PP +\fBmonitor\fR +.RS 4 +Monitor cwd for testing, run +\fIrake {spec,test}\fR +on changes\&. +.RE +.PP +\fBgemset\fR +.RS 4 +gemsets: +http://rvm\&.beginrescueend\&.com/gemsets/ +.RE +.PP +\fBgemdir\fR +.RS 4 +Display the path to the current gem directory (\fI$GEM_HOME\fR)\&. +.RE +.PP +\fBsrcdir\fR +.RS 4 +Display the path to rvm source directory (may be yanked)\&. +.RE +.PP +\fBfetch\fR +.RS 4 +Performs an archive / src fetch only of the selected ruby\&. +.RE +.PP +\fBlist\fR +.RS 4 +Show currently installed rubies, interactive output\&. +http://rvm\&.beginrescueend\&.com/rubies/list/ +.RE +.PP +\fBpackage\fR +.RS 4 +Install a dependency package {readline,iconv,zlib,openssl}\&. +http://rvm\&.beginrescueend\&.com/packages/ +.RE +.PP +\fBnotes\fR +.RS 4 +Display notes, with operating system specifics\&. +.RE +.SH "IMPLEMENTATION" +.PP +\fBruby\fR +.RS 4 +MRI/YARV Ruby (The Gold Standard) {1\&.8\&.6,1\&.8\&.7,1\&.9\&.1,1\&.9\&.2\&...} +.RE +.PP +\fBjruby\fR +.RS 4 +JRuby, Ruby interpreter on the Java Virtual Machine\&. +.RE +.PP +\fBrbx\fR +.RS 4 +Rubinius +.RE +.PP +\fBree\fR +.RS 4 +Ruby Enterprise Edition, MRI Ruby with several custom patches for performance, stability, and memory\&. +.RE +.PP +\fBmacruby\fR +.RS 4 +MacRuby, insanely fast, can make real apps (Mac OS X Only)\&. +.RE +.PP +\fBmaglev\fR +.RS 4 +GemStone Ruby, awesome persistent ruby object store\&. +.RE +.PP +\fBironruby\fR +.RS 4 +IronRuby, NOT supported yet\&. Looking for volunteers to help\&. +.RE +.PP +\fBmput\fR +.RS 4 +shyouhei(mput)\'s github repository, popular in Japan :) +.RE +.PP +\fBsystem\fR +.RS 4 +Use the system ruby (eg\&. pre\-rvm state)\&. +.RE +.PP +\fBdefault\fR +.RS 4 +Use rvm set default ruby and system if it hasn\(cqt been set\&. +http://rvm\&.beginrescueend\&.com/rubies/default/ +.RE +.SH "RESOURCES" +.sp +Main web site +.sp +Online issue\-tracker +.SH "COPYING" +.sp +Copyright (c) 2009 Wayne E\&. Seguin +.sp +See LICENCE file for details\&. diff --git a/man/man1/rvm.1.gz b/man/man1/rvm.1.gz new file mode 100644 index 0000000000..74136c6b54 Binary files /dev/null and b/man/man1/rvm.1.gz differ diff --git a/patches/ree/1.8.7/readline-fix.diff b/patches/ree/1.8.7/readline-fix.diff new file mode 120000 index 0000000000..84ed3dedea --- /dev/null +++ b/patches/ree/1.8.7/readline-fix.diff @@ -0,0 +1 @@ +../../ruby/1.8.7/readline-fix.diff \ No newline at end of file diff --git a/patches/ruby/1.8.4/railsbench.patch b/patches/ruby/1.8.4/railsbench.patch new file mode 100644 index 0000000000..63ac19a97b --- /dev/null +++ b/patches/ruby/1.8.4/railsbench.patch @@ -0,0 +1,516 @@ +--- gc.c.orig 2005-12-16 05:58:51.000000000 +0100 ++++ gc.c 2006-07-16 14:46:55.890625000 +0200 +@@ -22,8 +22,16 @@ + #include + #include + ++#ifdef _WIN32 ++#include ++#else ++#include ++#endif ++ + #ifdef HAVE_SYS_TIME_H + #include ++#elif defined(_WIN32) ++#include + #endif + + #ifdef HAVE_SYS_RESOURCE_H +@@ -175,8 +183,17 @@ + RUBY_CRITICAL(free(x)); + } + ++#if HAVE_LONG_LONG ++#define GC_TIME_TYPE LONG_LONG ++#else ++#define GC_TIME_TYPE long ++#endif ++ + extern int ruby_in_compile; + static int dont_gc; ++static int gc_statistics = 0; ++static GC_TIME_TYPE gc_time = 0; ++static int gc_collections = 0; + static int during_gc; + static int need_call_final = 0; + static st_table *finalizer_table = 0; +@@ -211,7 +228,7 @@ + * Disables garbage collection, returning true if garbage + * collection was already disabled. + * +- * GC.disable #=> false ++ * GC.disable #=> false or true + * GC.disable #=> true + * + */ +@@ -225,6 +242,104 @@ + return old; + } + ++/* ++ * call-seq: ++ * GC.enable_stats => true or false ++ * ++ * Enables garbage collection statistics, returning true if garbage ++ * collection statistics was already enabled. ++ * ++ * GC.enable_stats #=> false or true ++ * GC.enable_stats #=> true ++ * ++ */ ++ ++VALUE ++rb_gc_enable_stats() ++{ ++ int old = gc_statistics; ++ gc_statistics = Qtrue; ++ return old; ++} ++ ++/* ++ * call-seq: ++ * GC.disable_stats => true or false ++ * ++ * Disables garbage collection statistics, returning true if garbage ++ * collection statistics was already disabled. ++ * ++ * GC.disable_stats #=> false or true ++ * GC.disable_stats #=> true ++ * ++ */ ++ ++VALUE ++rb_gc_disable_stats() ++{ ++ int old = gc_statistics; ++ gc_statistics = Qfalse; ++ return old; ++} ++ ++/* ++ * call-seq: ++ * GC.clear_stats => nil ++ * ++ * Clears garbage collection statistics, returning nil. This resets the number ++ * of collections (GC.collections) and the time used (GC.time) to 0. ++ * ++ * GC.clear_stats #=> nil ++ * ++ */ ++ ++VALUE ++rb_gc_clear_stats() ++{ ++ gc_collections = 0; ++ gc_time = 0; ++ return Qnil; ++} ++ ++/* ++ * call-seq: ++ * GC.collections => Integer ++ * ++ * Returns the number of garbage collections performed while GC statistics collection ++ * was enabled. ++ * ++ * GC.collections #=> 35 ++ * ++ */ ++ ++VALUE ++rb_gc_collections() ++{ ++ return INT2NUM(gc_collections); ++} ++ ++/* ++ * call-seq: ++ * GC.time => Integer ++ * ++ * Returns the time spent during garbage collection while GC statistics collection ++ * was enabled (in micro seconds). ++ * ++ * GC.time #=> 20000 ++ * ++ */ ++ ++VALUE ++rb_gc_time() ++{ ++#if HAVE_LONG_LONG ++ return LL2NUM(gc_time); ++#else ++ return LONG2NUM(gc_time); ++#endif ++} ++ ++ + VALUE rb_mGC; + + static struct gc_list { +@@ -308,7 +423,7 @@ + static RVALUE *freelist = 0; + static RVALUE *deferred_final_list = 0; + +-#define HEAPS_INCREMENT 10 ++static int heaps_increment = 10; + static struct heaps_slot { + RVALUE *slot; + int limit; +@@ -316,13 +431,141 @@ + static int heaps_length = 0; + static int heaps_used = 0; + +-#define HEAP_MIN_SLOTS 10000 +-static int heap_slots = HEAP_MIN_SLOTS; ++static int heap_min_slots = 10000; ++static int heap_slots = 10000; + +-#define FREE_MIN 4096 ++static int heap_free_min = 4096; ++ ++static long initial_malloc_limit = GC_MALLOC_LIMIT; ++ ++static int verbose_gc_stats = Qfalse; ++ ++static FILE* gc_data_file = NULL; + + static RVALUE *himem, *lomem; + ++static void set_gc_parameters() ++{ ++ char *gc_stats_ptr, *min_slots_ptr, *free_min_ptr, ++ *heap_incr_ptr, *malloc_limit_ptr, *gc_heap_file_ptr; ++ ++ gc_data_file = stderr; ++ ++ gc_stats_ptr = getenv("RUBY_GC_STATS"); ++ if (gc_stats_ptr != NULL) { ++ int gc_stats_i = atoi(gc_stats_ptr); ++ if (gc_stats_i > 0) { ++ verbose_gc_stats = Qtrue; ++ } ++ } ++ ++ gc_heap_file_ptr = getenv("RUBY_GC_DATA_FILE"); ++ if (gc_heap_file_ptr != NULL) { ++ FILE* data_file = fopen(gc_heap_file_ptr, "w"); ++ if (data_file != NULL) { ++ gc_data_file = data_file; ++ } ++ else { ++ fprintf(stderr, ++ "can't open gc log file %s for writing, using default\n", gc_heap_file_ptr); ++ } ++ } ++ ++ min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS"); ++ if (min_slots_ptr != NULL) { ++ int min_slots_i = atoi(min_slots_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_MIN_SLOTS=%s\n", min_slots_ptr); ++ } ++ if (min_slots_i > 0) { ++ heap_slots = min_slots_i; ++ heap_min_slots = min_slots_i; ++ } ++ } ++ ++ free_min_ptr = getenv("RUBY_HEAP_FREE_MIN"); ++ if (free_min_ptr != NULL) { ++ int free_min_i = atoi(free_min_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_FREE_MIN=%s\n", free_min_ptr); ++ } ++ if (free_min_i > 0) { ++ heap_free_min = free_min_i; ++ } ++ } ++ ++ heap_incr_ptr = getenv("RUBY_HEAP_INCREMENT"); ++ if (heap_incr_ptr != NULL) { ++ int heap_incr_i = atoi(heap_incr_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_INCREMENT=%s\n", heap_incr_ptr); ++ } ++ if (heap_incr_i > 0) { ++ heaps_increment = heap_incr_i; ++ } ++ } ++ ++ malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT"); ++ if (malloc_limit_ptr != NULL) { ++ int malloc_limit_i = atol(malloc_limit_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_GC_MALLOC_LIMIT=%s\n", malloc_limit_ptr); ++ } ++ if (malloc_limit_i > 0) { ++ initial_malloc_limit = malloc_limit_i; ++ } ++ } ++} ++ ++/* ++ * call-seq: ++ * GC.dump => nil ++ * ++ * dumps information about the current GC data structures to the GC log file ++ * ++ * GC.dump #=> nil ++ * ++ */ ++ ++VALUE ++rb_gc_dump() ++{ ++ int i; ++ ++ for (i = 0; i < heaps_used; i++) { ++ int heap_size = heaps[i].limit; ++ fprintf(gc_data_file, "HEAP[%2d]: size=%7d\n", i, heap_size); ++ } ++ ++ return Qnil; ++} ++ ++/* ++ * call-seq: ++ * GC.log String => String ++ * ++ * Logs string to the GC data file and returns it. ++ * ++ * GC.log "manual GC call" #=> "manual GC call" ++ * ++ */ ++ ++VALUE ++rb_gc_log(self, original_str) ++ VALUE self, original_str; ++{ ++ if (original_str == Qnil) { ++ fprintf(gc_data_file, "\n"); ++ } ++ else { ++ VALUE str = StringValue(original_str); ++ char *p = RSTRING(str)->ptr; ++ fprintf(gc_data_file, "%s\n", p); ++ } ++ return original_str; ++} ++ ++ + static void + add_heap() + { +@@ -333,7 +576,7 @@ + struct heaps_slot *p; + int length; + +- heaps_length += HEAPS_INCREMENT; ++ heaps_length += heaps_increment; + length = heaps_length*sizeof(struct heaps_slot); + RUBY_CRITICAL( + if (heaps_used > 0) { +@@ -350,10 +593,10 @@ + RUBY_CRITICAL(p = heaps[heaps_used].slot = (RVALUE*)malloc(sizeof(RVALUE)*heap_slots)); + heaps[heaps_used].limit = heap_slots; + if (p == 0) { +- if (heap_slots == HEAP_MIN_SLOTS) { ++ if (heap_slots == heap_min_slots) { + rb_memerror(); + } +- heap_slots = HEAP_MIN_SLOTS; ++ heap_slots = heap_min_slots; + continue; + } + break; +@@ -1031,6 +1274,39 @@ + } + } + ++static char* obj_type(int tp) ++{ ++ switch (tp) { ++ case T_NIL : return "NIL"; ++ case T_OBJECT : return "OBJECT"; ++ case T_CLASS : return "CLASS"; ++ case T_ICLASS : return "ICLASS"; ++ case T_MODULE : return "MODULE"; ++ case T_FLOAT : return "FLOAT"; ++ case T_STRING : return "STRING"; ++ case T_REGEXP : return "REGEXP"; ++ case T_ARRAY : return "ARRAY"; ++ case T_FIXNUM : return "FIXNUM"; ++ case T_HASH : return "HASH"; ++ case T_STRUCT : return "STRUCT"; ++ case T_BIGNUM : return "BIGNUM"; ++ case T_FILE : return "FILE"; ++ ++ case T_TRUE : return "TRUE"; ++ case T_FALSE : return "FALSE"; ++ case T_DATA : return "DATA"; ++ case T_MATCH : return "MATCH"; ++ case T_SYMBOL : return "SYMBOL"; ++ ++ case T_BLKTAG : return "BLKTAG"; ++ case T_UNDEF : return "UNDEF"; ++ case T_VARMAP : return "VARMAP"; ++ case T_SCOPE : return "SCOPE"; ++ case T_NODE : return "NODE"; ++ default: return "____"; ++ } ++} ++ + static void + gc_sweep() + { +@@ -1039,6 +1315,15 @@ + int i; + unsigned long live = 0; + ++ unsigned long really_freed = 0; ++ int free_counts[256]; ++ int live_counts[256]; ++ int do_gc_stats = gc_statistics & verbose_gc_stats; ++ ++ if (do_gc_stats) { ++ for (i = 0 ; i< 256; i++) { free_counts[i] = live_counts[i] = 0; } ++ } ++ + if (ruby_in_compile && ruby_parser_stack_on_heap()) { + /* should not reclaim nodes during compilation + if yacc's semantic stack is not allocated on machine stack */ +@@ -1070,6 +1355,9 @@ + if (!(p->as.basic.flags & FL_MARK)) { + if (p->as.basic.flags) { + obj_free((VALUE)p); ++ if (do_gc_stats) { ++ really_freed++; ++ } + } + if (need_call_final && FL_TEST(p, FL_FINALIZE)) { + p->as.free.flags = FL_MARK; /* remain marked */ +@@ -1077,6 +1365,12 @@ + final_list = p; + } + else { ++ if (do_gc_stats) { ++ int obt = p->as.basic.flags & T_MASK; ++ if (obt) { ++ free_counts[obt]++; ++ } ++ } + p->as.free.flags = 0; + p->as.free.next = freelist; + freelist = p; +@@ -1090,10 +1384,13 @@ + else { + RBASIC(p)->flags &= ~FL_MARK; + live++; ++ if (do_gc_stats) { ++ live_counts[RANY((VALUE)p)->as.basic.flags & T_MASK]++; ++ } + } + p++; + } +- if (n == heaps[i].limit && freed > FREE_MIN) { ++ if (n == heaps[i].limit && freed > heap_free_min) { + RVALUE *pp; + + heaps[i].limit = 0; +@@ -1108,14 +1405,28 @@ + } + if (malloc_increase > malloc_limit) { + malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed); +- if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT; ++ if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit; + } + malloc_increase = 0; +- if (freed < FREE_MIN) { ++ if (freed < heap_free_min) { + add_heap(); + } + during_gc = 0; + ++ if (do_gc_stats) { ++ fprintf(gc_data_file, "objects processed: %.7d\n", live+freed); ++ fprintf(gc_data_file, "live objects : %.7d\n", live); ++ fprintf(gc_data_file, "freelist objects : %.7d\n", freed - really_freed); ++ fprintf(gc_data_file, "freed objects : %.7d\n", really_freed); ++ for(i=0; i<256; i++) { ++ if (free_counts[i]>0) { ++ fprintf(gc_data_file, ++ "kept %.7d / freed %.7d objects of type %s\n", ++ live_counts[i], free_counts[i], obj_type(i)); ++ } ++ } ++ } ++ + /* clear finalization list */ + if (final_list) { + deferred_final_list = final_list; +@@ -1311,6 +1622,7 @@ + struct gc_list *list; + struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */ + jmp_buf save_regs_gc_mark; ++ struct timeval gctv1, gctv2; + SET_STACK_END; + + #ifdef HAVE_NATIVETHREAD +@@ -1327,6 +1639,14 @@ + if (during_gc) return; + during_gc++; + ++ if (gc_statistics) { ++ gc_collections++; ++ gettimeofday(&gctv1, NULL); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "Garbage collection started\n"); ++ } ++ } ++ + init_mark_stack(); + + /* mark frame stack */ +@@ -1409,6 +1729,17 @@ + } + } + gc_sweep(); ++ ++ if (gc_statistics) { ++ GC_TIME_TYPE musecs_used; ++ gettimeofday(&gctv2, NULL); ++ musecs_used = ((GC_TIME_TYPE)(gctv2.tv_sec - gctv1.tv_sec) * 1000000) + (gctv2.tv_usec - gctv1.tv_usec); ++ gc_time += musecs_used; ++ ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "GC time: %d msec\n", musecs_used / 1000); ++ } ++ } + } + + void +@@ -1522,6 +1853,7 @@ + if (!rb_gc_stack_start) { + Init_stack(0); + } ++ set_gc_parameters(); + add_heap(); + } + +@@ -1920,6 +2252,14 @@ + rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0); + rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0); + ++ rb_define_singleton_method(rb_mGC, "enable_stats", rb_gc_enable_stats, 0); ++ rb_define_singleton_method(rb_mGC, "disable_stats", rb_gc_disable_stats, 0); ++ rb_define_singleton_method(rb_mGC, "clear_stats", rb_gc_clear_stats, 0); ++ rb_define_singleton_method(rb_mGC, "collections", rb_gc_collections, 0); ++ rb_define_singleton_method(rb_mGC, "time", rb_gc_time, 0); ++ rb_define_singleton_method(rb_mGC, "dump", rb_gc_dump, 0); ++ rb_define_singleton_method(rb_mGC, "log", rb_gc_log, 1); ++ + rb_mObSpace = rb_define_module("ObjectSpace"); + rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1); + rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0); diff --git a/patches/ruby/1.8.5/backported-ossl-fixes.diff b/patches/ruby/1.8.5/backported-ossl-fixes.diff new file mode 100644 index 0000000000..c91cfd4cb1 --- /dev/null +++ b/patches/ruby/1.8.5/backported-ossl-fixes.diff @@ -0,0 +1,371 @@ +diff -r -u ruby-1.8.5-p231/ext/openssl/extconf.rb ruby-1.8.5-p231-fixed/ext/openssl/extconf.rb +--- ruby-1.8.5-p231/ext/openssl/extconf.rb 2007-02-13 08:01:19.000000000 +0900 ++++ ruby-1.8.5-p231-fixed/ext/openssl/extconf.rb 2010-07-13 02:18:18.000000000 +0800 +@@ -1,5 +1,5 @@ + =begin +-= $RCSfile: extconf.rb,v $ -- Generator for Makefile ++= $RCSfile$ -- Generator for Makefile + + = Info + 'OpenSSL for Ruby 2' project +@@ -11,7 +11,7 @@ + (See the file 'LICENCE'.) + + = Version +- $Id: extconf.rb,v 1.21.2.9 2006/06/20 11:18:15 gotoyuzo Exp $ ++ $Id: extconf.rb 12572 2007-06-18 09:03:15Z technorama $ + =end + + require "mkmf" +@@ -36,8 +36,6 @@ + message "=== Checking for system dependent stuff... ===\n" + have_library("nsl", "t_open") + have_library("socket", "socket") +-have_header("unistd.h") +-have_header("sys/time.h") + have_header("assert.h") + + message "=== Checking for required stuff... ===\n" +@@ -61,6 +59,8 @@ + exit 1 + end + ++%w"rb_str_set_len rb_block_call".each {|func| have_func(func, "ruby.h")} ++ + message "=== Checking for OpenSSL features... ===\n" + have_func("ERR_peek_last_error") + have_func("BN_mod_add") +@@ -83,6 +83,8 @@ + have_func("HMAC_CTX_copy") + have_func("HMAC_CTX_init") + have_func("PEM_def_callback") ++have_func("PKCS5_PBKDF2_HMAC") ++have_func("PKCS5_PBKDF2_HMAC_SHA1") + have_func("X509V3_set_nconf") + have_func("X509V3_EXT_nconf_nid") + have_func("X509_CRL_add0_revoked") +@@ -92,6 +94,7 @@ + have_func("X509_STORE_get_ex_data") + have_func("X509_STORE_set_ex_data") + have_func("OBJ_NAME_do_all_sorted") ++have_func("SSL_SESSION_get_id") + have_func("OPENSSL_cleanse") + if try_compile("#define FOO(a, ...) foo(a, ##__VA_ARGS__)\n int x(){FOO(1);FOO(1,2);FOO(1,2,3);}\n") + $defs.push("-DHAVE_VA_ARGS_MACRO") +diff -r -u ruby-1.8.5-p231/ext/openssl/openssl_missing.c ruby-1.8.5-p231-fixed/ext/openssl/openssl_missing.c +--- ruby-1.8.5-p231/ext/openssl/openssl_missing.c 2007-02-13 08:01:19.000000000 +0900 ++++ ruby-1.8.5-p231-fixed/ext/openssl/openssl_missing.c 2010-07-13 02:22:10.000000000 +0800 +@@ -1,5 +1,5 @@ + /* +- * $Id: openssl_missing.c,v 1.2.2.4 2006/06/02 10:02:56 gotoyuzo Exp $ ++ * $Id: openssl_missing.c 16467 2008-05-19 03:00:52Z knu $ + * 'OpenSSL for Ruby' project + * Copyright (C) 2001-2002 Michal Rokos + * All rights reserved. +@@ -22,17 +22,15 @@ + #include "openssl_missing.h" + + #if !defined(HAVE_HMAC_CTX_COPY) +-int ++void + HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in) + { +- if (!out || !in) return 0; ++ if (!out || !in) return; + memcpy(out, in, sizeof(HMAC_CTX)); + +- if (!EVP_MD_CTX_copy(&out->md_ctx, &in->md_ctx) +- || !EVP_MD_CTX_copy(&out->i_ctx, &in->i_ctx) +- || !EVP_MD_CTX_copy(&out->o_ctx, &in->o_ctx)) +- return 0; +- return 1; ++ EVP_MD_CTX_copy(&out->md_ctx, &in->md_ctx); ++ EVP_MD_CTX_copy(&out->i_ctx, &in->i_ctx); ++ EVP_MD_CTX_copy(&out->o_ctx, &in->o_ctx); + } + #endif /* HAVE_HMAC_CTX_COPY */ + #endif /* NO_HMAC */ +diff -r -u ruby-1.8.5-p231/ext/openssl/openssl_missing.h ruby-1.8.5-p231-fixed/ext/openssl/openssl_missing.h +--- ruby-1.8.5-p231/ext/openssl/openssl_missing.h 2007-02-13 08:01:19.000000000 +0900 ++++ ruby-1.8.5-p231-fixed/ext/openssl/openssl_missing.h 2010-07-13 02:22:10.000000000 +0800 +@@ -1,5 +1,5 @@ + /* +- * $Id: openssl_missing.h,v 1.2.2.2 2005/04/15 19:16:18 gotoyuzo Exp $ ++ * $Id: openssl_missing.h 18335 2008-08-04 04:44:17Z shyouhei $ + * 'OpenSSL for Ruby' project + * Copyright (C) 2001-2002 Michal Rokos + * All rights reserved. +@@ -15,6 +15,10 @@ + extern "C" { + #endif + ++#ifndef TYPEDEF_D2I_OF ++typedef char *d2i_of_void(); ++#endif ++ + /* + * These functions are not included in headers of OPENSSL <= 0.9.6b + */ +@@ -56,14 +60,33 @@ + (char *(*)())d2i_PKCS7_RECIP_INFO, (char *)ri) + #endif + ++#if !defined(HAVE_EVP_MD_CTX_INIT) + void HMAC_CTX_init(HMAC_CTX *ctx); +-int HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in); ++#endif ++ ++#if !defined(HAVE_HMAC_CTX_COPY) ++void HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in); ++#endif ++ ++#if !defined(HAVE_HMAC_CTX_CLEANUP) + void HMAC_CTX_cleanup(HMAC_CTX *ctx); ++#endif + ++#if !defined(HAVE_EVP_MD_CTX_CREATE) + EVP_MD_CTX *EVP_MD_CTX_create(void); ++#endif ++ ++#if !defined(HAVE_EVP_MD_CTX_INIT) + void EVP_MD_CTX_init(EVP_MD_CTX *ctx); ++#endif ++ ++#if !defined(HAVE_EVP_MD_CTX_CLEANUP) + int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx); ++#endif ++ ++#if !defined(HAVE_EVP_MD_CTX_DESTROY) + void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx); ++#endif + + #if !defined(HAVE_EVP_CIPHER_CTX_COPY) + int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, EVP_CIPHER_CTX *in); +@@ -107,19 +130,54 @@ + #define OPENSSL_cleanse(p, l) memset(p, 0, l) + #endif + ++#if !defined(HAVE_X509_STORE_SET_EX_DATA) + void *X509_STORE_get_ex_data(X509_STORE *str, int idx); + int X509_STORE_set_ex_data(X509_STORE *str, int idx, void *data); ++#endif ++ ++#if !defined(HAVE_X509_CRL_SET_VERSION) + int X509_CRL_set_version(X509_CRL *x, long version); ++#endif ++ ++#if !defined(HAVE_X509_CRL_SET_ISSUER_NAME) + int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name); ++#endif ++ ++#if !defined(HAVE_X509_CRL_SORT) + int X509_CRL_sort(X509_CRL *c); ++#endif ++ ++#if !defined(HAVE_X509_CRL_ADD0_REVOKED) + int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev); ++#endif ++ ++#if !defined(HAVE_BN_MOD_SQR) + int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx); ++#endif ++ ++#if !defined(HAVE_BN_MOD_ADD) + int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); ++#endif ++ ++#if !defined(HAVE_BN_MOD_SUB) + int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); ++#endif ++ ++#if !defined(HAVE_BN_RAND_RANGE) + int BN_rand_range(BIGNUM *r, BIGNUM *range); ++#endif ++ ++#if !defined(HAVE_BN_PSEUDO_RAND_RANGE) + int BN_pseudo_rand_range(BIGNUM *r, BIGNUM *range); ++#endif ++ ++#if !defined(HAVE_CONF_GET1_DEFAULT_CONFIG_FILE) + char *CONF_get1_default_config_file(void); ++#endif ++ ++#if !defined(HAVE_PEM_DEF_CALLBACK) + int PEM_def_callback(char *buf, int num, int w, void *key); ++#endif + + #if defined(__cplusplus) + } +diff -r -u ruby-1.8.5-p231/ext/openssl/ossl_hmac.c ruby-1.8.5-p231-fixed/ext/openssl/ossl_hmac.c +--- ruby-1.8.5-p231/ext/openssl/ossl_hmac.c 2007-02-13 08:01:19.000000000 +0900 ++++ ruby-1.8.5-p231-fixed/ext/openssl/ossl_hmac.c 2010-07-13 02:18:36.000000000 +0800 +@@ -1,5 +1,5 @@ + /* +- * $Id: ossl_hmac.c,v 1.4.2.2 2004/12/15 01:54:39 matz Exp $ ++ * $Id: ossl_hmac.c 16467 2008-05-19 03:00:52Z knu $ + * 'OpenSSL for Ruby' project + * Copyright (C) 2001-2002 Michal Rokos + * All rights reserved. +@@ -57,6 +57,12 @@ + return obj; + } + ++ ++/* ++ * call-seq: ++ * HMAC.new(key, digest) -> hmac ++ * ++ */ + static VALUE + ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest) + { +@@ -64,7 +70,7 @@ + + StringValue(key); + GetHMAC(self, ctx); +- HMAC_Init_ex(ctx, RSTRING(key)->ptr, RSTRING(key)->len, ++ HMAC_Init_ex(ctx, RSTRING_PTR(key), RSTRING_LEN(key), + GetDigestPtr(digest), NULL); + + return self; +@@ -81,12 +87,15 @@ + GetHMAC(self, ctx1); + SafeGetHMAC(other, ctx2); + +- if (!HMAC_CTX_copy(ctx1, ctx2)) { +- ossl_raise(eHMACError, NULL); +- } ++ HMAC_CTX_copy(ctx1, ctx2); + return self; + } + ++/* ++ * call-seq: ++ * hmac.update(string) -> self ++ * ++ */ + static VALUE + ossl_hmac_update(VALUE self, VALUE data) + { +@@ -94,7 +103,7 @@ + + StringValue(data); + GetHMAC(self, ctx); +- HMAC_Update(ctx, RSTRING(data)->ptr, RSTRING(data)->len); ++ HMAC_Update(ctx, RSTRING_PTR(data), RSTRING_LEN(data)); + + return self; + } +@@ -104,9 +113,7 @@ + { + HMAC_CTX final; + +- if (!HMAC_CTX_copy(&final, ctx)) { +- ossl_raise(eHMACError, NULL); +- } ++ HMAC_CTX_copy(&final, ctx); + if (!(*buf = OPENSSL_malloc(HMAC_size(&final)))) { + HMAC_CTX_cleanup(&final); + OSSL_Debug("Allocating %d mem", HMAC_size(&final)); +@@ -116,6 +123,11 @@ + HMAC_CTX_cleanup(&final); + } + ++/* ++ * call-seq: ++ * hmac.digest -> aString ++ * ++ */ + static VALUE + ossl_hmac_digest(VALUE self) + { +@@ -131,6 +143,11 @@ + return digest; + } + ++/* ++ * call-seq: ++ * hmac.hexdigest -> aString ++ * ++ */ + static VALUE + ossl_hmac_hexdigest(VALUE self) + { +@@ -151,6 +168,27 @@ + return hexdigest; + } + ++/* ++ * call-seq: ++ * hmac.reset -> self ++ * ++ */ ++static VALUE ++ossl_hmac_reset(VALUE self) ++{ ++ HMAC_CTX *ctx; ++ ++ GetHMAC(self, ctx); ++ HMAC_Init_ex(ctx, NULL, 0, NULL, NULL); ++ ++ return self; ++} ++ ++/* ++ * call-seq: ++ * HMAC.digest(digest, key, data) -> aString ++ * ++ */ + static VALUE + ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data) + { +@@ -159,12 +197,17 @@ + + StringValue(key); + StringValue(data); +- buf = HMAC(GetDigestPtr(digest), RSTRING(key)->ptr, RSTRING(key)->len, +- RSTRING(data)->ptr, RSTRING(data)->len, NULL, &buf_len); ++ buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LEN(key), ++ RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len); + + return rb_str_new(buf, buf_len); + } + ++/* ++ * call-seq: ++ * HMAC.digest(digest, key, data) -> aString ++ * ++ */ + static VALUE + ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data) + { +@@ -175,8 +218,8 @@ + StringValue(key); + StringValue(data); + +- buf = HMAC(GetDigestPtr(digest), RSTRING(key)->ptr, RSTRING(key)->len, +- RSTRING(data)->ptr, RSTRING(data)->len, NULL, &buf_len); ++ buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LEN(key), ++ RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len); + if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * buf_len) { + ossl_raise(eHMACError, "Cannot convert buf to hexbuf"); + } +@@ -191,6 +234,10 @@ + void + Init_ossl_hmac() + { ++#if 0 /* let rdoc know about mOSSL */ ++ mOSSL = rb_define_module("OpenSSL"); ++#endif ++ + eHMACError = rb_define_class_under(mOSSL, "HMACError", eOSSLError); + + cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject); +@@ -202,6 +249,7 @@ + rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2); + rb_define_copy_func(cHMAC, ossl_hmac_copy); + ++ rb_define_method(cHMAC, "reset", ossl_hmac_reset, 0); + rb_define_method(cHMAC, "update", ossl_hmac_update, 1); + rb_define_alias(cHMAC, "<<", "update"); + rb_define_method(cHMAC, "digest", ossl_hmac_digest, 0); diff --git a/patches/ruby/1.8.5/railsbench.patch b/patches/ruby/1.8.5/railsbench.patch new file mode 100644 index 0000000000..3bf9080db8 --- /dev/null +++ b/patches/ruby/1.8.5/railsbench.patch @@ -0,0 +1,562 @@ +--- gc.c.orig 2006-08-25 10:12:46.000000000 +0200 ++++ gc.c 2007-05-06 10:55:19.000000000 +0200 +@@ -22,8 +22,16 @@ + #include + #include + ++#ifdef _WIN32 ++#include ++#else ++#include ++#endif ++ + #ifdef HAVE_SYS_TIME_H + #include ++#elif defined(_WIN32) ++#include + #endif + + #ifdef HAVE_SYS_RESOURCE_H +@@ -54,7 +62,6 @@ + #if !defined(setjmp) && defined(HAVE__SETJMP) + #define setjmp(env) _setjmp(env) + #endif +- + /* Make alloca work the best possible way. */ + #ifdef __GNUC__ + # ifndef atarist +@@ -173,8 +180,17 @@ + RUBY_CRITICAL(free(x)); + } + ++#if HAVE_LONG_LONG ++#define GC_TIME_TYPE LONG_LONG ++#else ++#define GC_TIME_TYPE long ++#endif ++ + extern int ruby_in_compile; + static int dont_gc; ++static int gc_statistics = 0; ++static GC_TIME_TYPE gc_time = 0; ++static int gc_collections = 0; + static int during_gc; + static int need_call_final = 0; + static st_table *finalizer_table = 0; +@@ -209,7 +225,7 @@ + * Disables garbage collection, returning true if garbage + * collection was already disabled. + * +- * GC.disable #=> false ++ * GC.disable #=> false or true + * GC.disable #=> true + * + */ +@@ -223,6 +239,104 @@ + return old; + } + ++/* ++ * call-seq: ++ * GC.enable_stats => true or false ++ * ++ * Enables garbage collection statistics, returning true if garbage ++ * collection statistics was already enabled. ++ * ++ * GC.enable_stats #=> false or true ++ * GC.enable_stats #=> true ++ * ++ */ ++ ++VALUE ++rb_gc_enable_stats() ++{ ++ int old = gc_statistics; ++ gc_statistics = Qtrue; ++ return old; ++} ++ ++/* ++ * call-seq: ++ * GC.disable_stats => true or false ++ * ++ * Disables garbage collection statistics, returning true if garbage ++ * collection statistics was already disabled. ++ * ++ * GC.disable_stats #=> false or true ++ * GC.disable_stats #=> true ++ * ++ */ ++ ++VALUE ++rb_gc_disable_stats() ++{ ++ int old = gc_statistics; ++ gc_statistics = Qfalse; ++ return old; ++} ++ ++/* ++ * call-seq: ++ * GC.clear_stats => nil ++ * ++ * Clears garbage collection statistics, returning nil. This resets the number ++ * of collections (GC.collections) and the time used (GC.time) to 0. ++ * ++ * GC.clear_stats #=> nil ++ * ++ */ ++ ++VALUE ++rb_gc_clear_stats() ++{ ++ gc_collections = 0; ++ gc_time = 0; ++ return Qnil; ++} ++ ++/* ++ * call-seq: ++ * GC.collections => Integer ++ * ++ * Returns the number of garbage collections performed while GC statistics collection ++ * was enabled. ++ * ++ * GC.collections #=> 35 ++ * ++ */ ++ ++VALUE ++rb_gc_collections() ++{ ++ return INT2NUM(gc_collections); ++} ++ ++/* ++ * call-seq: ++ * GC.time => Integer ++ * ++ * Returns the time spent during garbage collection while GC statistics collection ++ * was enabled (in micro seconds). ++ * ++ * GC.time #=> 20000 ++ * ++ */ ++ ++VALUE ++rb_gc_time() ++{ ++#if HAVE_LONG_LONG ++ return LL2NUM(gc_time); ++#else ++ return LONG2NUM(gc_time); ++#endif ++} ++ ++ + VALUE rb_mGC; + + static struct gc_list { +@@ -314,7 +428,7 @@ + static RVALUE *freelist = 0; + static RVALUE *deferred_final_list = 0; + +-#define HEAPS_INCREMENT 10 ++static int heaps_increment = 10; + static struct heaps_slot { + void *membase; + RVALUE *slot; +@@ -323,13 +437,165 @@ + static int heaps_length = 0; + static int heaps_used = 0; + +-#define HEAP_MIN_SLOTS 10000 +-static int heap_slots = HEAP_MIN_SLOTS; ++static int heap_min_slots = 10000; ++static int heap_slots = 10000; ++ ++static int heap_free_min = 4096; ++static int heap_slots_increment = 10000; ++static double heap_slots_growth_factor = 1.8; ++ ++static long initial_malloc_limit = GC_MALLOC_LIMIT; + +-#define FREE_MIN 4096 ++static int verbose_gc_stats = Qfalse; ++ ++static FILE* gc_data_file = NULL; + + static RVALUE *himem, *lomem; + ++static void set_gc_parameters() ++{ ++ char *gc_stats_ptr, *min_slots_ptr, *free_min_ptr, *heap_slots_incr_ptr, ++ *heap_incr_ptr, *malloc_limit_ptr, *gc_heap_file_ptr, *heap_slots_growth_factor_ptr; ++ ++ gc_data_file = stderr; ++ ++ gc_stats_ptr = getenv("RUBY_GC_STATS"); ++ if (gc_stats_ptr != NULL) { ++ int gc_stats_i = atoi(gc_stats_ptr); ++ if (gc_stats_i > 0) { ++ verbose_gc_stats = Qtrue; ++ } ++ } ++ ++ gc_heap_file_ptr = getenv("RUBY_GC_DATA_FILE"); ++ if (gc_heap_file_ptr != NULL) { ++ FILE* data_file = fopen(gc_heap_file_ptr, "w"); ++ if (data_file != NULL) { ++ gc_data_file = data_file; ++ } ++ else { ++ fprintf(stderr, ++ "can't open gc log file %s for writing, using default\n", gc_heap_file_ptr); ++ } ++ } ++ ++ min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS"); ++ if (min_slots_ptr != NULL) { ++ int min_slots_i = atoi(min_slots_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_MIN_SLOTS=%s\n", min_slots_ptr); ++ } ++ if (min_slots_i > 0) { ++ heap_slots = min_slots_i; ++ heap_min_slots = min_slots_i; ++ } ++ } ++ ++ free_min_ptr = getenv("RUBY_HEAP_FREE_MIN"); ++ if (free_min_ptr != NULL) { ++ int free_min_i = atoi(free_min_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_FREE_MIN=%s\n", free_min_ptr); ++ } ++ if (free_min_i > 0) { ++ heap_free_min = free_min_i; ++ } ++ } ++ ++ heap_incr_ptr = getenv("RUBY_HEAP_INCREMENT"); ++ if (heap_incr_ptr != NULL) { ++ int heap_incr_i = atoi(heap_incr_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_INCREMENT=%s\n", heap_incr_ptr); ++ } ++ if (heap_incr_i > 0) { ++ heaps_increment = heap_incr_i; ++ } ++ } ++ ++ heap_slots_incr_ptr = getenv("RUBY_HEAP_SLOTS_INCREMENT"); ++ if (heap_slots_incr_ptr != NULL) { ++ int heap_slots_incr_i = atoi(heap_slots_incr_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_SLOTS_INCREMENT=%s\n", heap_slots_incr_ptr); ++ } ++ if (heap_slots_incr_i > 0) { ++ heap_slots_increment = heap_slots_incr_i; ++ } ++ } ++ ++ heap_slots_growth_factor_ptr = getenv("RUBY_HEAP_SLOTS_GROWTH_FACTOR"); ++ if (heap_slots_growth_factor_ptr != NULL) { ++ double heap_slots_growth_factor_d = atoi(heap_slots_growth_factor_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_SLOTS_GROWTH_FACTOR=%s\n", heap_slots_growth_factor_ptr); ++ } ++ if (heap_slots_growth_factor_d > 0) { ++ heap_slots_growth_factor = heap_slots_growth_factor_d; ++ } ++ } ++ ++ malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT"); ++ if (malloc_limit_ptr != NULL) { ++ int malloc_limit_i = atol(malloc_limit_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_GC_MALLOC_LIMIT=%s\n", malloc_limit_ptr); ++ } ++ if (malloc_limit_i > 0) { ++ initial_malloc_limit = malloc_limit_i; ++ } ++ } ++} ++ ++/* ++ * call-seq: ++ * GC.dump => nil ++ * ++ * dumps information about the current GC data structures to the GC log file ++ * ++ * GC.dump #=> nil ++ * ++ */ ++ ++VALUE ++rb_gc_dump() ++{ ++ int i; ++ ++ for (i = 0; i < heaps_used; i++) { ++ int heap_size = heaps[i].limit; ++ fprintf(gc_data_file, "HEAP[%2d]: size=%7d\n", i, heap_size); ++ } ++ ++ return Qnil; ++} ++ ++/* ++ * call-seq: ++ * GC.log String => String ++ * ++ * Logs string to the GC data file and returns it. ++ * ++ * GC.log "manual GC call" #=> "manual GC call" ++ * ++ */ ++ ++VALUE ++rb_gc_log(self, original_str) ++ VALUE self, original_str; ++{ ++ if (original_str == Qnil) { ++ fprintf(gc_data_file, "\n"); ++ } ++ else { ++ VALUE str = StringValue(original_str); ++ char *p = RSTRING(str)->ptr; ++ fprintf(gc_data_file, "%s\n", p); ++ } ++ return original_str; ++} ++ ++ + static void + add_heap() + { +@@ -340,7 +606,7 @@ + struct heaps_slot *p; + int length; + +- heaps_length += HEAPS_INCREMENT; ++ heaps_length += heaps_increment; + length = heaps_length*sizeof(struct heaps_slot); + RUBY_CRITICAL( + if (heaps_used > 0) { +@@ -356,10 +622,10 @@ + for (;;) { + RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1))); + if (p == 0) { +- if (heap_slots == HEAP_MIN_SLOTS) { ++ if (heap_slots == heap_min_slots) { + rb_memerror(); + } +- heap_slots = HEAP_MIN_SLOTS; ++ heap_slots = heap_min_slots; + continue; + } + heaps[heaps_used].membase = p; +@@ -375,8 +641,9 @@ + if (lomem == 0 || lomem > p) lomem = p; + if (himem < pend) himem = pend; + heaps_used++; +- heap_slots *= 1.8; +- if (heap_slots <= 0) heap_slots = HEAP_MIN_SLOTS; ++ heap_slots += heap_slots_increment; ++ heap_slots_increment *= heap_slots_growth_factor; ++ if (heap_slots <= 0) heap_slots = heap_min_slots; + + while (p < pend) { + p->as.free.flags = 0; +@@ -1026,6 +1293,39 @@ + } + } + ++static char* obj_type(int tp) ++{ ++ switch (tp) { ++ case T_NIL : return "NIL"; ++ case T_OBJECT : return "OBJECT"; ++ case T_CLASS : return "CLASS"; ++ case T_ICLASS : return "ICLASS"; ++ case T_MODULE : return "MODULE"; ++ case T_FLOAT : return "FLOAT"; ++ case T_STRING : return "STRING"; ++ case T_REGEXP : return "REGEXP"; ++ case T_ARRAY : return "ARRAY"; ++ case T_FIXNUM : return "FIXNUM"; ++ case T_HASH : return "HASH"; ++ case T_STRUCT : return "STRUCT"; ++ case T_BIGNUM : return "BIGNUM"; ++ case T_FILE : return "FILE"; ++ ++ case T_TRUE : return "TRUE"; ++ case T_FALSE : return "FALSE"; ++ case T_DATA : return "DATA"; ++ case T_MATCH : return "MATCH"; ++ case T_SYMBOL : return "SYMBOL"; ++ ++ case T_BLKTAG : return "BLKTAG"; ++ case T_UNDEF : return "UNDEF"; ++ case T_VARMAP : return "VARMAP"; ++ case T_SCOPE : return "SCOPE"; ++ case T_NODE : return "NODE"; ++ default: return "____"; ++ } ++} ++ + static void + free_unused_heaps() + { +@@ -1056,12 +1356,21 @@ + unsigned long live = 0; + unsigned long free_min = 0; + ++ unsigned long really_freed = 0; ++ int free_counts[256]; ++ int live_counts[256]; ++ int do_gc_stats = gc_statistics & verbose_gc_stats; ++ + for (i = 0; i < heaps_used; i++) { + free_min += heaps[i].limit; + } + free_min = free_min * 0.2; +- if (free_min < FREE_MIN) +- free_min = FREE_MIN; ++ if (free_min < heap_free_min) ++ free_min = heap_free_min; ++ ++ if (do_gc_stats) { ++ for (i = 0 ; i< 256; i++) { free_counts[i] = live_counts[i] = 0; } ++ } + + if (ruby_in_compile && ruby_parser_stack_on_heap()) { + /* should not reclaim nodes during compilation +@@ -1094,6 +1403,9 @@ + if (!(p->as.basic.flags & FL_MARK)) { + if (p->as.basic.flags) { + obj_free((VALUE)p); ++ if (do_gc_stats) { ++ really_freed++; ++ } + } + if (need_call_final && FL_TEST(p, FL_FINALIZE)) { + p->as.free.flags = FL_MARK; /* remain marked */ +@@ -1101,6 +1413,12 @@ + final_list = p; + } + else { ++ if (do_gc_stats) { ++ int obt = p->as.basic.flags & T_MASK; ++ if (obt) { ++ free_counts[obt]++; ++ } ++ } + p->as.free.flags = 0; + p->as.free.next = freelist; + freelist = p; +@@ -1114,6 +1432,9 @@ + else { + RBASIC(p)->flags &= ~FL_MARK; + live++; ++ if (do_gc_stats) { ++ live_counts[RANY((VALUE)p)->as.basic.flags & T_MASK]++; ++ } + } + p++; + } +@@ -1132,7 +1453,7 @@ + } + if (malloc_increase > malloc_limit) { + malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed); +- if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT; ++ if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit; + } + malloc_increase = 0; + if (freed < free_min) { +@@ -1140,6 +1461,20 @@ + } + during_gc = 0; + ++ if (do_gc_stats) { ++ fprintf(gc_data_file, "objects processed: %.7d\n", live+freed); ++ fprintf(gc_data_file, "live objects : %.7d\n", live); ++ fprintf(gc_data_file, "freelist objects : %.7d\n", freed - really_freed); ++ fprintf(gc_data_file, "freed objects : %.7d\n", really_freed); ++ for(i=0; i<256; i++) { ++ if (free_counts[i]>0) { ++ fprintf(gc_data_file, ++ "kept %.7d / freed %.7d objects of type %s\n", ++ live_counts[i], free_counts[i], obj_type(i)); ++ } ++ } ++ } ++ + /* clear finalization list */ + if (final_list) { + deferred_final_list = final_list; +@@ -1334,6 +1669,7 @@ + struct gc_list *list; + struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */ + jmp_buf save_regs_gc_mark; ++ struct timeval gctv1, gctv2; + SET_STACK_END; + + #ifdef HAVE_NATIVETHREAD +@@ -1350,6 +1686,14 @@ + if (during_gc) return; + during_gc++; + ++ if (gc_statistics) { ++ gc_collections++; ++ gettimeofday(&gctv1, NULL); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "Garbage collection started\n"); ++ } ++ } ++ + init_mark_stack(); + + gc_mark((VALUE)ruby_current_node, 0); +@@ -1438,6 +1782,17 @@ + } while (!MARK_STACK_EMPTY); + + gc_sweep(); ++ ++ if (gc_statistics) { ++ GC_TIME_TYPE musecs_used; ++ gettimeofday(&gctv2, NULL); ++ musecs_used = ((GC_TIME_TYPE)(gctv2.tv_sec - gctv1.tv_sec) * 1000000) + (gctv2.tv_usec - gctv1.tv_usec); ++ gc_time += musecs_used; ++ ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "GC time: %d msec\n", musecs_used / 1000); ++ } ++ } + } + + void +@@ -1551,6 +1906,7 @@ + if (!rb_gc_stack_start) { + Init_stack(0); + } ++ set_gc_parameters(); + add_heap(); + } + +@@ -2020,6 +2376,14 @@ + rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0); + rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0); + ++ rb_define_singleton_method(rb_mGC, "enable_stats", rb_gc_enable_stats, 0); ++ rb_define_singleton_method(rb_mGC, "disable_stats", rb_gc_disable_stats, 0); ++ rb_define_singleton_method(rb_mGC, "clear_stats", rb_gc_clear_stats, 0); ++ rb_define_singleton_method(rb_mGC, "collections", rb_gc_collections, 0); ++ rb_define_singleton_method(rb_mGC, "time", rb_gc_time, 0); ++ rb_define_singleton_method(rb_mGC, "dump", rb_gc_dump, 0); ++ rb_define_singleton_method(rb_mGC, "log", rb_gc_log, 1); ++ + rb_mObSpace = rb_define_module("ObjectSpace"); + rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1); + rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0); diff --git a/patches/ruby/1.8.6/hs.patch b/patches/ruby/1.8.6/hs.patch new file mode 100644 index 0000000000..ddc43d8b08 --- /dev/null +++ b/patches/ruby/1.8.6/hs.patch @@ -0,0 +1,1124 @@ +diff --git a/eval.c b/eval.c +index 4098b83..c70f270 100644 +--- a/eval.c ++++ b/eval.c +@@ -73,6 +73,7 @@ char *strrchr _((const char*,const char)); + #endif + + #include ++#include + + #ifdef __BEOS__ + #include +@@ -1025,7 +1026,7 @@ static struct tag *prot_tag; + _tag.blkid = 0; \ + prot_tag = &_tag + +-#define PROT_NONE Qfalse /* 0 */ ++#define PROT_EMPTY Qfalse /* 0 */ + #define PROT_THREAD Qtrue /* 2 */ + #define PROT_FUNC INT2FIX(0) /* 1 */ + #define PROT_LOOP INT2FIX(1) /* 3 */ +@@ -1236,7 +1237,7 @@ error_print() + + if (NIL_P(ruby_errinfo)) return; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if (EXEC_TAG() == 0) { + errat = get_backtrace(ruby_errinfo); + } +@@ -1396,7 +1397,7 @@ ruby_init() + /* default visibility is private at toplevel */ + SCOPE_SET(SCOPE_PRIVATE); + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + rb_call_inits(); + ruby_class = rb_cObject; +@@ -1530,7 +1531,7 @@ ruby_options(argc, argv) + int state; + + Init_stack((void*)&state); +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + ruby_process_options(argc, argv); + } +@@ -1547,7 +1548,7 @@ void rb_exec_end_proc _((void)); + static void + ruby_finalize_0() + { +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if (EXEC_TAG() == 0) { + rb_trap_exit(); + } +@@ -1585,7 +1586,7 @@ ruby_cleanup(ex) + Init_stack((void *)&state); + ruby_finalize_0(); + errs[0] = ruby_errinfo; +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + PUSH_ITER(ITER_NOT); + if ((state = EXEC_TAG()) == 0) { + rb_thread_cleanup(); +@@ -1636,7 +1637,7 @@ ruby_exec_internal() + { + int state; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + PUSH_ITER(ITER_NOT); + /* default visibility is private at toplevel */ + SCOPE_SET(SCOPE_PRIVATE); +@@ -1858,7 +1859,7 @@ rb_eval_cmd(cmd, arg, level) + } + if (TYPE(cmd) != T_STRING) { + PUSH_ITER(ITER_NOT); +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + ruby_safe_level = level; + if ((state = EXEC_TAG()) == 0) { + val = rb_funcall2(cmd, rb_intern("call"), RARRAY(arg)->len, RARRAY(arg)->ptr); +@@ -1880,7 +1881,7 @@ rb_eval_cmd(cmd, arg, level) + + ruby_safe_level = level; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + val = eval(ruby_top_self, cmd, Qnil, 0, 0); + } +@@ -2387,7 +2388,7 @@ is_defined(self, node, buf) + val = self; + if (node->nd_recv == (NODE *)1) goto check_bound; + case NODE_CALL: +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + val = rb_eval(self, node->nd_recv); + } +@@ -2489,7 +2490,7 @@ is_defined(self, node, buf) + break; + + case NODE_COLON2: +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + val = rb_eval(self, node->nd_head); + } +@@ -2538,7 +2539,7 @@ is_defined(self, node, buf) + goto again; + + default: +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + rb_eval(self, node); + } +@@ -2742,7 +2743,7 @@ call_trace_func(event, node, self, id, klass) + klass = rb_iv_get(klass, "__attached__"); + } + } +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + raised = rb_thread_reset_raised(th); + if ((state = EXEC_TAG()) == 0) { + srcfile = rb_str_new2(ruby_sourcefile?ruby_sourcefile:"(ruby)"); +@@ -3302,7 +3303,7 @@ rb_eval(self, n) + volatile VALUE e_info = ruby_errinfo; + volatile int rescuing = 0; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + retry_entry: + result = rb_eval(self, node->nd_head); +@@ -3351,7 +3352,7 @@ rb_eval(self, n) + break; + + case NODE_ENSURE: +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + result = rb_eval(self, node->nd_head); + } +@@ -3569,7 +3570,7 @@ rb_eval(self, n) + ruby_frame = &frame; + + PUSH_SCOPE(); +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if (node->nd_rval) { + saved_cref = ruby_cref; + ruby_cref = (NODE*)node->nd_rval; +@@ -4195,7 +4196,7 @@ module_setup(module, n) + } + + PUSH_CREF(module); +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + EXEC_EVENT_HOOK(RUBY_EVENT_CLASS, n, ruby_cbase, + ruby_frame->last_func, ruby_frame->last_class); +@@ -4602,7 +4603,7 @@ rb_longjmp(tag, mesg) + VALUE e = ruby_errinfo; + int status; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((status = EXEC_TAG()) == 0) { + StringValue(e); + warn_printf("Exception `%s' at %s:%d - %s\n", +@@ -4974,7 +4975,7 @@ rb_yield_0(val, self, klass, flags, avalue) + node = block->body; + + if (block->var) { +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + if (block->var == (NODE*)1) { /* no parameter || */ + if (lambda && RARRAY(val)->len != 0) { +@@ -5032,7 +5033,7 @@ rb_yield_0(val, self, klass, flags, avalue) + ruby_current_node = node; + + PUSH_ITER(block->iter); +- PUSH_TAG(lambda ? PROT_NONE : PROT_YIELD); ++ PUSH_TAG(lambda ? PROT_EMPTY : PROT_YIELD); + if ((state = EXEC_TAG()) == 0) { + redo: + if (nd_type(node) == NODE_CFUNC || nd_type(node) == NODE_IFUNC) { +@@ -5430,7 +5431,7 @@ rb_rescue2(b_proc, data1, r_proc, data2, va_alist) + VALUE eclass; + va_list args; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + switch (state = EXEC_TAG()) { + case TAG_RETRY: + if (!handle) break; +@@ -5488,7 +5489,7 @@ rb_protect(proc, data, state) + VALUE result = Qnil; /* OK */ + int status; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + cont_protect = (VALUE)rb_node_newnode(NODE_MEMO, cont_protect, 0, 0); + if ((status = EXEC_TAG()) == 0) { + result = (*proc)(data); +@@ -5516,7 +5517,7 @@ rb_ensure(b_proc, data1, e_proc, data2) + volatile VALUE result = Qnil; + VALUE retval; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + result = (*b_proc)(data1); + } +@@ -5543,7 +5544,7 @@ rb_with_disable_interrupt(proc, data) + int thr_critical = rb_thread_critical; + + rb_thread_critical = Qtrue; +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((status = EXEC_TAG()) == 0) { + result = (*proc)(data); + } +@@ -6230,7 +6231,7 @@ rb_funcall_rescue(recv, mid, n, va_alist) + + va_init_list(ar, n); + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((status = EXEC_TAG()) == 0) { + result = vafuncall(recv, mid, n, &ar); + } +@@ -6499,7 +6500,7 @@ eval(self, src, scope, file, line) + if (TYPE(ruby_class) == T_ICLASS) { + ruby_class = RBASIC(ruby_class)->klass; + } +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + NODE *node; + +@@ -6658,7 +6659,7 @@ exec_under(func, under, cbase, args) + + mode = scope_vmode; + SCOPE_SET(SCOPE_PUBLIC); +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + val = (*func)(args); + } +@@ -6889,7 +6890,7 @@ rb_load(fname, wrap) + PUSH_SCOPE(); + /* default visibility is private at loading toplevel */ + SCOPE_SET(SCOPE_PRIVATE); +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + state = EXEC_TAG(); + last_func = ruby_frame->last_func; + last_node = ruby_current_node; +@@ -6948,7 +6949,7 @@ rb_load_protect(fname, wrap, state) + { + int status; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((status = EXEC_TAG()) == 0) { + rb_load(fname, wrap); + } +@@ -7269,7 +7270,7 @@ rb_require_safe(fname, safe) + saved.node = ruby_current_node; + saved.func = ruby_frame->last_func; + saved.safe = ruby_safe_level; +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + VALUE feature, path; + long handle; +@@ -7977,7 +7978,7 @@ rb_exec_end_proc() + tmp_end_procs = link = ephemeral_end_procs; + ephemeral_end_procs = 0; + while (link) { +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((status = EXEC_TAG()) == 0) { + ruby_safe_level = link->safe; + (*link->func)(link->data); +@@ -7995,7 +7996,7 @@ rb_exec_end_proc() + tmp_end_procs = link = end_procs; + end_procs = 0; + while (link) { +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((status = EXEC_TAG()) == 0) { + ruby_safe_level = link->safe; + (*link->func)(link->data); +@@ -8654,7 +8655,7 @@ proc_invoke(proc, args, self, klass) + ruby_block = &_block; + PUSH_ITER(ITER_CUR); + ruby_frame->iter = ITER_CUR; +- PUSH_TAG(pcall ? PROT_LAMBDA : PROT_NONE); ++ PUSH_TAG(pcall ? PROT_LAMBDA : PROT_EMPTY); + state = EXEC_TAG(); + if (state == 0) { + proc_set_safe_level(proc); +@@ -9896,6 +9897,7 @@ win32_set_exception_list(p) + int rb_thread_pending = 0; + + VALUE rb_cThread; ++static unsigned int rb_thread_stack_size; + + extern VALUE rb_last_status; + +@@ -10123,12 +10125,20 @@ thread_mark(th) + rb_gc_mark(th->thread); + if (th->join) rb_gc_mark(th->join->thread); + +- rb_gc_mark(th->klass); +- rb_gc_mark(th->wrapper); +- rb_gc_mark((VALUE)th->cref); ++ if (curr_thread == th) { ++ rb_gc_mark(ruby_class); ++ rb_gc_mark(ruby_wrapper); ++ rb_gc_mark((VALUE)ruby_cref); ++ rb_gc_mark((VALUE)ruby_scope); ++ rb_gc_mark((VALUE)ruby_dyna_vars); ++ } else { ++ rb_gc_mark(th->klass); ++ rb_gc_mark(th->wrapper); ++ rb_gc_mark((VALUE)th->cref); ++ rb_gc_mark((VALUE)th->scope); ++ rb_gc_mark((VALUE)th->dyna_vars); ++ } + +- rb_gc_mark((VALUE)th->scope); +- rb_gc_mark((VALUE)th->dyna_vars); + rb_gc_mark(th->errinfo); + rb_gc_mark(th->last_status); + rb_gc_mark(th->last_line); +@@ -10138,11 +10148,11 @@ thread_mark(th) + rb_gc_mark_maybe(th->sandbox); + + /* mark data in copied stack */ +- if (th == curr_thread) return; ++ if (th == main_thread) return; + if (th->status == THREAD_KILLED) return; + if (th->stk_len == 0) return; /* stack not active, no need to mark. */ +- if (th->stk_ptr) { +- rb_gc_mark_locations(th->stk_ptr, th->stk_ptr+th->stk_len); ++ if (th->stk_ptr && th != curr_thread) { ++ rb_gc_mark_locations(th->stk_pos, th->stk_base); + #if defined(THINK_C) || defined(__human68k__) + rb_gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2); + #endif +@@ -10152,24 +10162,30 @@ thread_mark(th) + } + #endif + } +- frame = th->frame; ++ ++ if (curr_thread == th) ++ frame = ruby_frame; ++ else ++ frame = th->frame; ++ + while (frame && frame != top_frame) { +- frame = ADJ(frame); + rb_gc_mark_frame(frame); + if (frame->tmp) { + struct FRAME *tmp = frame->tmp; +- + while (tmp && tmp != top_frame) { +- tmp = ADJ(tmp); + rb_gc_mark_frame(tmp); + tmp = tmp->prev; + } + } + frame = frame->prev; + } +- block = th->block; ++ ++ if (curr_thread == th) ++ block = ruby_block; ++ else ++ block = th->block; ++ + while (block) { +- block = ADJ(block); + rb_gc_mark_frame(&block->frame); + block = block->prev; + } +@@ -10232,7 +10248,7 @@ static inline void + stack_free(th) + rb_thread_t th; + { +- if (th->stk_ptr) free(th->stk_ptr); ++ if (th->stk_ptr) munmap(th->stk_ptr, th->stk_size); + th->stk_ptr = 0; + #ifdef __ia64 + if (th->bstr_ptr) free(th->bstr_ptr); +@@ -10293,35 +10309,8 @@ rb_thread_save_context(th) + static VALUE tval; + + len = ruby_stack_length(&pos); +- th->stk_len = 0; +- th->stk_pos = pos; +- if (len > th->stk_max) { +- VALUE *ptr = realloc(th->stk_ptr, sizeof(VALUE) * len); +- if (!ptr) rb_memerror(); +- th->stk_ptr = ptr; +- th->stk_max = len; +- } + th->stk_len = len; +- FLUSH_REGISTER_WINDOWS; +- MEMCPY(th->stk_ptr, th->stk_pos, VALUE, th->stk_len); +-#ifdef __ia64 +- th->bstr_pos = rb_gc_register_stack_start; +- len = (VALUE*)rb_ia64_bsp() - th->bstr_pos; +- th->bstr_len = 0; +- if (len > th->bstr_max) { +- VALUE *ptr = realloc(th->bstr_ptr, sizeof(VALUE) * len); +- if (!ptr) rb_memerror(); +- th->bstr_ptr = ptr; +- th->bstr_max = len; +- } +- th->bstr_len = len; +- rb_ia64_flushrs(); +- MEMCPY(th->bstr_ptr, th->bstr_pos, VALUE, th->bstr_len); +-#endif +-#ifdef SAVE_WIN32_EXCEPTION_LIST +- th->win32_exception_list = win32_get_exception_list(); +-#endif +- ++ th->stk_pos = pos; + th->frame = ruby_frame; + th->scope = ruby_scope; + ruby_scope->flags |= SCOPE_DONT_RECYCLE; +@@ -10431,11 +10420,6 @@ rb_thread_restore_context_0(rb_thread_t th, int exit) + #endif + tmp = th; + ex = exit; +- FLUSH_REGISTER_WINDOWS; +- MEMCPY(tmp->stk_pos, tmp->stk_ptr, VALUE, tmp->stk_len); +-#ifdef __ia64 +- MEMCPY(tmp->bstr_pos, tmp->bstr_ptr, VALUE, tmp->bstr_len); +-#endif + + tval = rb_lastline_get(); + rb_lastline_set(tmp->last_line); +@@ -10526,8 +10510,8 @@ rb_thread_restore_context(th, exit) + rb_thread_t th; + int exit; + { +- if (!th->stk_ptr) rb_bug("unsaved context"); +- stack_extend(th, exit); ++ if (!th->stk_ptr && th != main_thread) rb_bug("unsaved context"); ++ rb_thread_restore_context_0(th, exit); + } + + static void +@@ -10546,7 +10530,6 @@ rb_thread_die(th) + { + th->thgroup = 0; + th->status = THREAD_KILLED; +- stack_free(th); + } + + static void +@@ -11822,6 +11805,7 @@ rb_thread_group(thread) + \ + th->stk_ptr = 0;\ + th->stk_len = 0;\ ++ th->stk_size = 0;\ + th->stk_max = 0;\ + th->wait_for = 0;\ + IA64_INIT(th->bstr_ptr = 0);\ +@@ -11869,6 +11853,48 @@ rb_thread_alloc(klass) + THREAD_ALLOC(th); + th->thread = Data_Wrap_Struct(klass, thread_mark, thread_free, th); + ++ /* if main_thread != NULL, then this is NOT the main thread, so ++ * we create a heap-stack ++ */ ++ if (main_thread) { ++ /* Allocate stack, don't forget to add 1 extra word because of the MATH below */ ++ unsigned int pagesize = getpagesize(); ++ unsigned int total_size = rb_thread_stack_size + pagesize + sizeof(int); ++ void *stack_area = NULL; ++ ++ stack_area = mmap(NULL, total_size, PROT_READ | PROT_WRITE | PROT_EXEC, ++ MAP_PRIVATE | MAP_ANON, -1, 0); ++ ++ if (stack_area == MAP_FAILED) { ++ fprintf(stderr, "Thread stack allocation failed!\n"); ++ rb_memerror(); ++ } ++ ++ th->stk_ptr = th->stk_pos = stack_area; ++ th->stk_size = total_size; ++ ++ if (mprotect(th->stk_ptr, pagesize, PROT_NONE) == -1) { ++ fprintf(stderr, "Failed to create thread guard region: %s\n", strerror(errno)); ++ rb_memerror(); ++ } ++ ++ th->guard = th->stk_ptr + (pagesize/sizeof(VALUE *)); ++ ++ /* point stk_base at the top of the stack */ ++ /* ASSUMPTIONS: ++ * 1.) The address returned by malloc is "suitably aligned" for anything on this system ++ * 2.) Adding a value that is "aligned" for this platform should not unalign the address ++ * returned from malloc. ++ * 3.) Don't push anything on to the stack, otherwise it'll get unaligned. ++ * 4.) x86_64 ABI says aligned AFTER arguments have been pushed. You *must* then do a call[lq] ++ * or push[lq] something else on to the stack if you inted to do a ret. ++ */ ++ th->stk_base = th->stk_ptr + ((total_size - sizeof(int))/sizeof(VALUE *)); ++ th->stk_len = rb_thread_stack_size; ++ } else { ++ th->stk_ptr = th->stk_pos = rb_gc_stack_start; ++ } ++ + for (vars = th->dyna_vars; vars; vars = vars->next) { + if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; + FL_SET(vars, DVAR_DONT_RECYCLE); +@@ -12014,17 +12040,22 @@ rb_thread_cancel_timer() + } + #endif + ++struct thread_start_args { ++ VALUE (*fn)(); ++ void *arg; ++ rb_thread_t th; ++} new_th; ++ ++static VALUE ++rb_thread_start_2(); ++ + static VALUE + rb_thread_start_0(fn, arg, th) + VALUE (*fn)(); + void *arg; + rb_thread_t th; + { +- volatile rb_thread_t th_save = th; + volatile VALUE thread = th->thread; +- struct BLOCK *volatile saved_block = 0; +- enum rb_thread_status status; +- int state; + + if (OBJ_FROZEN(curr_thread->thgroup)) { + rb_raise(rb_eThreadError, +@@ -12054,16 +12085,41 @@ rb_thread_start_0(fn, arg, th) + return thread; + } + +- if (ruby_block) { /* should nail down higher blocks */ +- struct BLOCK dummy; ++ new_th.fn = fn; ++ new_th.arg = arg; ++ new_th.th = th; ++ ++#if defined(__i386__) ++ __asm__ __volatile__ ("movl %0, %%esp\n\t" ++ "calll *%1\n" ++ :: "r" (th->stk_base), ++ "r" (rb_thread_start_2)); ++#elif defined(__x86_64__) ++ __asm__ __volatile__ ("movq %0, %%rsp\n\t" ++ "callq *%1\n" ++ :: "r" (th->stk_base), ++ "r" (rb_thread_start_2)); ++#else ++ #error unsupported architecture! ++#endif ++ /* NOTREACHED */ ++ return 0; ++} + +- dummy.prev = ruby_block; +- blk_copy_prev(&dummy); +- saved_block = ruby_block = dummy.prev; +- } +- scope_dup(ruby_scope); ++static VALUE ++rb_thread_start_2() ++{ ++ volatile rb_thread_t th = new_th.th; ++ volatile rb_thread_t th_save = th; ++ volatile VALUE thread = th->thread; ++ struct BLOCK *volatile saved_block = 0; ++ enum rb_thread_status status; ++ int state; ++ struct tag *tag; ++ struct RVarmap *vars; ++ struct FRAME dummy_frame; + +- if (!th->next) { ++ if (!th->next) { + /* merge in thread list */ + th->prev = curr_thread; + curr_thread->next->prev = th; +@@ -12071,13 +12127,27 @@ rb_thread_start_0(fn, arg, th) + curr_thread->next = th; + th->priority = curr_thread->priority; + th->thgroup = curr_thread->thgroup; ++ } ++ curr_thread = th; ++ ++ dummy_frame = *ruby_frame; ++ dummy_frame.prev = top_frame; ++ ruby_frame = &dummy_frame; ++ ++ if (ruby_block) { /* should nail down higher blocks */ ++ struct BLOCK dummy; ++ ++ dummy.prev = ruby_block; ++ blk_copy_prev(&dummy); ++ saved_block = ruby_block = dummy.prev; + } + ++ scope_dup(ruby_scope); ++ + PUSH_TAG(PROT_THREAD); + if ((state = EXEC_TAG()) == 0) { + if (THREAD_SAVE_CONTEXT(th) == 0) { +- curr_thread = th; +- th->result = (*fn)(arg, th); ++ th->result = (*new_th.fn)(new_th.arg, th); + } + th = th_save; + } +@@ -12414,6 +12484,43 @@ rb_thread_cleanup() + END_FOREACH_FROM(curr, th); + } + ++/* ++ * call-seq: ++ * Thread.stack_size => fixnum ++ * ++ * Returns the thread stack size in bytes ++ */ ++static VALUE ++rb_thread_stacksize_get() ++{ ++ return INT2FIX(rb_thread_stack_size); ++} ++ ++/* ++ * call-seq: ++ * Thread.stack_size= fixnum => Qnil ++ * ++ * Sets the global thread stacksize and returns Qnil. ++ */ ++static VALUE ++rb_thread_stacksize_set(obj, val) ++ VALUE obj; ++ VALUE val; ++{ ++ ++ unsigned int size = FIX2UINT(val); ++ ++ /* 16byte alignment works for both x86 and x86_64 */ ++ if (size & (~0xf)) { ++ size += 0x10; ++ size = size & (~0xf); ++ } ++ ++ rb_thread_stack_size = size; ++ ++ return Qnil; ++} ++ + int rb_thread_critical; + + +@@ -13167,6 +13274,8 @@ Init_Thread() + { + VALUE cThGroup; + ++ rb_thread_stack_size = (1024 * 1024); ++ + rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError); + rb_cThread = rb_define_class("Thread", rb_cObject); + rb_undef_alloc_func(rb_cThread); +@@ -13190,6 +13299,9 @@ Init_Thread() + rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0); + rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1); + ++ rb_define_singleton_method(rb_cThread, "stack_size", rb_thread_stacksize_get, 0); ++ rb_define_singleton_method(rb_cThread, "stack_size=", rb_thread_stacksize_set, 1); ++ + rb_define_method(rb_cThread, "run", rb_thread_run, 0); + rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0); + rb_define_method(rb_cThread, "kill", rb_thread_kill, 0); +diff --git a/gc.c b/gc.c +index 318e24c..0746834 100644 +--- a/gc.c ++++ b/gc.c +@@ -466,12 +466,12 @@ stack_end_address(VALUE **stack_end_p) + # define STACK_END (stack_end) + #endif + #if STACK_GROW_DIRECTION < 0 +-# define STACK_LENGTH (rb_gc_stack_start - STACK_END) ++# define STACK_LENGTH(start) ((start) - STACK_END) + #elif STACK_GROW_DIRECTION > 0 +-# define STACK_LENGTH (STACK_END - rb_gc_stack_start + 1) ++# define STACK_LENGTH(start) (STACK_END - (start) + 1) + #else +-# define STACK_LENGTH ((STACK_END < rb_gc_stack_start) ? rb_gc_stack_start - STACK_END\ +- : STACK_END - rb_gc_stack_start + 1) ++# define STACK_LENGTH(start) ((STACK_END < (start)) ? (start) - STACK_END\ ++ : STACK_END - (start) + 1) + #endif + #if STACK_GROW_DIRECTION > 0 + # define STACK_UPPER(x, a, b) a +@@ -494,27 +494,36 @@ stack_grow_direction(addr) + + #define GC_WATER_MARK 512 + +-#define CHECK_STACK(ret) do {\ ++#define CHECK_STACK(ret, start) do {\ + SET_STACK_END;\ +- (ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\ ++ (ret) = (STACK_LENGTH(start) > STACK_LEVEL_MAX + GC_WATER_MARK);\ + } while (0) + + size_t + ruby_stack_length(p) + VALUE **p; + { +- SET_STACK_END; +- if (p) *p = STACK_UPPER(STACK_END, rb_gc_stack_start, STACK_END); +- return STACK_LENGTH; ++ SET_STACK_END; ++ VALUE *start; ++ if (rb_curr_thread == rb_main_thread) { ++ start = rb_gc_stack_start; ++ } else { ++ start = rb_curr_thread->stk_base; ++ } ++ if (p) *p = STACK_UPPER(STACK_END, start, STACK_END); ++ return STACK_LENGTH(start); + } + + int + ruby_stack_check() + { +- int ret; +- +- CHECK_STACK(ret); +- return ret; ++ int ret; ++ if (rb_curr_thread == rb_main_thread) { ++ CHECK_STACK(ret, rb_gc_stack_start); ++ } else { ++ CHECK_STACK(ret, rb_curr_thread->stk_base); ++ } ++ return ret; + } + + #define MARK_STACK_MAX 1024 +@@ -1404,10 +1413,13 @@ garbage_collect() + + init_mark_stack(); + +- gc_mark((VALUE)ruby_current_node, 0); +- + /* mark frame stack */ +- for (frame = ruby_frame; frame; frame = frame->prev) { ++ if (rb_curr_thread == rb_main_thread) ++ frame = ruby_frame; ++ else ++ frame = rb_main_thread->frame; ++ ++ for (; frame; frame = frame->prev) { + rb_gc_mark_frame(frame); + if (frame->tmp) { + struct FRAME *tmp = frame->tmp; +@@ -1417,16 +1429,35 @@ garbage_collect() + } + } + } +- gc_mark((VALUE)ruby_scope, 0); +- gc_mark((VALUE)ruby_dyna_vars, 0); ++ ++ if (rb_curr_thread == rb_main_thread) { ++ gc_mark((VALUE)ruby_current_node, 0); ++ gc_mark((VALUE)ruby_scope, 0); ++ gc_mark((VALUE)ruby_dyna_vars, 0); ++ } else { ++ gc_mark((VALUE)rb_main_thread->node, 0); ++ gc_mark((VALUE)rb_main_thread->scope, 0); ++ gc_mark((VALUE)rb_main_thread->dyna_vars, 0); ++ ++ /* scan the current thread's stack */ ++ rb_gc_mark_locations((VALUE*)STACK_END, rb_curr_thread->stk_base); ++ } ++ + if (finalizer_table) { +- mark_tbl(finalizer_table, 0); ++ mark_tbl(finalizer_table, 0); + } + + FLUSH_REGISTER_WINDOWS; + /* This assumes that all registers are saved into the jmp_buf (and stack) */ + setjmp(save_regs_gc_mark); + mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *)); ++ ++ /* If this is not the main thread, we need to scan the C stack, so ++ * set STACK_END to the end of the C stack. ++ */ ++ if (rb_curr_thread != rb_main_thread) ++ STACK_END = rb_main_thread->stk_pos; ++ + #if STACK_GROW_DIRECTION < 0 + rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start); + #elif STACK_GROW_DIRECTION > 0 +@@ -1446,6 +1477,7 @@ garbage_collect() + rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2), + (VALUE*)((char*)rb_gc_stack_start + 2)); + #endif ++ + rb_gc_mark_threads(); + + /* mark protected global variables */ +diff --git a/lib/logger.rb b/lib/logger.rb +index e9ab171..2564c33 100644 +--- a/lib/logger.rb ++++ b/lib/logger.rb +@@ -170,7 +170,7 @@ require 'monitor' + + class Logger + VERSION = "1.2.6" +- id, name, rev = %w$Id$ ++ id, name, rev = %w$Id logger.rb 1234$ + ProgName = "#{name.chomp(",v")}/#{rev}" + + class Error < RuntimeError; end +diff --git a/node.h b/node.h +index 476a826..ecdc053 100644 +--- a/node.h ++++ b/node.h +@@ -411,8 +411,11 @@ struct rb_thread { + + size_t stk_len; + size_t stk_max; ++ size_t stk_size; + VALUE *stk_ptr; + VALUE *stk_pos; ++ VALUE *stk_base; ++ VALUE *guard; + #ifdef __ia64 + size_t bstr_len; + size_t bstr_max; +diff --git a/signal.c b/signal.c +index b6cad9d..116ac05 100644 +--- a/signal.c ++++ b/signal.c +@@ -14,6 +14,7 @@ + + #include "ruby.h" + #include "rubysig.h" ++#include "node.h" + #include + #include + +@@ -425,15 +426,22 @@ typedef RETSIGTYPE (*sighandler_t)_((int)); + static sighandler_t + ruby_signal(signum, handler) + int signum; +- sighandler_t handler; ++ void *handler; + { + struct sigaction sigact, old; + + rb_trap_accept_nativethreads[signum] = 0; + +- sigact.sa_handler = handler; ++ if (signum == SIGSEGV || signum == SIGBUS) { ++ sigact.sa_sigaction = handler; ++ sigact.sa_flags = (SA_ONSTACK | SA_RESETHAND | SA_SIGINFO); ++ } else { ++ sigact.sa_handler = handler; ++ sigact.sa_flags = 0; ++ } ++ + sigemptyset(&sigact.sa_mask); +- sigact.sa_flags = 0; ++ + # ifdef SA_NOCLDWAIT + if (signum == SIGCHLD && handler == SIG_IGN) + sigact.sa_flags |= SA_NOCLDWAIT; +@@ -596,7 +604,132 @@ sighandler(sig) + } + } + ++#include ++#ifdef HAVE_STDARG_PROTOTYPES ++#include ++#define va_init_list(a,b) va_start(a,b) ++#else ++#include ++#define va_init_list(a,b) va_start(a) ++#endif ++ ++void ++#ifdef HAVE_STDARG_PROTOTYPES ++sig_printf(const char *fmt, ...) ++#else ++ sig_printf(fmt, va_alist) ++ const char *fmt; ++ va_dcl ++#endif ++{ ++ char buf[BUFSIZ]; ++ va_list args; ++ FILE *out = stderr; ++ ++ va_init_list(args, fmt); ++ vfprintf(out, fmt, args); ++ va_end(args); ++ fprintf(out, "\n"); ++} ++ ++static void ++dump_machine_state(uc) ++ ucontext_t *uc; ++{ ++ const char *dump64 = ++ " ----------------- Register state dump ----------------------\n" ++ "rax = 0x%.16x rbx = 0x%.16x rcx = 0x%.16x rdx = 0x%.16x\n" ++ "rdi = 0x%.16x rsi = 0x%.16x rbp = 0x%.16x rsp = 0x%.16x\n" ++ "r8 = 0x%.16x r9 = 0x%.16x r10 = 0x%.16x r11 = 0x%.16x\n" ++ "r12 = 0x%.16x r13 = 0x%.16x r14 = 0x%.16x r15 = 0x%.16x\n" ++ "rip = 0x%.16x rflags = 0x%.16x cs = 0x%.16x fs = 0x%.16x\n" ++ "gs = 0x%.16x"; ++ ++ const char *dump32 = ++ " ----------------- Register state dump -------------------\n" ++ "eax = 0x%.8x ebx = 0x%.8x ecx = 0x%.8x edx = 0x%.8x\n" ++ "edi = 0x%.8x esi = 0x%.8x ebp = 0x%.8x esp = 0x%.8x\n" ++ "ss = 0x%.8x eflags = 0x%.8x eip = 0x%.8x cs = 0x%.8x\n" ++ "ds = 0x%.8x es = 0x%.8x fs = 0x%.8x gs = 0x%.8x\n"; ++ ++#if defined(__LP64__) && defined(__APPLE__) ++ sig_printf(dump64, uc->uc_mcontext->__ss.__rax, uc->uc_mcontext->__ss.__rbx, ++ uc->uc_mcontext->__ss.__rcx, uc->uc_mcontext->__ss.__rdx, uc->uc_mcontext->__ss.__rdi, ++ uc->uc_mcontext->__ss.__rsi, uc->uc_mcontext->__ss.__rbp, uc->uc_mcontext->__ss.__rsp, ++ uc->uc_mcontext->__ss.__r8, uc->uc_mcontext->__ss.__r9, uc->uc_mcontext->__ss.__r10, ++ uc->uc_mcontext->__ss.__r11, uc->uc_mcontext->__ss.__r12, uc->uc_mcontext->__ss.__r13, ++ uc->uc_mcontext->__ss.__r14, uc->uc_mcontext->__ss.__r15, uc->uc_mcontext->__ss.__rip, ++ uc->uc_mcontext->__ss.__rflags, uc->uc_mcontext->__ss.__cs, uc->uc_mcontext->__ss.__fs, ++ uc->uc_mcontext->__ss.__gs); ++#elif !defined(__LP64__) && defined(__APPLE__) ++ sig_printf(dump32, uc->uc_mcontext->__ss.__eax, uc->uc_mcontext->__ss.__ebx, ++ uc->uc_mcontext->__ss.__ecx, uc->uc_mcontext->__ss.__edx, ++ uc->uc_mcontext->__ss.__edi, uc->uc_mcontext->__ss.__esi, ++ uc->uc_mcontext->__ss.__ebp, uc->uc_mcontext->__ss.__esp, ++ uc->uc_mcontext->__ss.__ss, uc->uc_mcontext->__ss.__eflags, ++ uc->uc_mcontext->__ss.__eip, uc->uc_mcontext->__ss.__cs, ++ uc->uc_mcontext->__ss.__ds, uc->uc_mcontext->__ss.__es, ++ uc->uc_mcontext->__ss.__fs, uc->uc_mcontext->__ss.__gs); ++#elif defined(__i386__) ++ sig_printf(dump32, uc->uc_mcontext.gregs[REG_EAX], uc->uc_mcontext.gregs[REG_EBX], ++ uc->uc_mcontext.gregs[REG_ECX], uc->uc_mcontext.gregs[REG_EDX], ++ uc->uc_mcontext.gregs[REG_EDI], uc->uc_mcontext.gregs[REG_ESI], ++ uc->uc_mcontext.gregs[REG_EBP], uc->uc_mcontext.gregs[REG_ESP], ++ uc->uc_mcontext.gregs[REG_SS], uc->uc_mcontext.gregs[REG_EFL], ++ uc->uc_mcontext.gregs[REG_EIP], uc->uc_mcontext.gregs[REG_EIP], ++ uc->uc_mcontext.gregs[REG_DS], uc->uc_mcontext.gregs[REG_ES], ++ uc->uc_mcontext.gregs[REG_FS], uc->uc_mcontext.gregs[REG_FS]); ++#elif defined(__x86_64__) ++ sig_printf(dump64, uc->uc_mcontext.gregs[REG_RAX], uc->uc_mcontext.gregs[REG_RBX], ++ uc->uc_mcontext.gregs[REG_RCX], uc->uc_mcontext.gregs[REG_RDX], ++ uc->uc_mcontext.gregs[REG_RDI], uc->uc_mcontext.gregs[REG_RSI], ++ uc->uc_mcontext.gregs[REG_RBP], uc->uc_mcontext.gregs[REG_RSP], ++ uc->uc_mcontext.gregs[REG_R8], uc->uc_mcontext.gregs[REG_R9], ++ uc->uc_mcontext.gregs[REG_R10], uc->uc_mcontext.gregs[REG_R11], ++ uc->uc_mcontext.gregs[REG_R12], uc->uc_mcontext.gregs[REG_R13], ++ uc->uc_mcontext.gregs[REG_R14], uc->uc_mcontext.gregs[REG_R15], ++ uc->uc_mcontext.gregs[REG_RIP], uc->uc_mcontext.gregs[REG_EFL], ++ uc->uc_mcontext.gregs[REG_CSGSFS]); ++#else ++#endif ++} ++ ++static int ++check_guard(caddr_t fault_addr, rb_thread_t th) { ++ if(fault_addr <= (caddr_t)rb_curr_thread->guard && ++ fault_addr >= (caddr_t)rb_curr_thread->stk_ptr) { ++ return 1; ++ } ++ return 0; ++} ++ + #ifdef SIGBUS ++#ifdef POSIX_SIGNAL ++static void sigbus _((int, siginfo_t*, void*)); ++static void ++sigbus(sig, ip, context) ++ int sig; ++ siginfo_t *ip; ++ void *context; ++{ ++#if defined(HAVE_NATIVETHREAD) && defined(HAVE_NATIVETHREAD_KILL) ++ if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) { ++ sigsend_to_ruby_thread(sig); ++ return; ++ } ++#endif ++ ++ dump_machine_state(context); ++ if (check_guard((caddr_t)ip->si_addr, rb_curr_thread)) { ++ /* we hit the guard page, print out a warning to help app developers */ ++ rb_bug("Thread stack overflow! Try increasing it!"); ++ } else { ++ rb_bug("Bus Error"); ++ } ++} ++ ++#else /* !defined(POSIX_SIGNAL) */ ++ + static RETSIGTYPE sigbus _((int)); + static RETSIGTYPE + sigbus(sig) +@@ -612,8 +745,36 @@ sigbus(sig) + rb_bug("Bus Error"); + } + #endif ++#endif ++ + + #ifdef SIGSEGV ++#ifdef POSIX_SIGNAL ++static void sigsegv _((int, siginfo_t*, void*)); ++static void ++sigsegv(sig, ip, context) ++ int sig; ++ siginfo_t *ip; ++ void *context; ++{ ++#if defined(HAVE_NATIVETHREAD) && defined(HAVE_NATIVETHREAD_KILL) ++ if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) { ++ sigsend_to_ruby_thread(sig); ++ return; ++ } ++#endif ++ ++ dump_machine_state(context); ++ if (check_guard((caddr_t)ip->si_addr, rb_curr_thread)) { ++ /* we hit the guard page, print out a warning to help app developers */ ++ rb_bug("Thread stack overflow! Try increasing it!"); ++ } else { ++ rb_bug("Segmentation fault"); ++ } ++} ++ ++#else /* !defined(POSIX_SIGNAL) */ ++ + static RETSIGTYPE sigsegv _((int)); + static RETSIGTYPE + sigsegv(sig) +@@ -629,6 +790,7 @@ sigsegv(sig) + rb_bug("Segmentation fault"); + } + #endif ++#endif + + #ifdef SIGPIPE + static RETSIGTYPE sigpipe _((int)); +@@ -698,7 +860,8 @@ static VALUE + trap(arg) + struct trap_arg *arg; + { +- sighandler_t func, oldfunc; ++ sighandler_t oldfunc; ++ void *func; + VALUE command, oldcmd; + int sig = -1; + char *s; +@@ -945,6 +1108,20 @@ sig_list() + } + + static void ++create_sigstack() ++{ ++ stack_t ss; ++ ss.ss_size = SIGSTKSZ; ++ ss.ss_sp = malloc(ss.ss_size); ++ ss.ss_flags = 0; ++ if (sigaltstack(&ss, NULL) < 0) { ++ free(ss.ss_sp); ++ fprintf(stderr, "Couldn't create signal stack! Error %d: %s\n", errno, strerror(errno)); ++ exit(1); ++ } ++} ++ ++static void + install_sighandler(signum, handler) + int signum; + sighandler_t handler; +@@ -953,7 +1130,7 @@ install_sighandler(signum, handler) + + old = ruby_signal(signum, handler); + if (old != SIG_DFL) { +- ruby_signal(signum, old); ++ ruby_signal(signum, old); + } + } + +@@ -1080,6 +1257,8 @@ Init_signal() + rb_alias(rb_eSignal, rb_intern("signm"), rb_intern("message")); + rb_define_method(rb_eInterrupt, "initialize", interrupt_init, 1); + ++ create_sigstack(); ++ + install_sighandler(SIGINT, sighandler); + #ifdef SIGHUP + install_sighandler(SIGHUP, sighandler); diff --git a/patches/ruby/1.8.6/mbari.patch b/patches/ruby/1.8.6/mbari.patch new file mode 100644 index 0000000000..75eb4d84ae --- /dev/null +++ b/patches/ruby/1.8.6/mbari.patch @@ -0,0 +1,5555 @@ +diff --git a/ChangeLog b/ChangeLog +index e66e305..e4c539a 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,20 @@ ++Wed Feb 27 12:01:19 2009 Brent Roman ++ ++ * rubysig.c: added support for __anyPowerPC__ ++ ++ * version.h: bumped date ++ ++Mon Feb 25 10:53:52 2008 Brent Roman ++ ++ * backported MBARI 8A patches still ++ fails YAML test_object_id_collision ++ ++Mon Feb 16 10:53:52 2008 Brent Roman ++ ++ * backport from 1.8.7p72-mbari of MBARI patches described at ++ http://sites.google.com/site/brentsrubypatches ++ fails YAML test_object_id_collision ++ + Fri Aug 8 10:53:52 2008 Tanaka Akira + + * lib/resolv.rb: randomize source port and transaction id. +diff --git a/common.mk b/common.mk +index 6d5b35d..3e43e41 100644 +--- a/common.mk ++++ b/common.mk +@@ -441,7 +441,7 @@ variable.$(OBJEXT): {$(VPATH)}variable.c {$(VPATH)}ruby.h config.h \ + {$(VPATH)}env.h {$(VPATH)}node.h {$(VPATH)}st.h {$(VPATH)}util.h + version.$(OBJEXT): {$(VPATH)}version.c {$(VPATH)}ruby.h config.h \ + {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ +- {$(VPATH)}version.h ++ {$(VPATH)}rubysig.h {$(VPATH)}version.h + + dist: $(PROGRAM) + $(RUNRUBY) $(srcdir)/distruby.rb +diff --git a/configure.in b/configure.in +index c775862..aafeb30 100644 +--- a/configure.in ++++ b/configure.in +@@ -139,6 +139,24 @@ AC_ARG_ENABLE(frame-address, + if test $frame_address = yes; then + AC_DEFINE(USE_BUILTIN_FRAME_ADDRESS) + fi ++AC_ARG_ENABLE(mbari-api, ++ [ --enable-mbari-api enable API changes from the MBARI patches. ], ++ [mbari_api=$enableval]) ++if test "$mbari_api" = yes; then ++ AC_DEFINE(MBARI_API) ++fi ++AC_ARG_WITH(wipe-sites, ++[ --with-wipe-sites=MASK override default STACK_WIPES_SITES mask in rubysig.h], ++[wipe_sites=$withval]) ++if test "$wipe_sites" != ""; then ++ case $wipe_sites in ++ none|no) wipe_sites=0x0;; ++ yes) wipe_sites=;; ++ esac ++ if test -n "$wipe_sites"; then ++ AC_DEFINE_UNQUOTED(STACK_WIPE_SITES,$wipe_sites) ++ fi ++fi + + AC_ARG_PROGRAM + +diff --git a/eval.c b/eval.c +index 54a0fee..8002203 100644 +--- a/eval.c ++++ b/eval.c +@@ -222,9 +222,9 @@ VALUE rb_cProc; + VALUE rb_cBinding; + static VALUE proc_invoke _((VALUE,VALUE,VALUE,VALUE)); + static VALUE rb_f_binding _((VALUE)); +-static void rb_f_END _((void)); ++NOINLINE(static void rb_f_END _((void))); + static VALUE rb_f_block_given_p _((void)); +-static VALUE block_pass _((VALUE,NODE*)); ++static VALUE block_pass _((volatile VALUE, NODE *volatile)); + + VALUE rb_cMethod; + static VALUE method_call _((int, VALUE*, VALUE)); +@@ -246,6 +246,30 @@ static int scope_vmode; + VALUE (*ruby_sandbox_save)_((rb_thread_t)); + VALUE (*ruby_sandbox_restore)_((rb_thread_t)); + NODE* ruby_current_node; ++ ++#if 0 ++#define SET_CURRENT_SOURCE() (ruby_sourcefile = ruby_current_node->nd_file, \ ++ ruby_sourceline = nd_line(ruby_current_node)) ++#else ++#define SET_CURRENT_SOURCE() ((void)0) ++#endif ++ ++void ++ruby_set_current_source() ++{ ++ if (ruby_current_node) { ++ ruby_sourcefile = ruby_current_node->nd_file; ++ ruby_sourceline = nd_line(ruby_current_node); ++ } ++} ++ ++#ifdef MBARI_API ++#define SET_METHOD_SOURCE() ruby_set_current_source() ++#else ++#define SET_METHOD_SOURCE() (void)0 ++#endif ++ ++ + int ruby_safe_level = 0; + /* safe-level: + 0 - strings from streams/environment/ARGV are tainted (default) +@@ -490,7 +514,7 @@ rb_get_method_body(klassp, idp, noexp) + { + ID id = *idp; + VALUE klass = *klassp; +- VALUE origin; ++ VALUE origin = 0; + NODE * volatile body; + struct cache_entry *ent; + +@@ -729,6 +753,7 @@ rb_attr(klass, id, read, write, ex) + if (!name) { + rb_raise(rb_eArgError, "argument needs to be symbol or string"); + } ++ SET_METHOD_SOURCE(); + len = strlen(name)+2; + buf = ALLOCA_N(char,len); + snprintf(buf, len, "@%s", name); +@@ -769,11 +794,11 @@ static unsigned long frame_unique = 0; + _frame.argc = 0; \ + _frame.flags = 0; \ + _frame.uniq = frame_unique++; \ +- ruby_frame = &_frame ++ ruby_frame = (struct FRAME *)&_frame + + #define POP_FRAME() \ + ruby_current_node = _frame.node; \ +- ruby_frame = _frame.prev; \ ++ ruby_frame = _frame.prev; \ + } while (0) + + struct BLOCK { +@@ -967,7 +992,7 @@ rb_svar(cnt) + ID id; + + if (!ruby_scope->local_tbl) return NULL; +- if (cnt >= ruby_scope->local_tbl[0]) return NULL; ++ if ((ID)cnt >= ruby_scope->local_tbl[0]) return NULL; + id = ruby_scope->local_tbl[cnt+1]; + while (vars) { + if (vars->id == id) return &vars->val; +@@ -1030,7 +1055,26 @@ static struct tag *prot_tag; + #define PROT_LAMBDA INT2FIX(2) /* 5 */ + #define PROT_YIELD INT2FIX(3) /* 7 */ + +-#define EXEC_TAG() (FLUSH_REGISTER_WINDOWS, ruby_setjmp(((void)0), prot_tag->buf)) ++#if STACK_WIPE_SITES & 0x42 ++#ifdef __GNUC__ ++static inline int wipeAfter(int) __attribute__((always_inline)); ++#endif ++static inline int wipeAfter(int status) ++{ ++ rb_gc_wipe_stack(); ++ return status; ++} ++#else ++#define wipeAfter(status) status ++#endif ++#if STACK_WIPE_SITES & 2 ++#define wipeAfterTag(status) wipeAfter(status) ++#else ++#define wipeAfterTag(status) status ++#endif ++ ++#define EXEC_TAG_0() ruby_setjmp(((void)0), prot_tag->buf) ++#define EXEC_TAG() wipeAfterTag(EXEC_TAG_0()) + + #define JUMP_TAG(st) do { \ + ruby_frame = prot_tag->frame; \ +@@ -1106,10 +1150,17 @@ static void scope_dup _((struct SCOPE *)); + } while (0) + + static VALUE rb_eval _((VALUE,NODE*)); +-static VALUE eval _((VALUE,VALUE,VALUE,char*,int)); +-static NODE *compile _((VALUE, char*, int)); ++static VALUE eval _((VALUE,VALUE,volatile VALUE,const char* volatile,int)); ++static NODE *compile _((VALUE, const char*, int)); + +-static VALUE rb_yield_0 _((VALUE, VALUE, VALUE, int, int)); ++static VALUE rb_yield_0 ++ _((volatile VALUE, volatile VALUE, VALUE, int, volatile int)); ++ ++#if STACK_WIPE_SITES & 0x20 ++#define wipeBeforeYield() rb_gc_wipe_stack() ++#else ++#define wipeBeforeYield() (void)0 ++#endif + + #define YIELD_LAMBDA_CALL 1 + #define YIELD_PROC_CALL 2 +@@ -1118,7 +1169,7 @@ static VALUE rb_yield_0 _((VALUE, VALUE, VALUE, int, int)); + #define YIELD_FUNC_SVALUE 2 + + static VALUE rb_call _((VALUE,VALUE,ID,int,const VALUE*,int,VALUE)); +-static VALUE module_setup _((VALUE,NODE*)); ++static VALUE module_setup _((VALUE,NODE *volatile)); + + static VALUE massign _((VALUE,NODE*,VALUE,int)); + static void assign _((VALUE,NODE*,VALUE,int)); +@@ -1150,22 +1201,6 @@ static VALUE trace_func = 0; + static int tracing = 0; + static void call_trace_func _((rb_event_t,NODE*,VALUE,ID,VALUE)); + +-#if 0 +-#define SET_CURRENT_SOURCE() (ruby_sourcefile = ruby_current_node->nd_file, \ +- ruby_sourceline = nd_line(ruby_current_node)) +-#else +-#define SET_CURRENT_SOURCE() ((void)0) +-#endif +- +-void +-ruby_set_current_source() +-{ +- if (ruby_current_node) { +- ruby_sourcefile = ruby_current_node->nd_file; +- ruby_sourceline = nd_line(ruby_current_node); +- } +-} +- + static void + #ifdef HAVE_STDARG_PROTOTYPES + warn_printf(const char *fmt, ...) +@@ -1227,20 +1262,15 @@ set_backtrace(info, bt) + static void + error_print() + { +- VALUE errat = Qnil; /* OK */ ++ VALUE errat; + volatile VALUE eclass, e; +- char *einfo; ++ const char * einfo; + long elen; + + if (NIL_P(ruby_errinfo)) return; + + PUSH_TAG(PROT_NONE); +- if (EXEC_TAG() == 0) { +- errat = get_backtrace(ruby_errinfo); +- } +- else { +- errat = Qnil; +- } ++ errat = EXEC_TAG() ? Qnil : get_backtrace(ruby_errinfo); + if (EXEC_TAG()) goto error; + if (NIL_P(errat)){ + ruby_set_current_source(); +@@ -1422,7 +1452,7 @@ ruby_init() + } + + static VALUE +-eval_node(self, node) ++eval_tree(self, node) + VALUE self; + NODE *node; + { +@@ -1571,12 +1601,13 @@ ruby_finalize() + } + + int +-ruby_cleanup(ex) +- int ex; ++ruby_cleanup(exArg) ++ int exArg; + { + int state; + volatile VALUE errs[2]; +- int nerr; ++ unsigned nerr; ++ volatile int ex = exArg; + + errs[1] = ruby_errinfo; + ruby_safe_level = 0; +@@ -1639,7 +1670,7 @@ ruby_exec_internal() + /* default visibility is private at toplevel */ + SCOPE_SET(SCOPE_PRIVATE); + if ((state = EXEC_TAG()) == 0) { +- eval_node(ruby_top_self, ruby_eval_tree); ++ eval_tree(ruby_top_self, ruby_eval_tree); + } + POP_ITER(); + POP_TAG(); +@@ -1847,8 +1878,8 @@ rb_eval_cmd(cmd, arg, level) + int level; + { + int state; +- VALUE val = Qnil; /* OK */ +- struct SCOPE *saved_scope; ++ VALUE val; ++ struct SCOPE * volatile saved_scope; + volatile int safe = ruby_safe_level; + + if (OBJ_TAINTED(cmd)) { +@@ -1879,9 +1910,7 @@ rb_eval_cmd(cmd, arg, level) + ruby_safe_level = level; + + PUSH_TAG(PROT_NONE); +- if ((state = EXEC_TAG()) == 0) { +- val = eval(ruby_top_self, cmd, Qnil, 0, 0); +- } ++ val = (state = EXEC_TAG()) ? Qnil : eval(ruby_top_self, cmd, Qnil, 0, 0); + if (ruby_scope->flags & SCOPE_DONT_RECYCLE) + scope_dup(saved_scope); + ruby_scope = saved_scope; +@@ -1920,6 +1949,10 @@ ev_const_defined(cref, id, self) + return rb_const_defined(cref->nd_clss, id); + } + ++NOINLINE(static VALUE ev_const_get _((NODE *cref, ID id, VALUE self))); ++NOINLINE(static void eval_cvar_set _((NODE *node, VALUE result, int warn))); ++NOINLINE(static void eval_cdecl _((VALUE self, NODE *node, VALUE value))); ++ + static VALUE + ev_const_get(cref, id, self) + NODE *cref; +@@ -2032,7 +2065,7 @@ void + rb_frozen_class_p(klass) + VALUE klass; + { +- char *desc = "something(?!)"; ++ const char *desc = "something(?!)"; + + if (OBJ_FROZEN(klass)) { + if (FL_TEST(klass, FL_SINGLETON)) +@@ -2070,7 +2103,7 @@ rb_undef(klass, id) + } + body = search_method(klass, id, &origin); + if (!body || !body->nd_body) { +- char *s0 = " class"; ++ const char *s0 = " class"; + VALUE c = klass; + + if (FL_TEST(c, FL_SINGLETON)) { +@@ -2161,7 +2194,7 @@ rb_alias(klass, name, def) + VALUE klass; + ID name, def; + { +- VALUE origin; ++ VALUE origin = 0; + NODE *orig, *body, *node; + VALUE singleton = 0; + st_data_t data; +@@ -2247,7 +2280,10 @@ rb_copy_node_scope(node, rval) + NODE *node; + NODE *rval; + { +- NODE *copy = NEW_NODE(NODE_SCOPE,0,rval,node->nd_next); ++ NODE *copy; ++ ++ SET_METHOD_SOURCE(); ++ copy=NEW_NODE(NODE_SCOPE,0,rval,node->nd_next); + + if (node->nd_tbl) { + copy->nd_tbl = ALLOC_N(ID, node->nd_tbl[0]+1); +@@ -2322,9 +2358,9 @@ rb_copy_node_scope(node, rval) + + #define MATCH_DATA *rb_svar(node->nd_cnt) + +-static char* is_defined _((VALUE, NODE*, char*)); ++static const char* is_defined _((VALUE, NODE*, char*)); + +-static char* ++static const char* + arg_defined(self, node, buf, type) + VALUE self; + NODE *node; +@@ -2351,13 +2387,13 @@ arg_defined(self, node, buf, type) + return type; + } + +-static char* ++static const char* + is_defined(self, node, buf) + VALUE self; +- NODE *node; /* OK */ ++ NODE *node; + char *buf; + { +- VALUE val; /* OK */ ++ VALUE val; + int state; + + again: +@@ -2671,27 +2707,27 @@ set_trace_func(obj, trace) + return trace; + } + +-static char * ++static const char * + get_event_name(rb_event_t event) + { + switch (event) { +- case RUBY_EVENT_LINE: ++ case RUBY_EVENT_LINE: + return "line"; +- case RUBY_EVENT_CLASS: ++ case RUBY_EVENT_CLASS: + return "class"; +- case RUBY_EVENT_END: ++ case RUBY_EVENT_END: + return "end"; +- case RUBY_EVENT_CALL: ++ case RUBY_EVENT_CALL: + return "call"; +- case RUBY_EVENT_RETURN: ++ case RUBY_EVENT_RETURN: + return "return"; +- case RUBY_EVENT_C_CALL: ++ case RUBY_EVENT_C_CALL: + return "c-call"; +- case RUBY_EVENT_C_RETURN: ++ case RUBY_EVENT_C_RETURN: + return "c-return"; +- case RUBY_EVENT_RAISE: ++ case RUBY_EVENT_RAISE: + return "raise"; +- default: ++ default: + return "unknown"; + } + } +@@ -2702,14 +2738,15 @@ call_trace_func(event, node, self, id, klass) + NODE *node; + VALUE self; + ID id; +- VALUE klass; /* OK */ ++ VALUE klass; + { +- int state, raised; ++ int state; ++ volatile int raised; + struct FRAME *prev; +- NODE *node_save; ++ NODE * volatile node_save; + VALUE srcfile; +- char *event_name; +- rb_thread_t th = curr_thread; ++ const char *event_name; ++ volatile rb_thread_t th = curr_thread; + + if (!trace_func) return; + if (tracing) return; +@@ -2918,11 +2955,11 @@ class_prefix(self, cpath) + NORETURN(static void return_jump _((VALUE))); + NORETURN(static void break_jump _((VALUE))); + NORETURN(static void next_jump _((VALUE))); +-NORETURN(static void unknown_node _((NODE * volatile))); ++NORETURN(static void unknown_node _((NODE *))); + + static void + unknown_node(node) +- NODE *volatile node; ++ NODE *node; + { + ruby_current_node = 0; + if (node->flags == 0) { +@@ -2936,40 +2973,886 @@ unknown_node(node) + } + } + +-static VALUE +-rb_eval(self, n) +- VALUE self; +- NODE *n; ++/* ++ * functions factored out of rb_eval() to reduce its stack frame size ++ */ ++#define eval_node_0(n,retType, self, node) \ ++NOINLINE(static retType TOKEN_PASTE(eval_,n) _((self, node)));\ ++static retType TOKEN_PASTE(eval_,n)(self, node) ++ ++#define eval_node(n,retType) \ ++ eval_node_0(n,retType, VALUE self, NODE *node) ++#define eval_node_volatile(n,retType) \ ++ eval_node_0(n,retType, volatile VALUE self, NODE * volatile node) ++ ++eval_node(match2, VALUE) ++{ ++ VALUE l = rb_eval(self,node->nd_recv); ++ VALUE r = rb_eval(self,node->nd_value); ++ return rb_reg_match(l, r); ++} ++ ++eval_node(match3, VALUE) + { +- NODE * volatile contnode = 0; +- NODE * volatile node = n; ++ VALUE r = rb_eval(self,node->nd_recv); ++ VALUE l = rb_eval(self,node->nd_value); ++ return TYPE(l) == T_STRING ? rb_reg_match(r, l) : rb_funcall(l, match, 1, r); ++} ++ ++ ++eval_node_volatile(opt_n, void) ++{ ++ int state; ++ PUSH_TAG(PROT_LOOP); ++ switch (state = EXEC_TAG()) { ++ case TAG_NEXT: ++ state = 0; ++ case 0: ++ while (!NIL_P(rb_gets())) { ++ opt_n_redo: ++ rb_eval(self, node->nd_body); ++ } ++ break; ++ ++ case TAG_REDO: ++ state = 0; ++ goto opt_n_redo; ++ ++ case TAG_BREAK: ++ state = 0; ++ default: ++ break; ++ } ++ POP_TAG(); ++ if (state) JUMP_TAG(state); ++} ++ ++ ++eval_node(when, NODE*) ++{ ++ do { ++ NODE *tag = node->nd_head; ++ while (tag) { ++ EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self, ++ ruby_frame->last_func, ++ ruby_frame->last_class); ++ if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) { ++ VALUE v = rb_eval(self, tag->nd_head->nd_head); ++ long i; ++ ++ if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v); ++ for (i=0; ilen; i++) { ++ if (RTEST(RARRAY(v)->ptr[i])) return node->nd_body; ++ } ++ tag = tag->nd_next; ++ continue; ++ } ++ if (RTEST(rb_eval(self, tag->nd_head))) return node->nd_body; ++ tag = tag->nd_next; ++ } ++ } while ((node = node->nd_next) && nd_type(node) == NODE_WHEN); ++ return node; ++} ++ ++ ++eval_node(case, NODE*) ++{ ++ VALUE val = rb_eval(self, node->nd_head); ++ node = node->nd_body; ++ while (node) { ++ NODE *tag; ++ ++ if (nd_type(node) != NODE_WHEN) break; ++ tag = node->nd_head; ++ while (tag) { ++ EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self, ++ ruby_frame->last_func, ++ ruby_frame->last_class); ++ if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) { ++ VALUE v = rb_eval(self, tag->nd_head->nd_head); ++ long i; ++ ++ if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v); ++ for (i=0; ilen; i++) { ++ if (RTEST(rb_funcall2(RARRAY(v)->ptr[i], eqq, 1, &val))) ++ return node->nd_body; ++ } ++ tag = tag->nd_next; ++ continue; ++ } ++ if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head), eqq, 1, &val))) ++ return node->nd_body; ++ tag = tag->nd_next; ++ } ++ node = node->nd_next; ++ } ++ return node; ++} ++ ++ ++eval_node_volatile(while, VALUE) ++{ ++ int state; ++ VALUE result; ++ PUSH_TAG(PROT_LOOP); ++ switch (state = EXEC_TAG()) { ++ case 0: ++ if (!(node->nd_state) || RTEST(rb_eval(self, node->nd_cond))) { ++ do { ++ while_redo: ++#if STACK_WIPE_SITES & 0x10 ++ rb_gc_wipe_stack(); ++#endif ++ rb_eval(self, node->nd_body); ++ while_next: ++ ; ++ } while (RTEST(rb_eval(self, node->nd_cond))); ++ } /* fall thru */ ++ default: ++ result=Qnil; ++ break; ++ ++ case TAG_REDO: ++ state = 0; ++ goto while_redo; ++ case TAG_NEXT: ++ state = 0; ++ goto while_next; ++ case TAG_BREAK: ++ if (TAG_DST()) { ++ state = 0; ++ result = prot_tag->retval; ++ } ++ } ++ POP_TAG(); ++ if (state) JUMP_TAG(state); ++ return result; ++} ++ ++ ++eval_node_volatile(until, VALUE) ++{ ++ int state; ++ VALUE result; ++ PUSH_TAG(PROT_LOOP); ++ switch (state = EXEC_TAG()) { ++ case 0: ++ if (!(node->nd_state) || !RTEST(rb_eval(self, node->nd_cond))) { ++ do { ++ until_redo: ++ #if STACK_WIPE_SITES & 0x10 ++ rb_gc_wipe_stack(); ++ #endif ++ rb_eval(self, node->nd_body); ++ until_next: ++ ; ++ } while (!RTEST(rb_eval(self, node->nd_cond))); ++ } /* fall thru */ ++ default: ++ result=Qnil; ++ break; ++ ++ case TAG_REDO: ++ state = 0; ++ goto until_redo; ++ case TAG_NEXT: ++ state = 0; ++ goto until_next; ++ case TAG_BREAK: ++ if (TAG_DST()) { ++ state = 0; ++ result = prot_tag->retval; ++ } ++ } ++ POP_TAG(); ++ if (state) JUMP_TAG(state); ++ return result; ++} ++ ++ ++eval_node_volatile(iter, VALUE) ++{ ++ int state; ++ VALUE result; ++ ++ PUSH_TAG(PROT_LOOP); ++ PUSH_BLOCK(node->nd_var, node->nd_body); ++ ++ state = EXEC_TAG(); ++ switch (state) { ++ case TAG_RETRY: ++ state = 0; /* fall thru to case 0 */ ++ case 0: ++ PUSH_ITER(ITER_PRE); ++ if (nd_type(node) == NODE_ITER) { ++ result = rb_eval(self, node->nd_iter); ++ } ++ else { ++ _block.flags &= ~BLOCK_D_SCOPE; ++ BEGIN_CALLARGS; ++ result = rb_eval(self, node->nd_iter); ++ END_CALLARGS; ++ ruby_current_node = (NODE *)node; ++ SET_CURRENT_SOURCE(); ++ result = rb_call(CLASS_OF(result),result,each,0,0,0,self); ++ } ++ POP_ITER(); ++ break; ++ ++ case TAG_BREAK: ++ if (TAG_DST()) { ++ result = prot_tag->retval; ++ state = 0; ++ } ++ } ++ POP_BLOCK(); ++ POP_TAG(); ++ if (state) JUMP_TAG(state); ++ return result; ++} ++ ++ ++eval_node_volatile(rescue, VALUE) ++{ ++ volatile VALUE e_info = ruby_errinfo; ++ volatile int rescuing = 0; + int state; +- volatile VALUE result = Qnil; +- st_data_t data; ++ VALUE result; + +-#define RETURN(v) do { \ +- result = (v); \ +- goto finish; \ +-} while (0) ++ PUSH_TAG(PROT_NONE); ++ if ((state = EXEC_TAG()) == 0) { ++ retry_entry: ++ result = rb_eval(self, node->nd_head); ++ } ++ else if (rescuing) { ++ if (rescuing < 0) { ++ /* in rescue argument, just reraise */ ++ result = Qnil; ++ } ++ else if (state == TAG_RETRY) { ++ rescuing = state = 0; ++ ruby_errinfo = e_info; ++ goto retry_entry; ++ } ++ else if (state != TAG_RAISE) { ++ result = prot_tag->retval; ++ } ++ } ++ else if (state == TAG_RAISE) { ++ NODE *resq = node->nd_resq; ++ ++ rescuing = -1; ++ while (resq) { ++ ruby_current_node = resq; ++ if (handle_rescue(self, resq)) { ++ state = 0; ++ rescuing = 1; ++ result = rb_eval(self, resq->nd_body); ++ break; ++ } ++ resq = resq->nd_head; /* next rescue */ ++ } ++ } ++ else { ++ result = prot_tag->retval; ++ } ++ POP_TAG(); ++ if (state != TAG_RAISE) ruby_errinfo = e_info; ++ if (state) { ++ JUMP_TAG(state); ++ } ++ /* no exception raised */ ++ if (!rescuing && node->nd_else) { /* else clause given */ ++ result = Qundef; /* caller must eval this! */ ++ } ++ return result; ++} ++ ++ ++eval_node_volatile(ensure, VALUE) ++{ ++ int state; ++ VALUE result; ++ ++ PUSH_TAG(PROT_NONE); ++ if ((state = EXEC_TAG()) == 0) { ++ result = rb_eval(self, node->nd_head); ++ } ++ POP_TAG(); ++ if (node->nd_ensr && !thread_no_ensure()) { ++ VALUE retval = prot_tag->retval; /* save retval */ ++ VALUE errinfo = ruby_errinfo; ++ ++ rb_eval(self, node->nd_ensr); ++ return_value(retval); ++ ruby_errinfo = errinfo; ++ } ++ if (state) JUMP_TAG(state); ++ return result; ++} ++ ++ ++eval_node(dot, VALUE) ++{ ++ VALUE beg = rb_eval(self, node->nd_beg); ++ VALUE end = rb_eval(self, node->nd_end); ++ return rb_range_new(beg, end, nd_type(node) == NODE_DOT3); ++} ++ ++ ++eval_node(flip2, VALUE) ++{ ++ VALUE *flip = rb_svar(node->nd_cnt); ++ if (!flip) rb_bug("unexpected local variable"); ++ if (!RTEST(*flip)) { ++ if (!RTEST(rb_eval(self, node->nd_beg))) ++ return Qfalse; ++ *flip = RTEST(rb_eval(self, node->nd_end))?Qfalse:Qtrue; ++ } ++ else if (RTEST(rb_eval(self, node->nd_end))) ++ *flip = Qfalse; ++ return Qtrue; ++} ++ ++ ++eval_node(flip3, VALUE) ++{ ++ VALUE *flip = rb_svar(node->nd_cnt); ++ if (!flip) rb_bug("unexpected local variable"); ++ if (!RTEST(*flip)) ++ return *flip = (RTEST(rb_eval(self, node->nd_beg)) ? Qtrue : Qfalse); ++ if (RTEST(rb_eval(self, node->nd_end))) ++ *flip = Qfalse; ++ return Qtrue; ++} ++ ++ ++eval_node(attrasgn, VALUE) ++{ ++ VALUE recv; ++ int argc; VALUE *argv; /* used in SETUP_ARGS */ ++ int scope; ++ TMP_PROTECT; ++ ++ BEGIN_CALLARGS; ++ if (node->nd_recv == (NODE *)1) { ++ recv = self; ++ scope = 1; ++ } ++ else { ++ recv = rb_eval(self, node->nd_recv); ++ scope = 0; ++ } ++ SETUP_ARGS(node->nd_args); ++ END_CALLARGS; ++ ++ ruby_current_node = node; ++ SET_CURRENT_SOURCE(); ++ rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,scope,self); ++ return argv[argc-1]; ++} ++ ++ ++eval_node(call, VALUE) ++{ ++ VALUE recv; ++ int argc; VALUE *argv; /* used in SETUP_ARGS */ ++ TMP_PROTECT; ++ ++ BEGIN_CALLARGS; ++ recv = rb_eval(self, node->nd_recv); ++ SETUP_ARGS(node->nd_args); ++ END_CALLARGS; ++ ++ ruby_current_node = node; ++ SET_CURRENT_SOURCE(); ++ return rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0,self); ++} ++ ++ ++eval_node(fcall, VALUE) ++{ ++ int argc; VALUE *argv; /* used in SETUP_ARGS */ ++ TMP_PROTECT; ++ ++ BEGIN_CALLARGS; ++ SETUP_ARGS(node->nd_args); ++ END_CALLARGS; ++ ++ ruby_current_node = node; ++ SET_CURRENT_SOURCE(); ++ return rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1,self); ++} ++ ++ ++eval_node(super, VALUE) ++{ ++ int argc; VALUE *argv; /* used in SETUP_ARGS */ ++ TMP_PROTECT; ++ ++ if (ruby_frame->last_class == 0) { ++ if (ruby_frame->last_func) { ++ rb_name_error(ruby_frame->last_func, ++ "superclass method `%s' disabled", ++ rb_id2name(ruby_frame->orig_func)); ++ } ++ else { ++ rb_raise(rb_eNoMethodError, "super called outside of method"); ++ } ++ } ++ if (nd_type(node) == NODE_ZSUPER) { ++ argc = ruby_frame->argc; ++ if (argc && DMETHOD_P()) { ++ if (TYPE(RBASIC(ruby_scope)->klass) != T_ARRAY || ++ RARRAY(RBASIC(ruby_scope)->klass)->len != argc) { ++ rb_raise(rb_eRuntimeError, ++ "super: specify arguments explicitly"); ++ } ++ argv = RARRAY(RBASIC(ruby_scope)->klass)->ptr; ++ } ++ else if (!ruby_scope->local_vars) { ++ argc = 0; ++ argv = 0; ++ } ++ else { ++ argv = ruby_scope->local_vars + 2; ++ } ++ } ++ else { ++ BEGIN_CALLARGS; ++ SETUP_ARGS(node->nd_args); ++ END_CALLARGS; ++ ruby_current_node = node; ++ } ++ ++ SET_CURRENT_SOURCE(); ++ return rb_call_super(argc, argv); ++} ++ ++ ++eval_node_volatile(scope, VALUE) ++{ ++ int state; ++ VALUE result; ++ struct FRAME frame; ++ NODE * volatile saved_cref = 0; ++ ++ frame = *ruby_frame; ++ frame.tmp = ruby_frame; ++ ruby_frame = &frame; ++ ++ PUSH_SCOPE(); ++ PUSH_TAG(PROT_NONE); ++ if (node->nd_rval) { ++ saved_cref = ruby_cref; ++ ruby_cref = (NODE*)node->nd_rval; ++ } ++ if (node->nd_tbl) { ++ VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1); ++ *vars++ = (VALUE)node; ++ ruby_scope->local_vars = vars; ++ rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]); ++ ruby_scope->local_tbl = node->nd_tbl; ++ } ++ else { ++ ruby_scope->local_vars = 0; ++ ruby_scope->local_tbl = 0; ++ } ++ if ((state = EXEC_TAG()) == 0) { ++ result = rb_eval(self, node->nd_next); ++ } ++ POP_TAG(); ++ POP_SCOPE(); ++ ruby_frame = frame.tmp; ++ if (saved_cref) ++ ruby_cref = saved_cref; ++ if (state) JUMP_TAG(state); ++ return result; ++} ++ ++eval_node(op_asgn1, VALUE) ++{ ++ int argc; VALUE *argv; /* used in SETUP_ARGS */ ++ VALUE recv, val, tmp; ++ NODE *rval; ++ TMP_PROTECT; ++ ++ recv = rb_eval(self, node->nd_recv); ++ rval = node->nd_args->nd_head; ++ SETUP_ARGS0(node->nd_args->nd_body, 1); ++ val = rb_funcall3(recv, aref, argc, argv); ++ switch (node->nd_mid) { ++ case 0: /* OR */ ++ if (RTEST(val)) return val; ++ val = rb_eval(self, rval); ++ break; ++ case 1: /* AND */ ++ if (!RTEST(val)) return val; ++ val = rb_eval(self, rval); ++ break; ++ default: ++ tmp = rb_eval(self, rval); ++ val = rb_funcall3(val, node->nd_mid, 1, &tmp); ++ } ++ argv[argc] = val; ++ rb_funcall2(recv, aset, argc+1, argv); ++ return val; ++} ++ ++ ++eval_node(op_asgn2, VALUE) ++{ ++ ID id = node->nd_next->nd_vid; ++ VALUE recv, val, tmp; ++ ++ recv = rb_eval(self, node->nd_recv); ++ val = rb_funcall3(recv, id, 0, 0); ++ switch (node->nd_next->nd_mid) { ++ case 0: /* OR */ ++ if (RTEST(val)) return val; ++ val = rb_eval(self, node->nd_value); ++ break; ++ case 1: /* AND */ ++ if (!RTEST(val)) return val; ++ val = rb_eval(self, node->nd_value); ++ break; ++ default: ++ tmp = rb_eval(self, node->nd_value); ++ val = rb_funcall3(val, node->nd_next->nd_mid, 1, &tmp); ++ } ++ ++ rb_funcall2(recv, node->nd_next->nd_aid, 1, &val); ++ return val; ++} ++ ++ ++eval_node(hash, VALUE) ++{ ++ NODE *list; ++ VALUE hash = rb_hash_new(); ++ VALUE key, val; ++ ++ list = node->nd_head; ++ while (list) { ++ key = rb_eval(self, list->nd_head); ++ list = list->nd_next; ++ if (list == 0) ++ rb_bug("odd number list for Hash"); ++ val = rb_eval(self, list->nd_head); ++ list = list->nd_next; ++ rb_hash_aset(hash, key, val); ++ } ++ return hash; ++} ++ ++ ++eval_node(array, VALUE) ++{ ++ VALUE ary; ++ long i; ++ ++ i = node->nd_alen; ++ ary = rb_ary_new2(i); ++ for (i=0;node;node=node->nd_next) { ++ RARRAY(ary)->ptr[i++] = rb_eval(self, node->nd_head); ++ RARRAY(ary)->len = i; ++ } ++ return ary; ++} ++ ++ ++eval_node(slit, VALUE) ++{ ++ VALUE str, str2; ++ NODE *list = node->nd_next; ++ ++ str = rb_str_new3(node->nd_lit); ++ while (list) { ++ if (list->nd_head) { ++ switch (nd_type(list->nd_head)) { ++ case NODE_STR: ++ str2 = list->nd_head->nd_lit; ++ break; ++ default: ++ str2 = rb_eval(self, list->nd_head); ++ break; ++ } ++ rb_str_append(str, str2); ++ OBJ_INFECT(str, str2); ++ } ++ list = list->nd_next; ++ } ++ switch (nd_type(node)) { ++ case NODE_DREGX: ++ str2 = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, ++ node->nd_cflag); ++ RB_GC_GUARD(str); /* prevent tail call optimization here */ ++ return str2; ++ case NODE_DREGX_ONCE: /* regexp expand once */ ++ str2 = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, ++ node->nd_cflag); ++ nd_set_type(node, NODE_LIT); ++ RB_GC_GUARD(str); /* ensure str is not GC'd in rb_reg_new */ ++ return node->nd_lit = str2; ++ case NODE_LIT: ++ /* other thread may replace NODE_DREGX_ONCE to NODE_LIT */ ++ return Qundef; ++ case NODE_DXSTR: ++ return rb_funcall(self, '`', 1, str); ++ case NODE_DSYM: ++ return rb_str_intern(str); ++ } ++ return str; ++} ++ ++ ++eval_node(defn, void) ++{ ++ NODE *body, *defn; ++ VALUE origin = 0; ++ int noex; ++ ++ if (NIL_P(ruby_class)) { ++ rb_raise(rb_eTypeError, "no class/module to add method"); ++ } ++ if (ruby_class == rb_cObject && node->nd_mid == init) { ++ rb_warn("redefining Object#initialize may cause infinite loop"); ++ } ++ if (node->nd_mid == __id__ || node->nd_mid == __send__) { ++ rb_warn("redefining `%s' may cause serious problem", ++ rb_id2name(node->nd_mid)); ++ } ++ rb_frozen_class_p(ruby_class); ++ body = search_method(ruby_class, node->nd_mid, &origin); ++ if (body){ ++ if (RTEST(ruby_verbose) && ruby_class == origin && body->nd_cnt == 0 && body->nd_body) { ++ rb_warning("method redefined; discarding old %s", rb_id2name(node->nd_mid)); ++ } ++ } ++ ++ if (SCOPE_TEST(SCOPE_PRIVATE) || node->nd_mid == init) { ++ noex = NOEX_PRIVATE; ++ } ++ else if (SCOPE_TEST(SCOPE_PROTECTED)) { ++ noex = NOEX_PROTECTED; ++ } ++ else { ++ noex = NOEX_PUBLIC; ++ } ++ if (body && origin == ruby_class && body->nd_body == 0) { ++ noex |= NOEX_NOSUPER; ++ } ++ ++ defn = rb_copy_node_scope(node->nd_defn, ruby_cref); ++ rb_add_method(ruby_class, node->nd_mid, defn, noex); ++ if (scope_vmode == SCOPE_MODFUNC) { ++ rb_add_method(rb_singleton_class(ruby_class), ++ node->nd_mid, defn, NOEX_PUBLIC); ++ } ++} ++ ++ ++eval_node(defs, void) ++{ ++ VALUE recv = rb_eval(self, node->nd_recv); ++ VALUE klass; ++ NODE *body = 0, *defn; ++ st_data_t data; ++ ++ if (ruby_safe_level >= 4 && !OBJ_TAINTED(recv)) { ++ rb_raise(rb_eSecurityError, "Insecure: can't define singleton method"); ++ } ++ if (FIXNUM_P(recv) || SYMBOL_P(recv)) { ++ rb_raise(rb_eTypeError, ++ "can't define singleton method \"%s\" for %s", ++ rb_id2name(node->nd_mid), ++ rb_obj_classname(recv)); ++ } ++ ++ if (OBJ_FROZEN(recv)) rb_error_frozen("object"); ++ klass = rb_singleton_class(recv); ++ if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, &data)) { ++ body = (NODE *)data; ++ if (ruby_safe_level >= 4) { ++ rb_raise(rb_eSecurityError, "redefining method prohibited"); ++ } ++ if (RTEST(ruby_verbose)) { ++ rb_warning("redefine %s", rb_id2name(node->nd_mid)); ++ } ++ } ++ defn = rb_copy_node_scope(node->nd_defn, ruby_cref); ++ rb_add_method(klass, node->nd_mid, defn, ++ NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0)); ++} ++ ++ ++eval_node(class, VALUE) ++{ ++ VALUE super, klass, tmp, cbase; ++ ID cname; ++ int gen = Qfalse; ++ ++ cbase = class_prefix(self, node->nd_cpath); ++ cname = node->nd_cpath->nd_mid; ++ ++ if (NIL_P(ruby_cbase)) { ++ rb_raise(rb_eTypeError, "no outer class/module"); ++ } ++ if (node->nd_super) { ++ super = rb_eval(self, node->nd_super); ++ rb_check_inheritable(super); ++ } ++ else { ++ super = 0; ++ } ++ ++ if (rb_const_defined_at(cbase, cname)) { ++ klass = rb_const_get_at(cbase, cname); ++ if (TYPE(klass) != T_CLASS) { ++ rb_raise(rb_eTypeError, "%s is not a class", ++ rb_id2name(cname)); ++ } ++ if (super) { ++ tmp = rb_class_real(RCLASS(klass)->super); ++ if (tmp != super) { ++ rb_raise(rb_eTypeError, "superclass mismatch for class %s", ++ rb_id2name(cname)); ++ } ++ super = 0; ++ } ++ if (ruby_safe_level >= 4) { ++ rb_raise(rb_eSecurityError, "extending class prohibited"); ++ } ++ } ++ else { ++ if (!super) super = rb_cObject; ++ klass = rb_define_class_id(cname, super); ++ rb_set_class_path(klass, cbase, rb_id2name(cname)); ++ rb_const_set(cbase, cname, klass); ++ gen = Qtrue; ++ } ++ if (ruby_wrapper) { ++ rb_extend_object(klass, ruby_wrapper); ++ rb_include_module(klass, ruby_wrapper); ++ } ++ if (super && gen) { ++ rb_class_inherited(super, klass); ++ } ++ return module_setup(klass, node); ++} ++ ++ ++eval_node(module, VALUE) ++{ ++ VALUE module, cbase; ++ ID cname; ++ ++ if (NIL_P(ruby_cbase)) { ++ rb_raise(rb_eTypeError, "no outer class/module"); ++ } ++ cbase = class_prefix(self, node->nd_cpath); ++ cname = node->nd_cpath->nd_mid; ++ if (rb_const_defined_at(cbase, cname)) { ++ module = rb_const_get_at(cbase, cname); ++ if (TYPE(module) != T_MODULE) { ++ rb_raise(rb_eTypeError, "%s is not a module", ++ rb_id2name(cname)); ++ } ++ if (ruby_safe_level >= 4) { ++ rb_raise(rb_eSecurityError, "extending module prohibited"); ++ } ++ } ++ else { ++ module = rb_define_module_id(cname); ++ rb_set_class_path(module, cbase, rb_id2name(cname)); ++ rb_const_set(cbase, cname, module); ++ } ++ if (ruby_wrapper) { ++ rb_extend_object(module, ruby_wrapper); ++ rb_include_module(module, ruby_wrapper); ++ } ++ ++ return module_setup(module, node); ++} ++ ++ ++eval_node(sclass, VALUE) ++{ ++ VALUE klass, result; ++ ++ result = rb_eval(self, node->nd_recv); ++ if (FIXNUM_P(result) || SYMBOL_P(result)) { ++ rb_raise(rb_eTypeError, "no virtual class for %s", ++ rb_obj_classname(result)); ++ } ++ if (ruby_safe_level >= 4 && !OBJ_TAINTED(result)) ++ rb_raise(rb_eSecurityError, "Insecure: can't extend object"); ++ klass = rb_singleton_class(result); ++ ++ if (ruby_wrapper) { ++ rb_extend_object(klass, ruby_wrapper); ++ rb_include_module(klass, ruby_wrapper); ++ } ++ ++ return module_setup(klass, node); ++} ++ ++ ++eval_node(defined, VALUE) ++{ ++ char buf[20]; ++ const char *desc = is_defined(self, node->nd_head, buf); ++ return desc ? rb_str_new2(desc) : Qnil; ++} ++ ++ ++static void ++eval_cvar_set(node, result, warn) ++ NODE *node; ++ VALUE result; ++ int warn; ++{ ++ rb_cvar_set(cvar_cbase(), node->nd_vid, result, warn); ++} ++ ++ ++static void ++eval_cdecl(self, node, result) ++ VALUE self, result; ++ NODE *node; ++{ ++ if (node->nd_vid == 0) ++ rb_const_set(class_prefix(self, node->nd_else), ++ node->nd_else->nd_mid, result); ++ else ++ rb_const_set(ruby_cbase, node->nd_vid, result); ++} + +- again: +- if (!node) RETURN(Qnil); + ++static VALUE ++rb_eval(self, node) ++ VALUE self; ++ NODE * node; ++{ ++ VALUE result; ++ ++again: ++ CHECK_INTS; ++ result = Qnil; ++ if (node) { + ruby_current_node = node; + switch (nd_type(node)) { + case NODE_BLOCK: +- if (contnode) { +- result = rb_eval(self, node); +- break; ++ while (node->nd_next) { ++ rb_eval(self, node->nd_head); ++ node = node->nd_next; + } +- contnode = node->nd_next; + node = node->nd_head; + goto again; + + case NODE_POSTEXE: + rb_f_END(); + nd_set_type(node, NODE_NIL); /* exec just once */ +- result = Qnil; + break; + + /* begin .. end without clauses */ +@@ -2984,223 +3867,57 @@ rb_eval(self, n) + + /* nodes for speed-up(literal match) */ + case NODE_MATCH2: +- { +- VALUE l = rb_eval(self,node->nd_recv); +- VALUE r = rb_eval(self,node->nd_value); +- result = rb_reg_match(l, r); +- } ++ result = eval_match2(self, node); + break; + + /* nodes for speed-up(literal match) */ + case NODE_MATCH3: +- { +- VALUE r = rb_eval(self,node->nd_recv); +- VALUE l = rb_eval(self,node->nd_value); +- if (TYPE(l) == T_STRING) { +- result = rb_reg_match(r, l); +- } +- else { +- result = rb_funcall(l, match, 1, r); +- } +- } ++ result = eval_match3(self,node); + break; + + /* node for speed-up(top-level loop for -n/-p) */ + case NODE_OPT_N: +- PUSH_TAG(PROT_LOOP); +- switch (state = EXEC_TAG()) { +- case 0: +- opt_n_next: +- while (!NIL_P(rb_gets())) { +- opt_n_redo: +- rb_eval(self, node->nd_body); +- } +- break; +- +- case TAG_REDO: +- state = 0; +- goto opt_n_redo; +- case TAG_NEXT: +- state = 0; +- goto opt_n_next; +- case TAG_BREAK: +- state = 0; +- default: +- break; +- } +- POP_TAG(); +- if (state) JUMP_TAG(state); +- RETURN(Qnil); ++ eval_opt_n(self, node); ++ break; + + case NODE_SELF: +- RETURN(self); ++ result = self; ++ break; + + case NODE_NIL: +- RETURN(Qnil); ++ break; + + case NODE_TRUE: +- RETURN(Qtrue); ++ result = Qtrue; ++ break; + + case NODE_FALSE: +- RETURN(Qfalse); ++ result = Qfalse; ++ break; + + case NODE_IF: + EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self, + ruby_frame->last_func, + ruby_frame->last_class); +- if (RTEST(rb_eval(self, node->nd_cond))) { +- node = node->nd_body; +- } +- else { +- node = node->nd_else; +- } ++ node = RTEST(rb_eval(self, node->nd_cond)) ? ++ node->nd_body : node->nd_else; + goto again; + + case NODE_WHEN: +- while (node) { +- NODE *tag; +- +- if (nd_type(node) != NODE_WHEN) goto again; +- tag = node->nd_head; +- while (tag) { +- EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self, +- ruby_frame->last_func, +- ruby_frame->last_class); +- if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) { +- VALUE v = rb_eval(self, tag->nd_head->nd_head); +- long i; +- +- if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v); +- for (i=0; ilen; i++) { +- if (RTEST(RARRAY(v)->ptr[i])) { +- node = node->nd_body; +- goto again; +- } +- } +- tag = tag->nd_next; +- continue; +- } +- if (RTEST(rb_eval(self, tag->nd_head))) { +- node = node->nd_body; +- goto again; +- } +- tag = tag->nd_next; +- } +- node = node->nd_next; +- } +- RETURN(Qnil); ++ if (node = eval_when(self, node)) goto again; ++ break; + + case NODE_CASE: +- { +- VALUE val; +- +- val = rb_eval(self, node->nd_head); +- node = node->nd_body; +- while (node) { +- NODE *tag; +- +- if (nd_type(node) != NODE_WHEN) { +- goto again; +- } +- tag = node->nd_head; +- while (tag) { +- EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self, +- ruby_frame->last_func, +- ruby_frame->last_class); +- if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) { +- VALUE v = rb_eval(self, tag->nd_head->nd_head); +- long i; +- +- if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v); +- for (i=0; ilen; i++) { +- if (RTEST(rb_funcall2(RARRAY(v)->ptr[i], eqq, 1, &val))){ +- node = node->nd_body; +- goto again; +- } +- } +- tag = tag->nd_next; +- continue; +- } +- if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head), eqq, 1, &val))) { +- node = node->nd_body; +- goto again; +- } +- tag = tag->nd_next; +- } +- node = node->nd_next; +- } +- } +- RETURN(Qnil); ++ if (node = eval_case(self, node)) goto again; ++ break; + + case NODE_WHILE: +- PUSH_TAG(PROT_LOOP); +- result = Qnil; +- switch (state = EXEC_TAG()) { +- case 0: +- if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond))) +- goto while_out; +- do { +- while_redo: +- rb_eval(self, node->nd_body); +- while_next: +- ; +- } while (RTEST(rb_eval(self, node->nd_cond))); +- break; +- +- case TAG_REDO: +- state = 0; +- goto while_redo; +- case TAG_NEXT: +- state = 0; +- goto while_next; +- case TAG_BREAK: +- if (TAG_DST()) { +- state = 0; +- result = prot_tag->retval; +- } +- /* fall through */ +- default: +- break; +- } +- while_out: +- POP_TAG(); +- if (state) JUMP_TAG(state); +- RETURN(result); ++ result = eval_while(self,node); ++ break; + + case NODE_UNTIL: +- PUSH_TAG(PROT_LOOP); +- result = Qnil; +- switch (state = EXEC_TAG()) { +- case 0: +- if (node->nd_state && RTEST(rb_eval(self, node->nd_cond))) +- goto until_out; +- do { +- until_redo: +- rb_eval(self, node->nd_body); +- until_next: +- ; +- } while (!RTEST(rb_eval(self, node->nd_cond))); +- break; +- +- case TAG_REDO: +- state = 0; +- goto until_redo; +- case TAG_NEXT: +- state = 0; +- goto until_next; +- case TAG_BREAK: +- if (TAG_DST()) { +- state = 0; +- result = prot_tag->retval; +- } +- /* fall through */ +- default: +- break; +- } +- until_out: +- POP_TAG(); +- if (state) JUMP_TAG(state); +- RETURN(result); ++ result = eval_until(self,node); ++ break; + + case NODE_BLOCK_PASS: + result = block_pass(self, node); +@@ -3208,47 +3925,7 @@ rb_eval(self, n) + + case NODE_ITER: + case NODE_FOR: +- { +- PUSH_TAG(PROT_LOOP); +- PUSH_BLOCK(node->nd_var, node->nd_body); +- +- state = EXEC_TAG(); +- if (state == 0) { +- iter_retry: +- PUSH_ITER(ITER_PRE); +- if (nd_type(node) == NODE_ITER) { +- result = rb_eval(self, node->nd_iter); +- } +- else { +- VALUE recv; +- +- _block.flags &= ~BLOCK_D_SCOPE; +- BEGIN_CALLARGS; +- recv = rb_eval(self, node->nd_iter); +- END_CALLARGS; +- ruby_current_node = node; +- SET_CURRENT_SOURCE(); +- result = rb_call(CLASS_OF(recv),recv,each,0,0,0,self); +- } +- POP_ITER(); +- } +- else if (state == TAG_BREAK && TAG_DST()) { +- result = prot_tag->retval; +- state = 0; +- } +- else if (state == TAG_RETRY) { +- state = 0; +- goto iter_retry; +- } +- POP_BLOCK(); +- POP_TAG(); +- switch (state) { +- case 0: +- break; +- default: +- JUMP_TAG(state); +- } +- } ++ result = eval_iter(self, node); + break; + + case NODE_BREAK: +@@ -3256,17 +3933,14 @@ rb_eval(self, n) + break; + + case NODE_NEXT: +- CHECK_INTS; + next_jump(rb_eval(self, node->nd_stts)); + break; + + case NODE_REDO: +- CHECK_INTS; + JUMP_TAG(TAG_REDO); + break; + + case NODE_RETRY: +- CHECK_INTS; + JUMP_TAG(TAG_RETRY); + break; + +@@ -3296,73 +3970,15 @@ rb_eval(self, n) + break; + + case NODE_RESCUE: +- { +- volatile VALUE e_info = ruby_errinfo; +- volatile int rescuing = 0; +- +- PUSH_TAG(PROT_NONE); +- if ((state = EXEC_TAG()) == 0) { +- retry_entry: +- result = rb_eval(self, node->nd_head); +- } +- else if (rescuing) { +- if (rescuing < 0) { +- /* in rescue argument, just reraise */ +- } +- else if (state == TAG_RETRY) { +- rescuing = state = 0; +- ruby_errinfo = e_info; +- goto retry_entry; +- } +- else if (state != TAG_RAISE) { +- result = prot_tag->retval; +- } +- } +- else if (state == TAG_RAISE) { +- NODE *resq = node->nd_resq; +- +- rescuing = -1; +- while (resq) { +- ruby_current_node = resq; +- if (handle_rescue(self, resq)) { +- state = 0; +- rescuing = 1; +- result = rb_eval(self, resq->nd_body); +- break; +- } +- resq = resq->nd_head; /* next rescue */ +- } +- } +- else { +- result = prot_tag->retval; +- } +- POP_TAG(); +- if (state != TAG_RAISE) ruby_errinfo = e_info; +- if (state) { +- JUMP_TAG(state); +- } +- /* no exception raised */ +- if (!rescuing && (node = node->nd_else)) { /* else clause given */ +- goto again; +- } +- } ++ result = eval_rescue(self,node); ++ if (result == Qundef) { /* handle else clause w/o recursion */ ++ node = node->nd_else; ++ goto again; ++ } + break; + + case NODE_ENSURE: +- PUSH_TAG(PROT_NONE); +- if ((state = EXEC_TAG()) == 0) { +- result = rb_eval(self, node->nd_head); +- } +- POP_TAG(); +- if (node->nd_ensr && !thread_no_ensure()) { +- VALUE retval = prot_tag->retval; /* save retval */ +- VALUE errinfo = ruby_errinfo; +- +- rb_eval(self, node->nd_ensr); +- return_value(retval); +- ruby_errinfo = errinfo; +- } +- if (state) JUMP_TAG(state); ++ result = eval_ensure(self,node); + break; + + case NODE_AND: +@@ -3378,56 +3994,20 @@ rb_eval(self, n) + goto again; + + case NODE_NOT: +- if (RTEST(rb_eval(self, node->nd_body))) result = Qfalse; +- else result = Qtrue; ++ result = RTEST(rb_eval(self, node->nd_body)) ? Qfalse : Qtrue; + break; + + case NODE_DOT2: + case NODE_DOT3: +- { +- VALUE beg = rb_eval(self, node->nd_beg); +- VALUE end = rb_eval(self, node->nd_end); +- result = rb_range_new(beg, end, nd_type(node) == NODE_DOT3); +- } +- break; ++ result = eval_dot(self,node); ++ break; + + case NODE_FLIP2: /* like AWK */ +- { +- VALUE *flip = rb_svar(node->nd_cnt); +- if (!flip) rb_bug("unexpected local variable"); +- if (!RTEST(*flip)) { +- if (RTEST(rb_eval(self, node->nd_beg))) { +- *flip = RTEST(rb_eval(self, node->nd_end))?Qfalse:Qtrue; +- result = Qtrue; +- } +- else { +- result = Qfalse; +- } +- } +- else { +- if (RTEST(rb_eval(self, node->nd_end))) { +- *flip = Qfalse; +- } +- result = Qtrue; +- } +- } ++ result = eval_flip2(self,node); + break; + + case NODE_FLIP3: /* like SED */ +- { +- VALUE *flip = rb_svar(node->nd_cnt); +- if (!flip) rb_bug("unexpected local variable"); +- if (!RTEST(*flip)) { +- result = RTEST(rb_eval(self, node->nd_beg)) ? Qtrue : Qfalse; +- *flip = result; +- } +- else { +- if (RTEST(rb_eval(self, node->nd_end))) { +- *flip = Qfalse; +- } +- result = Qtrue; +- } +- } ++ result = eval_flip3(self,node); + break; + + case NODE_RETURN: +@@ -3435,75 +4015,25 @@ rb_eval(self, n) + break; + + case NODE_ARGSCAT: +- { +- VALUE args = rb_eval(self, node->nd_head); +- result = rb_ary_concat(args, splat_value(rb_eval(self, node->nd_body))); +- } ++ result = rb_eval(self, node->nd_head); ++ result = rb_ary_concat(result, splat_value(rb_eval(self, node->nd_body))); + break; + + case NODE_ARGSPUSH: +- { +- VALUE args = rb_ary_dup(rb_eval(self, node->nd_head)); +- result = rb_ary_push(args, rb_eval(self, node->nd_body)); +- } ++ result = rb_ary_dup(rb_eval(self, node->nd_head)); ++ result = rb_ary_push(result, rb_eval(self, node->nd_body)); + break; + + case NODE_ATTRASGN: +- { +- VALUE recv; +- int argc; VALUE *argv; /* used in SETUP_ARGS */ +- int scope; +- TMP_PROTECT; +- +- BEGIN_CALLARGS; +- if (node->nd_recv == (NODE *)1) { +- recv = self; +- scope = 1; +- } +- else { +- recv = rb_eval(self, node->nd_recv); +- scope = 0; +- } +- SETUP_ARGS(node->nd_args); +- END_CALLARGS; +- +- ruby_current_node = node; +- SET_CURRENT_SOURCE(); +- rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,scope,self); +- result = argv[argc-1]; +- } +- break; ++ result = eval_attrasgn(self,node); ++ break; + + case NODE_CALL: +- { +- VALUE recv; +- int argc; VALUE *argv; /* used in SETUP_ARGS */ +- TMP_PROTECT; +- +- BEGIN_CALLARGS; +- recv = rb_eval(self, node->nd_recv); +- SETUP_ARGS(node->nd_args); +- END_CALLARGS; +- +- ruby_current_node = node; +- SET_CURRENT_SOURCE(); +- result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0,self); +- } ++ result = eval_call(self,node); + break; + + case NODE_FCALL: +- { +- int argc; VALUE *argv; /* used in SETUP_ARGS */ +- TMP_PROTECT; +- +- BEGIN_CALLARGS; +- SETUP_ARGS(node->nd_args); +- END_CALLARGS; +- +- ruby_current_node = node; +- SET_CURRENT_SOURCE(); +- result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1,self); +- } ++ result = eval_fcall(self,node); + break; + + case NODE_VCALL: +@@ -3513,142 +4043,19 @@ rb_eval(self, n) + + case NODE_SUPER: + case NODE_ZSUPER: +- { +- int argc; VALUE *argv; /* used in SETUP_ARGS */ +- TMP_PROTECT; +- +- if (ruby_frame->last_class == 0) { +- if (ruby_frame->last_func) { +- rb_name_error(ruby_frame->last_func, +- "superclass method `%s' disabled", +- rb_id2name(ruby_frame->orig_func)); +- } +- else { +- rb_raise(rb_eNoMethodError, "super called outside of method"); +- } +- } +- if (nd_type(node) == NODE_ZSUPER) { +- argc = ruby_frame->argc; +- if (argc && DMETHOD_P()) { +- if (TYPE(RBASIC(ruby_scope)->klass) != T_ARRAY || +- RARRAY(RBASIC(ruby_scope)->klass)->len != argc) { +- rb_raise(rb_eRuntimeError, +- "super: specify arguments explicitly"); +- } +- argv = RARRAY(RBASIC(ruby_scope)->klass)->ptr; +- } +- else if (!ruby_scope->local_vars) { +- argc = 0; +- argv = 0; +- } +- else { +- argv = ruby_scope->local_vars + 2; +- } +- } +- else { +- BEGIN_CALLARGS; +- SETUP_ARGS(node->nd_args); +- END_CALLARGS; +- ruby_current_node = node; +- } +- +- SET_CURRENT_SOURCE(); +- result = rb_call_super(argc, argv); +- } ++ result = eval_super(self,node); + break; + + case NODE_SCOPE: +- { +- struct FRAME frame; +- NODE *saved_cref = 0; +- +- frame = *ruby_frame; +- frame.tmp = ruby_frame; +- ruby_frame = &frame; +- +- PUSH_SCOPE(); +- PUSH_TAG(PROT_NONE); +- if (node->nd_rval) { +- saved_cref = ruby_cref; +- ruby_cref = (NODE*)node->nd_rval; +- } +- if (node->nd_tbl) { +- VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1); +- *vars++ = (VALUE)node; +- ruby_scope->local_vars = vars; +- rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]); +- ruby_scope->local_tbl = node->nd_tbl; +- } +- else { +- ruby_scope->local_vars = 0; +- ruby_scope->local_tbl = 0; +- } +- if ((state = EXEC_TAG()) == 0) { +- result = rb_eval(self, node->nd_next); +- } +- POP_TAG(); +- POP_SCOPE(); +- ruby_frame = frame.tmp; +- if (saved_cref) +- ruby_cref = saved_cref; +- if (state) JUMP_TAG(state); +- } +- break; ++ result = eval_scope(self,node); ++ break; + + case NODE_OP_ASGN1: +- { +- int argc; VALUE *argv; /* used in SETUP_ARGS */ +- VALUE recv, val, tmp; +- NODE *rval; +- TMP_PROTECT; +- +- recv = rb_eval(self, node->nd_recv); +- rval = node->nd_args->nd_head; +- SETUP_ARGS0(node->nd_args->nd_body, 1); +- val = rb_funcall3(recv, aref, argc, argv); +- switch (node->nd_mid) { +- case 0: /* OR */ +- if (RTEST(val)) RETURN(val); +- val = rb_eval(self, rval); +- break; +- case 1: /* AND */ +- if (!RTEST(val)) RETURN(val); +- val = rb_eval(self, rval); +- break; +- default: +- tmp = rb_eval(self, rval); +- val = rb_funcall3(val, node->nd_mid, 1, &tmp); +- } +- argv[argc] = val; +- rb_funcall2(recv, aset, argc+1, argv); +- result = val; +- } ++ result = eval_op_asgn1(self,node); + break; + + case NODE_OP_ASGN2: +- { +- ID id = node->nd_next->nd_vid; +- VALUE recv, val, tmp; +- +- recv = rb_eval(self, node->nd_recv); +- val = rb_funcall3(recv, id, 0, 0); +- switch (node->nd_next->nd_mid) { +- case 0: /* OR */ +- if (RTEST(val)) RETURN(val); +- val = rb_eval(self, node->nd_value); +- break; +- case 1: /* AND */ +- if (!RTEST(val)) RETURN(val); +- val = rb_eval(self, node->nd_value); +- break; +- default: +- tmp = rb_eval(self, node->nd_value); +- val = rb_funcall3(val, node->nd_next->nd_mid, 1, &tmp); +- } +- +- rb_funcall2(recv, node->nd_next->nd_aid, 1, &val); +- result = val; +- } ++ result = eval_op_asgn2(self,node); + break; + + case NODE_OP_ASGN_AND: +@@ -3697,26 +4104,21 @@ rb_eval(self, n) + break; + + case NODE_CDECL: +- result = rb_eval(self, node->nd_value); +- if (node->nd_vid == 0) { +- rb_const_set(class_prefix(self, node->nd_else), node->nd_else->nd_mid, result); +- } +- else { +- rb_const_set(ruby_cbase, node->nd_vid, result); +- } ++ result = rb_eval(self, node->nd_value); ++ eval_cdecl(self, node, result); + break; + + case NODE_CVDECL: + if (NIL_P(ruby_cbase)) { + rb_raise(rb_eTypeError, "no class/module to define class variable"); + } +- result = rb_eval(self, node->nd_value); +- rb_cvar_set(cvar_cbase(), node->nd_vid, result, Qtrue); ++ result = rb_eval(self, node->nd_value); ++ eval_cvar_set(node, result, Qtrue); + break; + + case NODE_CVASGN: +- result = rb_eval(self, node->nd_value); +- rb_cvar_set(cvar_cbase(), node->nd_vid, result, Qfalse); ++ result = rb_eval(self, node->nd_value); ++ eval_cvar_set(node, result, Qfalse); + break; + + case NODE_LVAR: +@@ -3759,26 +4161,21 @@ rb_eval(self, n) + break; + + case NODE_COLON2: +- { +- VALUE klass; +- +- klass = rb_eval(self, node->nd_head); +- if (rb_is_const_id(node->nd_mid)) { +- switch (TYPE(klass)) { +- case T_CLASS: +- case T_MODULE: +- result = rb_const_get_from(klass, node->nd_mid); +- break; +- default: +- rb_raise(rb_eTypeError, "%s is not a class/module", +- RSTRING(rb_obj_as_string(klass))->ptr); +- break; +- } +- } +- else { +- result = rb_funcall(klass, node->nd_mid, 0, 0); ++ result = rb_eval(self, node->nd_head); ++ if (rb_is_const_id(node->nd_mid)) { ++ switch (TYPE(result)) { ++ case T_CLASS: ++ case T_MODULE: ++ result = rb_const_get_from(result, node->nd_mid); ++ break; ++ default: ++ rb_raise(rb_eTypeError, "%s is not a class/module", ++ RSTRING(rb_obj_as_string(result))->ptr); ++ break; + } + } ++ else ++ result = rb_funcall(result, node->nd_mid, 0, 0); + break; + + case NODE_COLON3: +@@ -3809,23 +4206,7 @@ rb_eval(self, n) + break; + + case NODE_HASH: +- { +- NODE *list; +- VALUE hash = rb_hash_new(); +- VALUE key, val; +- +- list = node->nd_head; +- while (list) { +- key = rb_eval(self, list->nd_head); +- list = list->nd_next; +- if (list == 0) +- rb_bug("odd number list for Hash"); +- val = rb_eval(self, list->nd_head); +- list = list->nd_next; +- rb_hash_aset(hash, key, val); +- } +- result = hash; +- } ++ result = eval_hash(self,node); + break; + + case NODE_ZARRAY: /* zero length list */ +@@ -3833,19 +4214,7 @@ rb_eval(self, n) + break; + + case NODE_ARRAY: +- { +- VALUE ary; +- long i; +- +- i = node->nd_alen; +- ary = rb_ary_new2(i); +- for (i=0;node;node=node->nd_next) { +- RARRAY(ary)->ptr[i++] = rb_eval(self, node->nd_head); +- RARRAY(ary)->len = i; +- } +- +- result = ary; +- } ++ result = eval_array(self,node); + break; + + case NODE_STR: +@@ -3861,51 +4230,8 @@ rb_eval(self, n) + case NODE_DREGX: + case NODE_DREGX_ONCE: + case NODE_DSYM: +- { +- VALUE str, str2; +- NODE *list = node->nd_next; +- +- str = rb_str_new3(node->nd_lit); +- while (list) { +- if (list->nd_head) { +- switch (nd_type(list->nd_head)) { +- case NODE_STR: +- str2 = list->nd_head->nd_lit; +- break; +- default: +- str2 = rb_eval(self, list->nd_head); +- break; +- } +- rb_str_append(str, str2); +- OBJ_INFECT(str, str2); +- } +- list = list->nd_next; +- } +- switch (nd_type(node)) { +- case NODE_DREGX: +- result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, +- node->nd_cflag); +- break; +- case NODE_DREGX_ONCE: /* regexp expand once */ +- result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, +- node->nd_cflag); +- nd_set_type(node, NODE_LIT); +- node->nd_lit = result; +- break; +- case NODE_LIT: +- /* other thread may replace NODE_DREGX_ONCE to NODE_LIT */ +- goto again; +- case NODE_DXSTR: +- result = rb_funcall(self, '`', 1, str); +- break; +- case NODE_DSYM: +- result = rb_str_intern(str); +- break; +- default: +- result = str; +- break; +- } +- } ++ result = eval_slit(self, node); ++ if (result == Qundef) goto again; + break; + + case NODE_XSTR: +@@ -3917,84 +4243,13 @@ rb_eval(self, n) + break; + + case NODE_DEFN: +- if (node->nd_defn) { +- NODE *body, *defn; +- VALUE origin; +- int noex; +- +- if (NIL_P(ruby_class)) { +- rb_raise(rb_eTypeError, "no class/module to add method"); +- } +- if (ruby_class == rb_cObject && node->nd_mid == init) { +- rb_warn("redefining Object#initialize may cause infinite loop"); +- } +- if (node->nd_mid == __id__ || node->nd_mid == __send__) { +- rb_warn("redefining `%s' may cause serious problem", +- rb_id2name(node->nd_mid)); +- } +- rb_frozen_class_p(ruby_class); +- body = search_method(ruby_class, node->nd_mid, &origin); +- if (body){ +- if (RTEST(ruby_verbose) && ruby_class == origin && body->nd_cnt == 0 && body->nd_body) { +- rb_warning("method redefined; discarding old %s", rb_id2name(node->nd_mid)); +- } +- } +- +- if (SCOPE_TEST(SCOPE_PRIVATE) || node->nd_mid == init) { +- noex = NOEX_PRIVATE; +- } +- else if (SCOPE_TEST(SCOPE_PROTECTED)) { +- noex = NOEX_PROTECTED; +- } +- else { +- noex = NOEX_PUBLIC; +- } +- if (body && origin == ruby_class && body->nd_body == 0) { +- noex |= NOEX_NOSUPER; +- } +- +- defn = rb_copy_node_scope(node->nd_defn, ruby_cref); +- rb_add_method(ruby_class, node->nd_mid, defn, noex); +- if (scope_vmode == SCOPE_MODFUNC) { +- rb_add_method(rb_singleton_class(ruby_class), +- node->nd_mid, defn, NOEX_PUBLIC); +- } +- result = Qnil; +- } ++ if (node->nd_defn) ++ eval_defn(self,node); + break; + + case NODE_DEFS: +- if (node->nd_defn) { +- VALUE recv = rb_eval(self, node->nd_recv); +- VALUE klass; +- NODE *body = 0, *defn; +- +- if (ruby_safe_level >= 4 && !OBJ_TAINTED(recv)) { +- rb_raise(rb_eSecurityError, "Insecure: can't define singleton method"); +- } +- if (FIXNUM_P(recv) || SYMBOL_P(recv)) { +- rb_raise(rb_eTypeError, +- "can't define singleton method \"%s\" for %s", +- rb_id2name(node->nd_mid), +- rb_obj_classname(recv)); +- } +- +- if (OBJ_FROZEN(recv)) rb_error_frozen("object"); +- klass = rb_singleton_class(recv); +- if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, &data)) { +- body = (NODE *)data; +- if (ruby_safe_level >= 4) { +- rb_raise(rb_eSecurityError, "redefining method prohibited"); +- } +- if (RTEST(ruby_verbose)) { +- rb_warning("redefine %s", rb_id2name(node->nd_mid)); +- } +- } +- defn = rb_copy_node_scope(node->nd_defn, ruby_cref); +- rb_add_method(klass, node->nd_mid, defn, +- NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0)); +- result = Qnil; +- } ++ if (node->nd_defn) ++ eval_defs(self,node); + break; + + case NODE_UNDEF: +@@ -4002,7 +4257,6 @@ rb_eval(self, n) + rb_raise(rb_eTypeError, "no class to undef method"); + } + rb_undef(ruby_class, rb_to_id(rb_eval(self, node->u2.node))); +- result = Qnil; + break; + + case NODE_ALIAS: +@@ -4011,134 +4265,26 @@ rb_eval(self, n) + } + rb_alias(ruby_class, rb_to_id(rb_eval(self, node->u1.node)), + rb_to_id(rb_eval(self, node->u2.node))); +- result = Qnil; + break; + + case NODE_VALIAS: + rb_alias_variable(node->u1.id, node->u2.id); +- result = Qnil; + break; + + case NODE_CLASS: +- { +- VALUE super, klass, tmp, cbase; +- ID cname; +- int gen = Qfalse; +- +- cbase = class_prefix(self, node->nd_cpath); +- cname = node->nd_cpath->nd_mid; +- +- if (NIL_P(ruby_cbase)) { +- rb_raise(rb_eTypeError, "no outer class/module"); +- } +- if (node->nd_super) { +- super = rb_eval(self, node->nd_super); +- rb_check_inheritable(super); +- } +- else { +- super = 0; +- } +- +- if (rb_const_defined_at(cbase, cname)) { +- klass = rb_const_get_at(cbase, cname); +- if (TYPE(klass) != T_CLASS) { +- rb_raise(rb_eTypeError, "%s is not a class", +- rb_id2name(cname)); +- } +- if (super) { +- tmp = rb_class_real(RCLASS(klass)->super); +- if (tmp != super) { +- rb_raise(rb_eTypeError, "superclass mismatch for class %s", +- rb_id2name(cname)); +- } +- super = 0; +- } +- if (ruby_safe_level >= 4) { +- rb_raise(rb_eSecurityError, "extending class prohibited"); +- } +- } +- else { +- if (!super) super = rb_cObject; +- klass = rb_define_class_id(cname, super); +- rb_set_class_path(klass, cbase, rb_id2name(cname)); +- rb_const_set(cbase, cname, klass); +- gen = Qtrue; +- } +- if (ruby_wrapper) { +- rb_extend_object(klass, ruby_wrapper); +- rb_include_module(klass, ruby_wrapper); +- } +- if (super && gen) { +- rb_class_inherited(super, klass); +- } +- result = module_setup(klass, node); +- } ++ result = eval_class(self,node); + break; + + case NODE_MODULE: +- { +- VALUE module, cbase; +- ID cname; +- +- if (NIL_P(ruby_cbase)) { +- rb_raise(rb_eTypeError, "no outer class/module"); +- } +- cbase = class_prefix(self, node->nd_cpath); +- cname = node->nd_cpath->nd_mid; +- if (rb_const_defined_at(cbase, cname)) { +- module = rb_const_get_at(cbase, cname); +- if (TYPE(module) != T_MODULE) { +- rb_raise(rb_eTypeError, "%s is not a module", +- rb_id2name(cname)); +- } +- if (ruby_safe_level >= 4) { +- rb_raise(rb_eSecurityError, "extending module prohibited"); +- } +- } +- else { +- module = rb_define_module_id(cname); +- rb_set_class_path(module, cbase, rb_id2name(cname)); +- rb_const_set(cbase, cname, module); +- } +- if (ruby_wrapper) { +- rb_extend_object(module, ruby_wrapper); +- rb_include_module(module, ruby_wrapper); +- } +- +- result = module_setup(module, node); +- } ++ result = eval_module(self,node); + break; + + case NODE_SCLASS: +- { +- VALUE klass; +- +- result = rb_eval(self, node->nd_recv); +- if (FIXNUM_P(result) || SYMBOL_P(result)) { +- rb_raise(rb_eTypeError, "no virtual class for %s", +- rb_obj_classname(result)); +- } +- if (ruby_safe_level >= 4 && !OBJ_TAINTED(result)) +- rb_raise(rb_eSecurityError, "Insecure: can't extend object"); +- klass = rb_singleton_class(result); +- +- if (ruby_wrapper) { +- rb_extend_object(klass, ruby_wrapper); +- rb_include_module(klass, ruby_wrapper); +- } +- +- result = module_setup(klass, node); +- } ++ result = eval_sclass(self,node); + break; + + case NODE_DEFINED: +- { +- char buf[20]; +- char *desc = is_defined(self, node->nd_head, buf); +- +- if (desc) result = rb_str_new2(desc); +- else result = Qnil; +- } ++ result = eval_defined(self,node); + break; + + case NODE_NEWLINE: +@@ -4151,25 +4297,19 @@ rb_eval(self, n) + default: + unknown_node(node); + } +- finish: +- CHECK_INTS; +- if (contnode) { +- node = contnode; +- contnode = 0; +- goto again; +- } +- return result; ++ } ++ return result; + } + + static VALUE + module_setup(module, n) + VALUE module; +- NODE *n; ++ NODE * volatile n; + { +- NODE * volatile node = n->nd_body; ++ NODE *node = n->nd_body; + int state; + struct FRAME frame; +- VALUE result = Qnil; /* OK */ ++ VALUE result; + TMP_PROTECT; + + frame = *ruby_frame; +@@ -4560,16 +4700,16 @@ rb_iter_break() + break_jump(Qnil); + } + +-NORETURN(static void rb_longjmp _((int, VALUE))); ++NORETURN(static void rb_longjmp _((volatile int, volatile VALUE))); + static VALUE make_backtrace _((void)); + + static void + rb_longjmp(tag, mesg) +- int tag; +- VALUE mesg; ++ volatile int tag; ++ volatile VALUE mesg; + { + VALUE at; +- rb_thread_t th = curr_thread; ++ volatile rb_thread_t th = curr_thread; + + if (rb_thread_set_raised(th)) { + ruby_errinfo = exception_error; +@@ -4658,7 +4798,8 @@ rb_exc_fatal(mesg) + void + rb_interrupt() + { +- rb_raise(rb_eInterrupt, ""); ++ static const char fmt[1] = {'\0'}; ++ rb_raise(rb_eInterrupt, fmt); + } + + /* +@@ -4814,7 +4955,7 @@ proc_jump_error(state, result) + VALUE result; + { + char mesg[32]; +- char *statement; ++ const char *statement; + + switch (state) { + case TAG_BREAK: +@@ -4925,19 +5066,21 @@ rb_need_block() + + static VALUE + rb_yield_0(val, self, klass, flags, avalue) +- VALUE val, self, klass; /* OK */ +- int flags, avalue; ++ volatile VALUE val, self; ++ VALUE klass; ++ int flags; ++ volatile int avalue; + { +- NODE *node; ++ NODE *volatile node; + volatile VALUE result = Qnil; + volatile VALUE old_cref; + volatile VALUE old_wrapper; + struct BLOCK * volatile block; + struct SCOPE * volatile old_scope; +- int old_vmode; ++ volatile int old_vmode; + struct FRAME frame; + NODE *cnode = ruby_current_node; +- int lambda = flags & YIELD_LAMBDA_CALL; ++ volatile int lambda = flags & YIELD_LAMBDA_CALL; + int state; + + rb_need_block(); +@@ -5116,6 +5259,7 @@ rb_yield_0(val, self, klass, flags, avalue) + tt->retval = result; + JUMP_TAG(TAG_BREAK); + } ++ if (tt->tag == PROT_THREAD) break; + tt = tt->prev; + } + proc_jump_error(TAG_BREAK, result); +@@ -5133,6 +5277,7 @@ VALUE + rb_yield(val) + VALUE val; + { ++ wipeBeforeYield(); + return rb_yield_0(val, 0, 0, 0, Qfalse); + } + +@@ -5195,6 +5340,7 @@ static VALUE + rb_f_loop() + { + for (;;) { ++ wipeBeforeYield(); + rb_yield_0(Qundef, 0, 0, 0, Qfalse); + CHECK_INTS; + } +@@ -5348,11 +5494,12 @@ assign(self, lhs, val, pcall) + + VALUE + rb_iterate(it_proc, data1, bl_proc, data2) +- VALUE (*it_proc) _((VALUE)), (*bl_proc)(ANYARGS); +- VALUE data1, data2; ++ VALUE (* volatile it_proc) _((VALUE)), (*bl_proc)(ANYARGS); ++ volatile VALUE data1; ++ VALUE data2; + { + int state; +- volatile VALUE retval = Qnil; ++ VALUE retval = Qnil; + NODE *node = NEW_IFUNC(bl_proc, data2); + VALUE self = ruby_top_self; + +@@ -5376,12 +5523,7 @@ rb_iterate(it_proc, data1, bl_proc, data2) + POP_BLOCK(); + POP_TAG(); + +- switch (state) { +- case 0: +- break; +- default: +- JUMP_TAG(state); +- } ++ if (state) JUMP_TAG(state); + return retval; + } + +@@ -5413,16 +5555,17 @@ handle_rescue(self, node) + + VALUE + #ifdef HAVE_STDARG_PROTOTYPES +-rb_rescue2(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*r_proc)(ANYARGS), VALUE data2, ...) ++rb_rescue2(VALUE (* volatile b_proc)(ANYARGS), volatile VALUE data1, ++ VALUE (* volatile r_proc)(ANYARGS), volatile VALUE data2, ...) + #else + rb_rescue2(b_proc, data1, r_proc, data2, va_alist) +- VALUE (*b_proc)(ANYARGS), (*r_proc)(ANYARGS); +- VALUE data1, data2; ++ VALUE (* volatile b_proc)(ANYARGS), (* volatile r_proc)(ANYARGS); ++ volatile VALUE data1, data2; + va_dcl + #endif + { + int state; +- volatile VALUE result; ++ VALUE result; + volatile VALUE e_info = ruby_errinfo; + volatile int handle = Qfalse; + VALUE eclass; +@@ -5481,9 +5624,9 @@ VALUE + rb_protect(proc, data, state) + VALUE (*proc) _((VALUE)); + VALUE data; +- int *state; ++ int * volatile state; + { +- VALUE result = Qnil; /* OK */ ++ VALUE result; + int status; + + PUSH_TAG(PROT_NONE); +@@ -5496,22 +5639,18 @@ rb_protect(proc, data, state) + if (state) { + *state = status; + } +- if (status != 0) { +- return Qnil; +- } +- +- return result; ++ return status ? Qnil : result; + } + + VALUE + rb_ensure(b_proc, data1, e_proc, data2) + VALUE (*b_proc)(); + VALUE data1; +- VALUE (*e_proc)(); +- VALUE data2; ++ VALUE (* volatile e_proc)(); ++ volatile VALUE data2; + { + int state; +- volatile VALUE result = Qnil; ++ VALUE result; + VALUE retval; + + PUSH_TAG(PROT_NONE); +@@ -5519,7 +5658,7 @@ rb_ensure(b_proc, data1, e_proc, data2) + result = (*b_proc)(data1); + } + POP_TAG(); +- retval = prot_tag ? prot_tag->retval : Qnil; /* save retval */ ++ if (prot_tag) retval = prot_tag->retval; /* save retval */ + if (!thread_no_ensure()) { + (*e_proc)(data2); + } +@@ -5533,7 +5672,7 @@ rb_with_disable_interrupt(proc, data) + VALUE (*proc)(); + VALUE data; + { +- VALUE result = Qnil; /* OK */ ++ VALUE result; + int status; + + DEFER_INTS; +@@ -5610,7 +5749,7 @@ rb_method_missing(argc, argv, obj) + { + ID id; + VALUE exc = rb_eNoMethodError; +- char *format = 0; ++ const char *format = 0; + NODE *cnode = ruby_current_node; + + if (argc == 0 || !SYMBOL_P(argv[0])) { +@@ -5785,16 +5924,16 @@ call_cfunc(func, recv, len, argc, argv) + + static VALUE + rb_call0(klass, recv, id, oid, argc, argv, body, flags) +- VALUE klass, recv; +- ID id; ++ volatile VALUE klass, recv; ++ volatile ID id; + ID oid; +- int argc; /* OK */ +- VALUE *argv; /* OK */ +- NODE * volatile body; ++ int argc; ++ VALUE *argv; ++ NODE *volatile body; + int flags; + { + NODE *b2; /* OK */ +- volatile VALUE result = Qnil; ++ VALUE result; + int itr; + static int tick; + TMP_PROTECT; +@@ -5911,7 +6050,7 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags) + { + int state; + VALUE *local_vars; /* OK */ +- NODE *saved_cref = 0; ++ NODE * volatile saved_cref = 0; + + PUSH_SCOPE(); + if (body->nd_rval) { +@@ -6054,7 +6193,6 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags) + + default: + unknown_node(body); +- break; + } + POP_FRAME(); + POP_ITER(); +@@ -6222,7 +6360,7 @@ rb_funcall_rescue(recv, mid, n, va_alist) + va_dcl + #endif + { +- VALUE result = Qnil; /* OK */ ++ VALUE result; + int status; + va_list ar; + +@@ -6413,7 +6551,7 @@ rb_frame_last_func() + static NODE* + compile(src, file, line) + VALUE src; +- char *file; ++ const char *file; + int line; + { + NODE *node; +@@ -6432,12 +6570,13 @@ compile(src, file, line) + + static VALUE + eval(self, src, scope, file, line) +- VALUE self, src, scope; +- char *file; ++ VALUE self, src; ++ volatile VALUE scope; ++ const char * volatile file; + int line; + { + struct BLOCK *data = NULL; +- volatile VALUE result = Qnil; ++ VALUE result; + struct SCOPE * volatile old_scope; + struct BLOCK * volatile old_block; + struct RVarmap * volatile old_dyna_vars; +@@ -6445,7 +6584,7 @@ eval(self, src, scope, file, line) + int volatile old_vmode; + volatile VALUE old_wrapper; + struct FRAME frame; +- NODE *nodesave = ruby_current_node; ++ NODE * volatile nodesave = ruby_current_node; + volatile int iter = ruby_frame->iter; + volatile int safe = ruby_safe_level; + int state; +@@ -6510,7 +6649,7 @@ eval(self, src, scope, file, line) + compile_error(0); + } + if (!NIL_P(result)) ruby_errinfo = result; +- result = eval_node(self, node); ++ result = eval_tree(self, node); + } + POP_TAG(); + POP_CLASS(); +@@ -6532,6 +6671,7 @@ eval(self, src, scope, file, line) + + scope_dup(ruby_scope); + for (tag=prot_tag; tag; tag=tag->prev) { ++ if (tag->tag == PROT_THREAD) break; + scope_dup(tag->scope); + } + for (vars = ruby_dyna_vars; vars; vars = vars->next) { +@@ -6594,7 +6734,7 @@ rb_f_eval(argc, argv, self) + VALUE self; + { + VALUE src, scope, vfile, vline; +- char *file = "(eval)"; ++ const char *file = "(eval)"; + int line = 1; + + rb_scan_args(argc, argv, "13", &src, &scope, &vfile, &vline); +@@ -6635,12 +6775,13 @@ rb_f_eval(argc, argv, self) + static VALUE + exec_under(func, under, cbase, args) + VALUE (*func)(); +- VALUE under, cbase; ++ VALUE under; ++ volatile VALUE cbase; + void *args; + { +- VALUE val = Qnil; /* OK */ ++ VALUE val; + int state; +- int mode; ++ volatile int mode; + struct FRAME *f = ruby_frame; + + PUSH_CLASS(under); +@@ -6732,7 +6873,7 @@ specific_eval(argc, argv, klass, self) + return yield_under(klass, self); + } + else { +- char *file = "(eval)"; ++ const char *file = "(eval)"; + int line = 1; + + if (argc == 0) { +@@ -6846,9 +6987,9 @@ rb_load(fname, wrap) + volatile int prohibit_int = rb_prohibit_interrupt; + volatile ID last_func; + volatile VALUE wrapper = ruby_wrapper; +- volatile VALUE self = ruby_top_self; ++ VALUE self = ruby_top_self; + NODE *volatile last_node; +- NODE *saved_cref = ruby_cref; ++ NODE *volatile saved_cref = ruby_cref; + + if (wrap && ruby_safe_level >= 4) { + StringValue(fname); +@@ -6897,7 +7038,7 @@ rb_load(fname, wrap) + ruby_current_node = 0; + if (state == 0) { + NODE *node; +- volatile int critical; ++ int critical; + + DEFER_INTS; + ruby_in_eval++; +@@ -6909,7 +7050,7 @@ rb_load(fname, wrap) + rb_thread_critical = critical; + ALLOW_INTS; + if (ruby_nerrs == 0) { +- eval_node(self, node); ++ eval_tree(self, node); + } + } + ruby_frame->last_func = last_func; +@@ -6942,7 +7083,7 @@ void + rb_load_protect(fname, wrap, state) + VALUE fname; + int wrap; +- int *state; ++ int * volatile state; + { + int status; + +@@ -7231,7 +7372,7 @@ rb_require_safe(fname, safe) + VALUE fname; + int safe; + { +- VALUE result = Qnil; ++ VALUE result; + volatile VALUE errinfo = ruby_errinfo; + int state; + struct { +@@ -7282,7 +7423,8 @@ rb_require_safe(fname, safe) + rb_provide_feature(feature); + result = Qtrue; + } +- } ++ }else ++ result = Qnil; + } + POP_TAG(); + ruby_current_node = saved.node; +@@ -7950,7 +8092,7 @@ rb_f_at_exit() + void + rb_exec_end_proc() + { +- struct end_proc_data *link, *tmp; ++ struct end_proc_data *tmp, *volatile link; + int status; + volatile int safe = ruby_safe_level; + +@@ -8595,8 +8737,9 @@ proc_invoke(proc, args, self, klass) + int state; + volatile int safe = ruby_safe_level; + volatile VALUE old_wrapper = ruby_wrapper; +- volatile int pcall, avalue = Qtrue; +- volatile VALUE tmp = args; ++ volatile int pcall; ++ int avalue = Qtrue; ++ VALUE tmp = args; + + if (rb_block_given_p() && ruby_frame->last_func) { + if (klass != ruby_frame->last_class) +@@ -8814,7 +8957,7 @@ proc_to_s(self) + { + struct BLOCK *data; + NODE *node; +- char *cname = rb_obj_classname(self); ++ const char *cname = rb_obj_classname(self); + const int w = (sizeof(VALUE) * CHAR_BIT) / 4; + long len = strlen(cname)+6+w; /* 6:tags 16:addr */ + VALUE str; +@@ -8895,15 +9038,15 @@ proc_binding(proc) + + static VALUE + block_pass(self, node) +- VALUE self; +- NODE *node; ++ volatile VALUE self; ++ NODE *volatile node; + { +- VALUE proc = rb_eval(self, node->nd_body); /* OK */ ++ volatile VALUE proc = rb_eval(self, node->nd_body); + VALUE b; + struct BLOCK * volatile old_block; + struct BLOCK _block; + struct BLOCK *data; +- volatile VALUE result = Qnil; ++ VALUE result; + int state; + volatile int orphan; + volatile int safe = ruby_safe_level; +@@ -8950,20 +9093,24 @@ block_pass(self, node) + + PUSH_TAG(PROT_LOOP); + state = EXEC_TAG(); +- if (state == 0) { +- retry: ++ switch (state) { ++ case TAG_RETRY: ++ state = 0; ++ case 0: + proc_set_safe_level(proc); + if (safe > ruby_safe_level) + ruby_safe_level = safe; + result = rb_eval(self, node->nd_iter); +- } +- else if (state == TAG_BREAK && TAG_DST()) { +- result = prot_tag->retval; +- state = 0; +- } +- else if (state == TAG_RETRY) { +- state = 0; +- goto retry; ++ break; ++ case TAG_BREAK: ++ result = Qnil; ++ if (TAG_DST()) { ++ result = prot_tag->retval; ++ state = 0; ++ } ++ break; ++ default: ++ result = Qnil; + } + POP_TAG(); + POP_ITER(); +@@ -8980,7 +9127,6 @@ block_pass(self, node) + default: + JUMP_TAG(state); + } +- + return result; + } + +@@ -9239,7 +9385,7 @@ method_call(argc, argv, method) + VALUE *argv; + VALUE method; + { +- VALUE result = Qnil; /* OK */ ++ VALUE result; + struct METHOD *data; + int safe; + +@@ -9473,7 +9619,7 @@ method_inspect(method) + struct METHOD *data; + VALUE str; + const char *s; +- char *sharp = "#"; ++ const char *sharp = "#"; + + Data_Get_Struct(method, struct METHOD, data); + str = rb_str_buf_new2("#<"); +@@ -9538,12 +9684,9 @@ static VALUE + bmcall(args, method) + VALUE args, method; + { +- volatile VALUE a; +- VALUE ret; +- +- a = svalue_to_avalue(args); +- ret = method_call(RARRAY(a)->len, RARRAY(a)->ptr, method); +- a = Qnil; /* prevent tail call */ ++ VALUE a = svalue_to_avalue(args); ++ VALUE ret = method_call(RARRAY(a)->len, RARRAY(a)->ptr, method); ++ RB_GC_GUARD(a); /* ensure a is not GC'd during method_call */ + return ret; + } + +@@ -9658,6 +9801,7 @@ rb_mod_define_method(argc, argv, mod) + else { + rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); + } ++ SET_METHOD_SOURCE(); + if (RDATA(body)->dmark == (RUBY_DATA_FUNC)bm_mark) { + node = NEW_DMETHOD(method_unbind(body)); + } +@@ -9689,6 +9833,112 @@ rb_mod_define_method(argc, argv, mod) + return body; + } + ++ ++#ifdef MBARI_API ++/* ++ * call-seq: ++ * meth.__file__ => String ++ * ++ * returns the filename containing this method's definition ++ * ++ * raises ArgumentError if method has no associated ruby source code ++ * ++ * Only available when MBARI_API extentions are enabled at build time ++ */ ++ ++static VALUE ++method_source_file_name(VALUE method) ++{ ++ struct METHOD *data; ++ NODE *node; ++ ++ Data_Get_Struct(method, struct METHOD, data); ++ if (node = data->body) { ++ const char *filename = node->nd_file; ++ if (filename) ++ return rb_str_new2(filename); ++ } ++ rb_raise(rb_eArgError, "native Method"); ++} ++ ++/* ++ * call-seq: ++ * meth.__line__ => Fixnum ++ * ++ * returns the starting line number of this method ++ * ++ * raises ArgumentError if method has no associated ruby source code ++ * ++ * Only available when MBARI_API extentions are enabled at build time ++ */ ++ ++static VALUE ++method_source_line(VALUE method) ++{ ++ struct METHOD *data; ++ NODE *node; ++ ++ Data_Get_Struct(method, struct METHOD, data); ++ if (node = data->body) { ++ int lineno = nd_line(node); ++ if (lineno) ++ return INT2FIX(nd_line(node)); ++ } ++ rb_raise(rb_eArgError, "native Method"); ++} ++ ++ ++/* ++ * call-seq: ++ * prc.__file__ => String ++ * ++ * returns the filename where this proc is defined ++ * ++ * raises ArgumentError if proc has no associated ruby source ++ * ++ * Only available when MBARI_API extentions are enabled at build time ++ */ ++ ++static VALUE ++proc_source_file_name(VALUE block) ++{ ++ struct BLOCK *data; ++ const char *filename; ++ NODE *node; ++ ++ Data_Get_Struct(block, struct BLOCK, data); ++ if ((node = data->frame.node) || (node = data->body)) ++ return rb_str_new2(node->nd_file); ++ rb_raise(rb_eArgError, "native Proc"); ++} ++ ++ ++/* ++ * call-seq: ++ * prc.__line__ => Fixnum ++ * ++ * returns the starting line number of this proc ++ * ++ * raises ArgumentError if proc has no associated ruby source code ++ * ++ * Only available when MBARI_API extentions are enabled at build time ++ */ ++ ++static VALUE ++proc_source_line(VALUE block) ++{ ++ struct BLOCK *data; ++ NODE *node; ++ ++ Data_Get_Struct(block, struct BLOCK, data); ++ if ((node = data->frame.node) || (node = data->body)) ++ return INT2FIX( nd_line(node) ); ++ rb_raise(rb_eArgError, "native Proc"); ++} ++ ++#endif /* MBARI_API */ ++ ++ + /* + * Proc objects are blocks of code that have been bound to + * a set of local variables. Once bound, the code may be called in +@@ -9768,6 +10018,15 @@ Init_Proc() + rb_define_method(rb_cUnboundMethod, "to_s", method_inspect, 0); + rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1); + rb_define_method(rb_cModule, "instance_method", rb_mod_method, 1); ++ ++#ifdef MBARI_API ++ rb_define_method(rb_cUnboundMethod, "__file__", method_source_file_name, 0); ++ rb_define_method(rb_cUnboundMethod, "__line__", method_source_line, 0); ++ rb_define_method(rb_cProc, "__file__", proc_source_file_name, 0); ++ rb_define_method(rb_cProc, "__line__", proc_source_line, 0); ++ rb_define_method(rb_cMethod, "__file__", method_source_file_name, 0); ++ rb_define_method(rb_cMethod, "__line__", method_source_line, 0); ++#endif + } + + /* +@@ -10084,14 +10343,19 @@ timeofday() + return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6; + } + +-#define STACK(addr) (th->stk_pos<(VALUE*)(addr) && (VALUE*)(addr)stk_pos+th->stk_len) +-#define ADJ(addr) (void*)(STACK(addr)?(((VALUE*)(addr)-th->stk_pos)+th->stk_ptr):(VALUE*)(addr)) ++ ++#define ADJ(addr) \ ++ if ((size_t)((void *)addr - stkBase) < stkSize) addr=(void *)addr + stkShift ++ + static void + thread_mark(th) + rb_thread_t th; + { + struct FRAME *frame; + struct BLOCK *block; ++ void *stkBase; ++ ptrdiff_t stkShift; ++ size_t stkSize; + + rb_gc_mark(th->result); + rb_gc_mark(th->thread); +@@ -10126,15 +10390,26 @@ thread_mark(th) + } + #endif + } ++ ++ stkBase = (void *)th->stk_start; ++ stkSize = th->stk_len * sizeof(VALUE); ++#if STACK_GROW_DIRECTION == 0 ++ if (rb_gc_stack_grow_direction < 0) ++#endif ++#if STACK_GROW_DIRECTION <= 0 ++ stkBase -= stkSize; ++#endif ++ stkShift = (void *)th->stk_ptr - stkBase; ++ + frame = th->frame; + while (frame && frame != top_frame) { +- frame = ADJ(frame); ++ ADJ(frame); + rb_gc_mark_frame(frame); + if (frame->tmp) { + struct FRAME *tmp = frame->tmp; + + while (tmp && tmp != top_frame) { +- tmp = ADJ(tmp); ++ ADJ(tmp); + rb_gc_mark_frame(tmp); + tmp = tmp->prev; + } +@@ -10143,7 +10418,7 @@ thread_mark(th) + } + block = th->block; + while (block) { +- block = ADJ(block); ++ ADJ(block); + rb_gc_mark_frame(&block->frame); + block = block->prev; + } +@@ -10202,16 +10477,57 @@ rb_gc_abort_threads() + } END_FOREACH_FROM(main_thread, th); + } + +-static void +-thread_free(th) ++ ++static inline void ++stack_free(th) + rb_thread_t th; + { +- if (th->stk_ptr) free(th->stk_ptr); +- th->stk_ptr = 0; ++ if (th->stk_ptr) { ++ free(th->stk_ptr); ++ th->stk_ptr = 0; ++ } + #ifdef __ia64 +- if (th->bstr_ptr) free(th->bstr_ptr); +- th->bstr_ptr = 0; ++ if (th->bstr_ptr) { ++ free(th->bstr_ptr); ++ th->bstr_ptr = 0; ++ } + #endif ++} ++ ++static void ++rb_thread_die(th) ++ rb_thread_t th; ++{ ++ th->thgroup = 0; ++ th->status = THREAD_KILLED; ++ stack_free(th); ++} ++ ++#define THREAD_DATA(threadObject) ((rb_thread_t)RDATA(threadObject)->data) ++ ++static inline void ++cc_purge(cc) ++ rb_thread_t cc; ++{ /* free continuation's stack if it has just died */ ++ if (cc->thread != Qnil && THREAD_DATA(cc->thread)->status == THREAD_KILLED) { ++ cc->thread = Qnil; ++ rb_thread_die(cc); /* can't possibly activate this stack */ ++ } ++} ++ ++static void ++cc_mark(cc) ++ rb_thread_t cc; ++{ /* mark this continuation's stack only if its parent thread is still alive */ ++ cc_purge(cc); ++ thread_mark(cc); ++} ++ ++static void ++thread_free(th) ++ rb_thread_t th; ++{ ++ stack_free(th); + if (th->locals) st_free_table(th->locals); + if (th->status != THREAD_KILLED) { + if (th->prev) th->prev->next = th->next; +@@ -10228,7 +10544,7 @@ rb_thread_check(data) + rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)", + rb_obj_classname(data)); + } +- return (rb_thread_t)RDATA(data)->data; ++ return THREAD_DATA(data); + } + + static VALUE rb_thread_raise _((int, VALUE*, rb_thread_t)); +@@ -10255,13 +10571,10 @@ static void + rb_thread_save_context(th) + rb_thread_t th; + { +- VALUE *pos; +- int len; ++ size_t len; + static VALUE tval; + +- len = ruby_stack_length(&pos); +- th->stk_len = 0; +- th->stk_pos = pos; ++ len = ruby_stack_length(th->stk_start,&th->stk_pos); + if (len > th->stk_max) { + VALUE *ptr = realloc(th->stk_ptr, sizeof(VALUE) * len); + if (!ptr) rb_memerror(); +@@ -10323,6 +10636,9 @@ static int + rb_thread_switch(n) + int n; + { ++#if STACK_WIPE_SITES & 1 ++ rb_gc_wipe_stack(); ++#endif + rb_trap_immediate = (curr_thread->flags&0x100)?1:0; + switch (n) { + case 0: +@@ -10359,15 +10675,14 @@ rb_thread_switch(n) + return 1; + } + +-#define THREAD_SAVE_CONTEXT(th) \ +- (rb_thread_switch((FLUSH_REGISTER_WINDOWS, ruby_setjmp(rb_thread_save_context(th), (th)->context)))) ++#define THREAD_SAVE_CONTEXT(th) (rb_thread_switch( wipeAfter(\ ++ ruby_setjmp(rb_thread_save_context(th), (th)->context)))) + + NORETURN(static void rb_thread_restore_context _((rb_thread_t,int))); +-NORETURN(NOINLINE(static void rb_thread_restore_context_0(rb_thread_t,int,void*))); +-NORETURN(NOINLINE(static void stack_extend(rb_thread_t, int, VALUE *))); ++NORETURN(NOINLINE(static void rb_thread_restore_context_0(rb_thread_t,int))); + + static void +-rb_thread_restore_context_0(rb_thread_t th, int exit, void *vp) ++rb_thread_restore_context_0(rb_thread_t th, int exit) + { + static rb_thread_t tmp; + static int ex; +@@ -10424,9 +10739,9 @@ static volatile int C(f), C(g), C(h), C(i), C(j); + static volatile int C(k), C(l), C(m), C(n), C(o); + static volatile int C(p), C(q), C(r), C(s), C(t); + int rb_dummy_false = 0; +-NORETURN(NOINLINE(static void register_stack_extend(rb_thread_t, int, void *, VALUE *))); ++NORETURN(NOINLINE(static void register_stack_extend(rb_thread_t, int, VALUE *))); + static void +-register_stack_extend(rb_thread_t th, int exit, void *vp, VALUE *curr_bsp) ++register_stack_extend(rb_thread_t th, int exit, VALUE *curr_bsp) + { + if (rb_dummy_false) { + /* use registers as much as possible */ +@@ -10440,52 +10755,69 @@ register_stack_extend(rb_thread_t th, int exit, void *vp, VALUE *curr_bsp) + E(p) = E(q) = E(r) = E(s) = E(t) = 0; + } + if (curr_bsp < th->bstr_pos+th->bstr_len) { +- register_stack_extend(th, exit, &exit, (VALUE*)rb_ia64_bsp()); ++ register_stack_extend(th, exit, (VALUE*)rb_ia64_bsp()); + } +- rb_thread_restore_context_0(th, exit, &exit); ++ rb_thread_restore_context_0(th, exit); + } + #undef C + #undef E + #endif + +-# if defined(_MSC_VER) && _MSC_VER >= 1300 +-__declspec(noinline) static void stack_extend(rb_thread_t, int, VALUE*); +-# endif +-static void +-stack_extend(rb_thread_t th, int exit, VALUE *addr_in_prev_frame) +-{ +-#define STACK_PAD_SIZE 1024 +- VALUE space[STACK_PAD_SIZE]; +- +-#if STACK_GROW_DIRECTION < 0 +- if (addr_in_prev_frame > th->stk_pos) stack_extend(th, exit, &space[0]); +-#elif STACK_GROW_DIRECTION > 0 +- if (addr_in_prev_frame < th->stk_pos + th->stk_len) stack_extend(th, exit, &space[STACK_PAD_SIZE-1]); +-#else +- if (addr_in_prev_frame < rb_gc_stack_start) { +- /* Stack grows downward */ +- if (addr_in_prev_frame > th->stk_pos) stack_extend(th, exit, &space[0]); +- } +- else { +- /* Stack grows upward */ +- if (addr_in_prev_frame < th->stk_pos + th->stk_len) stack_extend(th, exit, &space[STACK_PAD_SIZE-1]); +- } +-#endif +-#ifdef __ia64 +- register_stack_extend(th, exit, space, (VALUE*)rb_ia64_bsp()); +-#else +- rb_thread_restore_context_0(th, exit, space); +-#endif +-} + + static void + rb_thread_restore_context(th, exit) + rb_thread_t th; + int exit; + { ++ VALUE *pos = th->stk_start; ++ ++#if HAVE_ALLOCA /* use alloca to grow stack in O(1) time */ + VALUE v; ++ ++ if (!th->stk_ptr) rb_bug("unsaved context"); ++# if !STACK_GROW_DIRECTION /* unknown at compile time */ ++ if (rb_gc_stack_grow_direction < 0) { ++# endif ++# if STACK_GROW_DIRECTION <= 0 ++ pos -= th->stk_len; ++ if (&v > pos) ++ (volatile void *)ALLOCA_N(VALUE, &v-pos); ++# endif ++# if !STACK_GROW_DIRECTION ++ }else ++# endif ++#if STACK_GROW_DIRECTION >= 0 /* stack grows upward */ ++ if (&v < pos + th->stk_len) ++ (volatile void *)ALLOCA_N(VALUE, pos+th->stk_len - &v); ++# endif ++ ++#else /* recursive O(n/1024) if extending stack > 1024 VALUEs */ ++ ++ volatile VALUE v[1023]; ++ ++# if !STACK_GROW_DIRECTION /* unknown at compile time */ ++ if (rb_gc_stack_grow_direction < 0) { ++# endif ++# if STACK_GROW_DIRECTION <= 0 ++ pos -= th->stk_len; ++ if (v > pos) rb_thread_restore_context(th, exit); ++# endif ++# if !STACK_GROW_DIRECTION ++ }else ++# endif ++# if STACK_GROW_DIRECTION >= 0 /* stack grows upward */ ++ if (v < pos + th->stk_len) rb_thread_restore_context(th, exit); ++# endif + if (!th->stk_ptr) rb_bug("unsaved context"); +- stack_extend(th, exit, &v); ++ ++#endif /* stack now extended */ ++ ++ ++#ifdef __ia64 ++ register_stack_extend(th, exit, (VALUE*)rb_ia64_bsp()); ++#else ++ rb_thread_restore_context_0(th, exit); ++#endif + } + + static void +@@ -10499,16 +10831,6 @@ rb_thread_ready(th) + } + + static void +-rb_thread_die(th) +- rb_thread_t th; +-{ +- th->thgroup = 0; +- th->status = THREAD_KILLED; +- if (th->stk_ptr) free(th->stk_ptr); +- th->stk_ptr = 0; +-} +- +-static void + rb_thread_remove(th) + rb_thread_t th; + { +@@ -11077,8 +11399,6 @@ rb_thread_select(max, read, write, except, timeout) + return curr_thread->select_value; + } + +-static int rb_thread_join _((rb_thread_t, double)); +- + static int + rb_thread_join(th, limit) + rb_thread_t th; +@@ -11171,7 +11491,7 @@ rb_thread_join_m(argc, argv, thread) + { + VALUE limit; + double delay = DELAY_INFTY; +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + rb_scan_args(argc, argv, "01", &limit); + if (!NIL_P(limit)) delay = rb_num2dbl(limit); +@@ -11283,7 +11603,7 @@ VALUE + rb_thread_wakeup_alive(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (th->status == THREAD_KILLED) + return Qnil; +@@ -11358,7 +11678,7 @@ VALUE + rb_thread_kill(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + rb_kill_thread(th, 0); + return thread; +@@ -11382,7 +11702,7 @@ static VALUE + rb_thread_kill_bang(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + rb_kill_thread(th, THREAD_NO_ENSURE); + return thread; + } +@@ -11554,7 +11874,7 @@ static VALUE + rb_thread_priority(thread) + VALUE thread; + { +- return INT2NUM(rb_thread_check(thread)->priority); ++ return INT2NUM(THREAD_DATA(thread)->priority); + } + + +@@ -11588,7 +11908,7 @@ rb_thread_priority_set(thread, prio) + rb_thread_t th; + + rb_secure(4); +- th = rb_thread_check(thread); ++ th = THREAD_DATA(thread); + + th->priority = NUM2INT(prio); + rb_thread_schedule(); +@@ -11614,7 +11934,7 @@ rb_thread_safe_level(thread) + { + rb_thread_t th; + +- th = rb_thread_check(thread); ++ th = THREAD_DATA(thread); + if (th == curr_thread) { + return INT2NUM(ruby_safe_level); + } +@@ -11691,7 +12011,7 @@ static VALUE + rb_thread_abort_exc(thread) + VALUE thread; + { +- return rb_thread_check(thread)->abort?Qtrue:Qfalse; ++ return THREAD_DATA(thread)->abort?Qtrue:Qfalse; + } + + +@@ -11709,7 +12029,7 @@ rb_thread_abort_exc_set(thread, val) + VALUE thread, val; + { + rb_secure(4); +- rb_thread_check(thread)->abort = RTEST(val); ++ THREAD_DATA(thread)->abort = RTEST(val); + return val; + } + +@@ -11718,7 +12038,7 @@ enum rb_thread_status + rb_thread_status(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + return th->status; + } + +@@ -11737,7 +12057,7 @@ VALUE + rb_thread_group(thread) + VALUE thread; + { +- VALUE group = rb_thread_check(thread)->thgroup; ++ VALUE group = THREAD_DATA(thread)->thgroup; + if (!group) { + group = Qnil; + } +@@ -11760,6 +12080,7 @@ rb_thread_group(thread) + th->result = 0;\ + th->flags = 0;\ + \ ++ th->stk_start = rb_gc_stack_start;\ + th->stk_ptr = 0;\ + th->stk_len = 0;\ + th->stk_max = 0;\ +@@ -11971,6 +12292,16 @@ rb_thread_start_0(fn, arg, th) + "can't start a new thread (frozen ThreadGroup)"); + } + ++ ++ th->stk_start = /* establish start of new thread's stack */ ++#if STACK_GROW_DIRECTION > 0 ++ (VALUE *)ruby_frame; ++#elif STACK_GROW_DIRECTION < 0 ++ (VALUE *)(ruby_frame+1); ++#else ++ (VALUE *)(ruby_frame+((VALUE *)(&arg)prev = top_frame; /* hide parent thread's frames */ ++ ruby_frame->tmp = 0; + curr_thread = th; + th->result = (*fn)(arg, th); + } +@@ -12127,9 +12460,6 @@ rb_thread_s_new(argc, argv, klass) + VALUE klass; + { + rb_thread_t th = rb_thread_alloc(klass); +- volatile VALUE *pos; +- +- pos = th->stk_pos; + rb_obj_call_init(th->thread, argc, argv); + if (th->stk_pos == 0) { + rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'", +@@ -12167,7 +12497,7 @@ rb_thread_initialize(thread, args) + if (!rb_block_given_p()) { + rb_raise(rb_eThreadError, "must be called with a block"); + } +- th = rb_thread_check(thread); ++ th = THREAD_DATA(thread); + if (th->stk_max) { + NODE *node = th->node; + if (!node) { +@@ -12216,7 +12546,7 @@ static VALUE + rb_thread_value(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + while (!rb_thread_join(th, DELAY_INFTY)); + +@@ -12251,7 +12581,7 @@ static VALUE + rb_thread_status_name(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (rb_thread_dead(th)) { + if (!NIL_P(th->errinfo) && (th->flags & RAISED_EXCEPTION)) +@@ -12279,7 +12609,7 @@ VALUE + rb_thread_alive_p(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (rb_thread_dead(th)) return Qfalse; + return Qtrue; +@@ -12302,7 +12632,7 @@ static VALUE + rb_thread_stop_p(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (rb_thread_dead(th)) return Qtrue; + if (th->status == THREAD_STOPPED) return Qtrue; +@@ -12536,7 +12866,7 @@ rb_thread_raise_m(argc, argv, thread) + VALUE *argv; + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (ruby_safe_level > th->safe) { + rb_secure(4); +@@ -12553,7 +12883,7 @@ rb_thread_local_aref(thread, id) + rb_thread_t th; + VALUE val; + +- th = rb_thread_check(thread); ++ th = THREAD_DATA(thread); + if (ruby_safe_level >= 4 && th != curr_thread) { + rb_raise(rb_eSecurityError, "Insecure: thread locals"); + } +@@ -12599,7 +12929,7 @@ rb_thread_local_aset(thread, id, val) + ID id; + VALUE val; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (ruby_safe_level >= 4 && th != curr_thread) { + rb_raise(rb_eSecurityError, "Insecure: can't modify thread locals"); +@@ -12652,7 +12982,7 @@ static VALUE + rb_thread_key_p(thread, id) + VALUE thread, id; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (!th->locals) return Qfalse; + if (st_lookup(th->locals, rb_to_id(id), 0)) +@@ -12688,7 +13018,7 @@ static VALUE + rb_thread_keys(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + VALUE ary = rb_ary_new(); + + if (th->locals) { +@@ -12709,7 +13039,7 @@ rb_thread_inspect(thread) + VALUE thread; + { + char *cname = rb_obj_classname(thread); +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + const char *status = thread_status_name(th->status); + VALUE str; + size_t len = strlen(cname)+7+16+9+1; +@@ -12789,6 +13119,32 @@ rb_thread_atfork() + + VALUE rb_cCont; + ++ ++static rb_thread_t prep4callcc(void) ++{ ++ rb_thread_t th; ++ struct tag *tag; ++ struct RVarmap *vars; ++ ++ THREAD_ALLOC(th); ++ /* must finish th initialization before any possible gc */ ++ th->thread = curr_thread->thread; /* brent@mbari.org */ ++ th->thgroup = cont_protect; ++ ++ scope_dup(ruby_scope); ++ for (tag=prot_tag; tag; tag=tag->prev) { ++ if (tag->tag == PROT_THREAD) break; ++ scope_dup(tag->scope); ++ } ++ ++ for (vars = ruby_dyna_vars; vars; vars = vars->next) { ++ if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; ++ FL_SET(vars, DVAR_DONT_RECYCLE); ++ } ++ return th; ++} ++ ++ + /* + * call-seq: + * callcc {|cont| block } => obj +@@ -12807,35 +13163,14 @@ static VALUE + rb_callcc(self) + VALUE self; + { +- volatile VALUE cont; +- rb_thread_t th; +- volatile rb_thread_t th_save; +- struct tag *tag; +- struct RVarmap *vars; +- +- THREAD_ALLOC(th); +- cont = Data_Wrap_Struct(rb_cCont, thread_mark, thread_free, th); +- +- scope_dup(ruby_scope); +- for (tag=prot_tag; tag; tag=tag->prev) { +- scope_dup(tag->scope); +- } +- th->thread = curr_thread->thread; +- th->thgroup = cont_protect; +- +- for (vars = ruby_dyna_vars; vars; vars = vars->next) { +- if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; +- FL_SET(vars, DVAR_DONT_RECYCLE); +- } +- th_save = th; +- if (THREAD_SAVE_CONTEXT(th)) { +- return th_save->result; +- } +- else { +- return rb_yield(cont); +- } ++ volatile rb_thread_t th = prep4callcc(); ++ return THREAD_SAVE_CONTEXT(th) ? ++ th->result ++ : ++ rb_yield(Data_Wrap_Struct(rb_cCont, cc_mark, thread_free, th)); + } + ++ + /* + * call-seq: + * cont.call(args, ...) +@@ -12858,7 +13193,7 @@ rb_cont_call(argc, argv, cont) + VALUE *argv; + VALUE cont; + { +- rb_thread_t th = rb_thread_check(cont); ++ rb_thread_t th = THREAD_DATA(cont); + + if (th->thread != curr_thread->thread) { + rb_raise(rb_eRuntimeError, "continuation called across threads"); +@@ -12882,6 +13217,34 @@ rb_cont_call(argc, argv, cont) + return Qnil; + } + ++ ++#ifdef MBARI_API ++/* ++ * call-seq: ++ * cont.thread ++ * ++ * Returns the thread on which this continuation can be called ++ * or nil if that thread has died ++ * ++ * t = Thread.new {callcc{|c| $x=c}; sleep 5} ++ * sleep 1 ++ * $x.thread #=> t ++ * sleep 10 ++ * $x.thread #=> nil ++ * ++ * Only available when MBARI_API extentions are enabled at build time ++ */ ++static VALUE ++rb_cont_thread(cont) ++ VALUE cont; ++{ ++ rb_thread_t th = THREAD_DATA(cont); ++ cc_purge(th); ++ return th->thread; ++} ++#endif ++ ++ + struct thgroup { + int enclosed; + VALUE group; +@@ -13034,10 +13397,6 @@ thgroup_add(group, thread) + + rb_secure(4); + th = rb_thread_check(thread); +- if (!th->next || !th->prev) { +- rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)", +- rb_obj_classname(thread)); +- } + + if (OBJ_FROZEN(group)) { + rb_raise(rb_eThreadError, "can't move to the frozen thread group"); +@@ -13135,6 +13494,9 @@ Init_Thread() + rb_undef_method(CLASS_OF(rb_cCont), "new"); + rb_define_method(rb_cCont, "call", rb_cont_call, -1); + rb_define_method(rb_cCont, "[]", rb_cont_call, -1); ++#ifdef MBARI_API ++ rb_define_method(rb_cCont, "thread", rb_cont_thread, 0); ++#endif + rb_define_global_function("callcc", rb_callcc, 0); + rb_global_variable(&cont_protect); + +@@ -13186,14 +13548,15 @@ Init_Thread() + + static VALUE + rb_f_catch(dmy, tag) +- VALUE dmy, tag; ++ VALUE dmy; ++ volatile VALUE tag; + { + int state; +- VALUE val = Qnil; /* OK */ ++ VALUE val; + + tag = ID2SYM(rb_to_id(tag)); + PUSH_TAG(tag); +- if ((state = EXEC_TAG()) == 0) { ++ if ((state = wipeAfter(EXEC_TAG_0())) == 0) { + val = rb_yield_0(tag, 0, 0, 0, Qfalse); + } + else if (state == TAG_THROW && tag == prot_tag->dst) { +@@ -13261,6 +13624,9 @@ rb_f_throw(argc, argv) + if (!tt) { + rb_name_error(SYM2ID(tag), "uncaught throw `%s'", rb_id2name(SYM2ID(tag))); + } ++#if STACK_WIPE_SITES & 0x800 ++ rb_gc_update_stack_extent(); ++#endif + rb_trap_restore_mask(); + JUMP_TAG(TAG_THROW); + #ifndef __GNUC__ +diff --git a/gc.c b/gc.c +index 33f035e..d89ee09 100644 +--- a/gc.c ++++ b/gc.c +@@ -22,10 +22,6 @@ + #include + #include + +-#ifdef HAVE_SYS_TIME_H +-#include +-#endif +- + #ifdef HAVE_SYS_RESOURCE_H + #include + #endif +@@ -41,39 +37,150 @@ void rb_io_fptr_finalize _((struct OpenFile*)); + #define setjmp(env) _setjmp(env) + #endif + +-/* Make alloca work the best possible way. */ +-#ifdef __GNUC__ +-# ifndef atarist +-# ifndef alloca +-# define alloca __builtin_alloca +-# endif +-# endif /* atarist */ +-#else +-# ifdef HAVE_ALLOCA_H +-# include +-# else +-# ifndef _AIX +-# ifndef alloca /* predefined by HP cc +Olibcalls */ +-void *alloca (); +-# endif +-# endif /* AIX */ +-# endif /* HAVE_ALLOCA_H */ +-#endif /* __GNUC__ */ +- + #ifndef GC_MALLOC_LIMIT + #if defined(MSDOS) || defined(__human68k__) + #define GC_MALLOC_LIMIT 200000 + #else +-#define GC_MALLOC_LIMIT 8000000 ++#define GC_MALLOC_LIMIT (2000000*sizeof(VALUE)) + #endif + #endif + +-static unsigned long malloc_increase = 0; +-static unsigned long malloc_limit = GC_MALLOC_LIMIT; ++#ifndef GC_LEVEL_MAX /*maximum # of VALUEs on 'C' stack during GC*/ ++#define GC_LEVEL_MAX 8000 ++#endif ++#ifndef GC_STACK_PAD ++#define GC_STACK_PAD 200 /* extra padding VALUEs for GC stack */ ++#endif ++#define GC_STACK_MAX (GC_LEVEL_MAX+GC_STACK_PAD) ++ ++static VALUE *stack_limit, *gc_stack_limit; ++ ++static size_t malloc_increase = 0; ++static size_t malloc_limit = GC_MALLOC_LIMIT; ++ ++#ifdef MBARI_API ++/* ++ * call-seq: ++ * GC.limit => increase limit in bytes ++ * ++ * Get the # of bytes that may be allocated before triggering ++ * a mark and sweep by the garbarge collector to reclaim unused storage. ++ * ++ * Only available when MBARI_API extentions are enabled at build time ++ */ ++static VALUE gc_getlimit(VALUE mod) ++{ ++ return ULONG2NUM(malloc_limit); ++} ++ ++/* ++ * call-seq: ++ * GC.limit= => updated increase limit in bytes ++ * ++ * Set the # of bytes that may be allocated before triggering ++ * a mark and sweep by the garbarge collector to reclaim unused storage. ++ * Attempts to set the GC.limit= less than 0 will be ignored. ++ * ++ * GC.limit=5000000 #=> 5000000 ++ * GC.limit #=> 5000000 ++ * GC.limit=-50 #=> 5000000 ++ * GC.limit=0 #=> 0 #functionally equivalent to GC.stress=true ++ * ++ * Only available when MBARI_API extentions are enabled at build time ++ */ ++static VALUE gc_setlimit(VALUE mod, VALUE newLimit) ++{ ++ long limit = NUM2LONG(newLimit); ++ rb_secure(2); ++ if (limit < 0) return gc_getlimit(mod); ++ malloc_limit = limit; ++ return newLimit; ++} ++ ++ ++/* ++ * call-seq: ++ * GC.growth ++ * ++ * Get # of bytes that have been allocated since the last mark & sweep ++ * ++ * Only available when MBARI_API extentions are enabled at build time ++ */ ++static VALUE gc_growth(VALUE mod) ++{ ++ return ULONG2NUM(malloc_increase); ++} ++ ++ ++/* ++ * call-seq: ++ * GC.exorcise ++ * ++ * Purge ghost references from recently freed stack space ++ * ++ * Only available when MBARI_API extentions are enabled at build time ++ */ ++static VALUE gc_exorcise(VALUE mod) ++{ ++ rb_gc_wipe_stack(); ++ return Qnil; ++} ++ ++#else /* no api changes */ ++ ++static size_t unstressed_malloc_limit = GC_MALLOC_LIMIT; ++ ++/* ++ * call-seq: ++ * GC.stress => true or false ++ * ++ * returns current status of GC stress mode. ++ * ++ * Only available when MBARI_API extentions are disabled at build time ++ */ ++ ++static VALUE ++gc_stress_get(self) ++ VALUE self; ++{ ++ return malloc_limit ? Qfalse : Qtrue; ++} ++ ++/* ++ * call-seq: ++ * GC.stress = bool => bool ++ * ++ * updates GC stress mode. ++ * ++ * When GC.stress = true, GC is invoked for all GC opportunity: ++ * all memory and object allocation. ++ * ++ * Since it makes Ruby very slow, it is only for debugging. ++ * ++ * Only available when MBARI_API extentions are enabled at build time ++ */ ++ ++static VALUE ++gc_stress_set(self, bool) ++ VALUE self, bool; ++{ ++ rb_secure(2); ++ if (!RTEST(bool)) ++ malloc_limit = unstressed_malloc_limit; ++ else if (malloc_limit > 0) { ++ unstressed_malloc_limit = malloc_limit; ++ malloc_limit = 0; ++ } ++ return bool; ++} ++ ++#endif /* MBARI_API */ ++ + static void run_final(); + static VALUE nomem_error; + static void garbage_collect(); + ++ + NORETURN(void rb_exc_jump _((VALUE))); + + void +@@ -93,6 +200,7 @@ rb_memerror() + rb_exc_raise(nomem_error); + } + ++ + void * + ruby_xmalloc(size) + long size; +@@ -104,8 +212,9 @@ ruby_xmalloc(size) + } + if (size == 0) size = 1; + +- if ((malloc_increase+size) > malloc_limit) { ++ if ((malloc_increase+=size) > malloc_limit) { + garbage_collect(); ++ malloc_increase = size; + } + RUBY_CRITICAL(mem = malloc(size)); + if (!mem) { +@@ -115,8 +224,9 @@ ruby_xmalloc(size) + rb_memerror(); + } + } +- malloc_increase += size; +- ++#if STACK_WIPE_SITES & 0x100 ++ rb_gc_update_stack_extent(); ++#endif + return mem; + } + +@@ -144,6 +254,10 @@ ruby_xrealloc(ptr, size) + } + if (!ptr) return xmalloc(size); + if (size == 0) size = 1; ++ if ((malloc_increase+=size) > malloc_limit) { ++ garbage_collect(); ++ malloc_increase = size; ++ } + RUBY_CRITICAL(mem = realloc(ptr, size)); + if (!mem) { + garbage_collect(); +@@ -152,8 +266,9 @@ ruby_xrealloc(ptr, size) + rb_memerror(); + } + } +- malloc_increase += size; +- ++#if STACK_WIPE_SITES & 0x200 ++ rb_gc_update_stack_extent(); ++#endif + return mem; + } + +@@ -393,7 +508,7 @@ rb_newobj() + if (during_gc) + rb_bug("object allocation during garbage collection phase"); + +- if (!freelist) garbage_collect(); ++ if (!malloc_limit || !freelist) garbage_collect(); + + obj = (VALUE)freelist; + freelist = freelist->as.free.next; +@@ -428,6 +543,9 @@ VALUE *rb_gc_stack_start = 0; + VALUE *rb_gc_register_stack_start = 0; + #endif + ++VALUE *rb_gc_stack_end = (VALUE *)STACK_GROW_DIRECTION; ++ ++ + #ifdef DJGPP + /* set stack size (http://www.delorie.com/djgpp/v2faq/faq15_9.html) */ + unsigned int _stklen = 0x180000; /* 1.5 kB */ +@@ -445,77 +563,90 @@ static unsigned int STACK_LEVEL_MAX = 655300; + # define STACK_LEVEL_MAX 655300 + #endif + +-#ifdef C_ALLOCA +-# define SET_STACK_END VALUE stack_end; alloca(0); ++#ifndef nativeAllocA ++ /* portable way to return an approximate stack pointer */ ++NOINLINE(VALUE *__sp(void)); ++VALUE *__sp(void) { ++ VALUE tos; ++ return &tos; ++} ++# define SET_STACK_END VALUE stack_end + # define STACK_END (&stack_end) + #else +-# if defined(__GNUC__) && defined(USE_BUILTIN_FRAME_ADDRESS) && !defined(__ia64) +-# if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3 +-__attribute__ ((noinline)) +-# endif +-static void +-stack_end_address(VALUE **stack_end_p) +-{ +- VALUE stack_end; +- *stack_end_p = &stack_end; +-} +-# define SET_STACK_END VALUE *stack_end; stack_end_address(&stack_end) +-# else +-# define SET_STACK_END VALUE *stack_end = alloca(1) +-# endif +-# define STACK_END (stack_end) ++# define SET_STACK_END ((void)0) ++# define STACK_END __sp() + #endif ++ + #if STACK_GROW_DIRECTION < 0 +-# define STACK_LENGTH (rb_gc_stack_start - STACK_END) ++# define STACK_LENGTH(start) ((start) - STACK_END) + #elif STACK_GROW_DIRECTION > 0 +-# define STACK_LENGTH (STACK_END - rb_gc_stack_start + 1) ++# define STACK_LENGTH(start) (STACK_END - (start) + 1) + #else +-# define STACK_LENGTH ((STACK_END < rb_gc_stack_start) ? rb_gc_stack_start - STACK_END\ +- : STACK_END - rb_gc_stack_start + 1) ++# define STACK_LENGTH(start) ((STACK_END < (start)) ? \ ++ (start) - STACK_END : STACK_END - (start) + 1) + #endif ++ + #if STACK_GROW_DIRECTION > 0 +-# define STACK_UPPER(x, a, b) a ++# define STACK_UPPER(a, b) a + #elif STACK_GROW_DIRECTION < 0 +-# define STACK_UPPER(x, a, b) b ++# define STACK_UPPER(a, b) b + #else +-static int grow_direction; ++int rb_gc_stack_grow_direction; + static int + stack_grow_direction(addr) + VALUE *addr; + { + SET_STACK_END; +- +- if (STACK_END > addr) return grow_direction = 1; +- return grow_direction = -1; ++ return rb_gc_stack_grow_direction = STACK_END > addr ? 1 : -1; + } +-# define stack_growup_p(x) ((grow_direction ? grow_direction : stack_grow_direction(x)) > 0) +-# define STACK_UPPER(x, a, b) (stack_growup_p(x) ? a : b) ++# define STACK_UPPER(a, b) (rb_gc_stack_grow_direction > 0 ? a : b) + #endif + +-#define GC_WATER_MARK 512 +- +-#define CHECK_STACK(ret) do {\ +- SET_STACK_END;\ +- (ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\ +-} while (0) +- +-int +-ruby_stack_length(p) +- VALUE **p; ++size_t ++ruby_stack_length(start, base) ++ VALUE *start, **base; + { + SET_STACK_END; +- if (p) *p = STACK_UPPER(STACK_END, rb_gc_stack_start, STACK_END); +- return STACK_LENGTH; ++ if (base) *base = STACK_UPPER(start, STACK_END); ++ return STACK_LENGTH(start); + } + + int + ruby_stack_check() + { +- int ret; ++ SET_STACK_END; ++ return __stack_past(stack_limit, STACK_END); ++} + +- CHECK_STACK(ret); +- return ret; ++/* ++ Zero memory that was (recently) part of the stack, but is no longer. ++ Invoke when stack is deep to mark its extent and when it's shallow to wipe it. ++*/ ++#if STACK_WIPE_METHOD != 4 ++#if STACK_WIPE_METHOD ++void rb_gc_wipe_stack(void) ++{ ++ VALUE *stack_end = rb_gc_stack_end; ++ VALUE *sp = __sp(); ++ rb_gc_stack_end = sp; ++#if STACK_WIPE_METHOD == 1 ++#warning clearing of "ghost references" from the call stack has been disabled ++#elif STACK_WIPE_METHOD == 2 /* alloca ghost stack before clearing it */ ++ if (__stack_past(sp, stack_end)) { ++ size_t bytes = __stack_depth((char *)stack_end, (char *)sp); ++ STACK_UPPER(sp = nativeAllocA(bytes), stack_end = nativeAllocA(bytes)); ++ __stack_zero(stack_end, sp); ++ } ++#elif STACK_WIPE_METHOD == 3 /* clear unallocated area past stack pointer */ ++ __stack_zero(stack_end, sp); /* will crash if compiler pushes a temp. here */ ++#else ++#error unsupported method of clearing ghost references from the stack ++#endif + } ++#else ++#warning clearing of "ghost references" from the call stack completely disabled ++#endif ++#endif + + #define MARK_STACK_MAX 1024 + static VALUE mark_stack[MARK_STACK_MAX]; +@@ -530,7 +661,18 @@ init_mark_stack() + } + + #define MARK_STACK_EMPTY (mark_stack_ptr == mark_stack) +- ++ ++static inline void ++push_mark_stack(VALUE ptr) ++{ ++ if (!mark_stack_overflow) { ++ if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) ++ *mark_stack_ptr++ = ptr; ++ else ++ mark_stack_overflow = 1; ++ } ++} ++ + static st_table *source_filenames; + + char * +@@ -574,22 +716,22 @@ sweep_source_filename(key, value) + } + } + +-static void gc_mark _((VALUE ptr, int lev)); +-static void gc_mark_children _((VALUE ptr, int lev)); ++#define gc_mark(ptr) rb_gc_mark(ptr) ++static void gc_mark_children _((VALUE ptr)); + + static void + gc_mark_all() + { + RVALUE *p, *pend; +- int i; ++ struct heaps_slot *heap = heaps+heaps_used; + + init_mark_stack(); +- for (i = 0; i < heaps_used; i++) { +- p = heaps[i].slot; pend = p + heaps[i].limit; ++ while (--heap >= heaps) { ++ p = heap->slot; pend = p + heap->limit; + while (p < pend) { + if ((p->as.basic.flags & FL_MARK) && + (p->as.basic.flags != FL_MARK)) { +- gc_mark_children((VALUE)p, 0); ++ gc_mark_children((VALUE)p); + } + p++; + } +@@ -599,169 +741,129 @@ gc_mark_all() + static void + gc_mark_rest() + { ++ size_t stackLen = mark_stack_ptr - mark_stack; ++#ifdef nativeAllocA ++ VALUE *tmp_arry = nativeAllocA(stackLen*sizeof(VALUE)); ++#else + VALUE tmp_arry[MARK_STACK_MAX]; +- VALUE *p; +- +- p = (mark_stack_ptr - mark_stack) + tmp_arry; +- MEMCPY(tmp_arry, mark_stack, VALUE, MARK_STACK_MAX); ++#endif ++ VALUE *p = tmp_arry + stackLen; ++ ++ MEMCPY(tmp_arry, mark_stack, VALUE, stackLen); + + init_mark_stack(); +- while(p != tmp_arry){ +- p--; +- gc_mark_children(*p, 0); +- } ++ while(--p >= tmp_arry) gc_mark_children(*p); + } + + static inline int + is_pointer_to_heap(ptr) + void *ptr; + { +- register RVALUE *p = RANY(ptr); +- register RVALUE *heap_org; +- register long i; ++ RVALUE *p = RANY(ptr); ++ struct heaps_slot *heap; + +- if (p < lomem || p > himem) return Qfalse; +- if ((VALUE)p % sizeof(RVALUE) != 0) return Qfalse; ++ if (p < lomem || p > himem || (VALUE)p % sizeof(RVALUE)) return Qfalse; + + /* check if p looks like a pointer */ +- for (i=0; i < heaps_used; i++) { +- heap_org = heaps[i].slot; +- if (heap_org <= p && p < heap_org + heaps[i].limit) +- return Qtrue; +- } ++ heap = heaps+heaps_used; ++ while (--heap >= heaps) ++ if (p >= heap->slot && p < heap->slot + heap->limit) ++ return Qtrue; + return Qfalse; + } + + static void + mark_locations_array(x, n) +- register VALUE *x; +- register long n; ++ VALUE *x; ++ size_t n; + { + VALUE v; + while (n--) { + v = *x; + if (is_pointer_to_heap((void *)v)) { +- gc_mark(v, 0); ++ gc_mark(v); + } + x++; + } + } + +-void ++inline void + rb_gc_mark_locations(start, end) + VALUE *start, *end; + { +- long n; +- +- n = end - start; +- mark_locations_array(start,n); ++ mark_locations_array(start,end - start); + } + + static int +-mark_entry(key, value, lev) ++mark_entry(key, value) + ID key; + VALUE value; +- int lev; + { +- gc_mark(value, lev); ++ gc_mark(value); + return ST_CONTINUE; + } + +-static void +-mark_tbl(tbl, lev) +- st_table *tbl; +- int lev; +-{ +- if (!tbl) return; +- st_foreach(tbl, mark_entry, lev); +-} +- + void + rb_mark_tbl(tbl) + st_table *tbl; + { +- mark_tbl(tbl, 0); ++ if (!tbl) return; ++ st_foreach(tbl, mark_entry, 0); + } ++#define mark_tbl(tbl) rb_mark_tbl(tbl) + + static int +-mark_keyvalue(key, value, lev) ++mark_keyvalue(key, value) + VALUE key; + VALUE value; +- int lev; + { +- gc_mark(key, lev); +- gc_mark(value, lev); ++ gc_mark(key); ++ gc_mark(value); + return ST_CONTINUE; + } + +-static void +-mark_hash(tbl, lev) +- st_table *tbl; +- int lev; +-{ +- if (!tbl) return; +- st_foreach(tbl, mark_keyvalue, lev); +-} +- + void + rb_mark_hash(tbl) + st_table *tbl; + { +- mark_hash(tbl, 0); ++ if (!tbl) return; ++ st_foreach(tbl, mark_keyvalue, 0); + } ++#define mark_hash(tbl) rb_mark_hash(tbl) + + void + rb_gc_mark_maybe(obj) + VALUE obj; + { + if (is_pointer_to_heap((void *)obj)) { +- gc_mark(obj, 0); ++ gc_mark(obj); + } + } + +-#define GC_LEVEL_MAX 250 +- +-static void +-gc_mark(ptr, lev) ++void ++rb_gc_mark(ptr) + VALUE ptr; +- int lev; + { +- register RVALUE *obj; +- +- obj = RANY(ptr); ++ RVALUE *obj = RANY(ptr); ++ SET_STACK_END; ++ + if (rb_special_const_p(ptr)) return; /* special const not marked */ + if (obj->as.basic.flags == 0) return; /* free cell */ + if (obj->as.basic.flags & FL_MARK) return; /* already marked */ + obj->as.basic.flags |= FL_MARK; + +- if (lev > GC_LEVEL_MAX || (lev == 0 && ruby_stack_check())) { +- if (!mark_stack_overflow) { +- if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) { +- *mark_stack_ptr = ptr; +- mark_stack_ptr++; +- } +- else { +- mark_stack_overflow = 1; +- } +- } +- return; ++ if (__stack_past(gc_stack_limit, STACK_END)) ++ push_mark_stack(ptr); ++ else{ ++ gc_mark_children(ptr); + } +- gc_mark_children(ptr, lev+1); +-} +- +-void +-rb_gc_mark(ptr) +- VALUE ptr; +-{ +- gc_mark(ptr, 0); + } + + static void +-gc_mark_children(ptr, lev) ++gc_mark_children(ptr) + VALUE ptr; +- int lev; + { +- register RVALUE *obj = RANY(ptr); ++ RVALUE *obj = RANY(ptr); + + goto marking; /* skip */ + +@@ -795,7 +897,7 @@ gc_mark_children(ptr, lev) + case NODE_RESCUE: + case NODE_RESBODY: + case NODE_CLASS: +- gc_mark((VALUE)obj->as.node.u2.node, lev); ++ gc_mark((VALUE)obj->as.node.u2.node); + /* fall through */ + case NODE_BLOCK: /* 1,3 */ + case NODE_ARRAY: +@@ -808,7 +910,7 @@ gc_mark_children(ptr, lev) + case NODE_CALL: + case NODE_DEFS: + case NODE_OP_ASGN1: +- gc_mark((VALUE)obj->as.node.u1.node, lev); ++ gc_mark((VALUE)obj->as.node.u1.node); + /* fall through */ + case NODE_SUPER: /* 3 */ + case NODE_FCALL: +@@ -835,7 +937,7 @@ gc_mark_children(ptr, lev) + case NODE_ALIAS: + case NODE_VALIAS: + case NODE_ARGS: +- gc_mark((VALUE)obj->as.node.u1.node, lev); ++ gc_mark((VALUE)obj->as.node.u1.node); + /* fall through */ + case NODE_METHOD: /* 2 */ + case NODE_NOT: +@@ -873,7 +975,7 @@ gc_mark_children(ptr, lev) + case NODE_SCOPE: /* 2,3 */ + case NODE_BLOCK_PASS: + case NODE_CDECL: +- gc_mark((VALUE)obj->as.node.u3.node, lev); ++ gc_mark((VALUE)obj->as.node.u3.node); + ptr = (VALUE)obj->as.node.u2.node; + goto again; + +@@ -906,25 +1008,26 @@ gc_mark_children(ptr, lev) + + default: /* unlisted NODE */ + if (is_pointer_to_heap(obj->as.node.u1.node)) { +- gc_mark((VALUE)obj->as.node.u1.node, lev); ++ gc_mark((VALUE)obj->as.node.u1.node); + } + if (is_pointer_to_heap(obj->as.node.u2.node)) { +- gc_mark((VALUE)obj->as.node.u2.node, lev); ++ gc_mark((VALUE)obj->as.node.u2.node); + } + if (is_pointer_to_heap(obj->as.node.u3.node)) { +- gc_mark((VALUE)obj->as.node.u3.node, lev); ++ ptr = (VALUE)obj->as.node.u3.node; ++ goto again; + } + } +- return; /* no need to mark class. */ ++ return; /* no need to mark class. */ + } + +- gc_mark(obj->as.basic.klass, lev); ++ gc_mark(obj->as.basic.klass); + switch (obj->as.basic.flags & T_MASK) { + case T_ICLASS: + case T_CLASS: + case T_MODULE: +- mark_tbl(obj->as.klass.m_tbl, lev); +- mark_tbl(obj->as.klass.iv_tbl, lev); ++ mark_tbl(obj->as.klass.m_tbl); ++ mark_tbl(obj->as.klass.iv_tbl); + ptr = obj->as.klass.super; + goto again; + +@@ -934,17 +1037,16 @@ gc_mark_children(ptr, lev) + goto again; + } + else { +- long i, len = obj->as.array.len; + VALUE *ptr = obj->as.array.ptr; +- +- for (i=0; i < len; i++) { +- gc_mark(*ptr++, lev); ++ VALUE *pend = ptr + obj->as.array.len; ++ while (ptr < pend) { ++ gc_mark(*ptr++); + } + } + break; + + case T_HASH: +- mark_hash(obj->as.hash.tbl, lev); ++ mark_hash(obj->as.hash.tbl); + ptr = obj->as.hash.ifnone; + goto again; + +@@ -961,7 +1063,7 @@ gc_mark_children(ptr, lev) + break; + + case T_OBJECT: +- mark_tbl(obj->as.object.iv_tbl, lev); ++ mark_tbl(obj->as.object.iv_tbl); + break; + + case T_FILE: +@@ -979,7 +1081,7 @@ gc_mark_children(ptr, lev) + break; + + case T_VARMAP: +- gc_mark(obj->as.varmap.val, lev); ++ gc_mark(obj->as.varmap.val); + ptr = (VALUE)obj->as.varmap.next; + goto again; + +@@ -989,19 +1091,17 @@ gc_mark_children(ptr, lev) + VALUE *vars = &obj->as.scope.local_vars[-1]; + + while (n--) { +- gc_mark(*vars++, lev); ++ gc_mark(*vars++); + } + } + break; + + case T_STRUCT: + { +- long len = obj->as.rstruct.len; + VALUE *ptr = obj->as.rstruct.ptr; +- +- while (len--) { +- gc_mark(*ptr++, lev); +- } ++ VALUE *pend = ptr + obj->as.rstruct.len; ++ while (ptr < pend) ++ gc_mark(*ptr++); + } + break; + +@@ -1057,13 +1157,12 @@ gc_sweep() + RVALUE *p, *pend, *final_list; + int freed = 0; + int i; +- unsigned long live = 0; +- unsigned long free_min = 0; ++ long free_min = 0; + + for (i = 0; i < heaps_used; i++) { + free_min += heaps[i].limit; + } +- free_min = free_min * 0.2; ++ free_min /= 5; + if (free_min < FREE_MIN) + free_min = FREE_MIN; + +@@ -1074,7 +1173,7 @@ gc_sweep() + p = heaps[i].slot; pend = p + heaps[i].limit; + while (p < pend) { + if (!(p->as.basic.flags&FL_MARK) && BUILTIN_TYPE(p) == T_NODE) +- gc_mark((VALUE)p, 0); ++ gc_mark((VALUE)p); + p++; + } + } +@@ -1117,7 +1216,6 @@ gc_sweep() + } + else { + RBASIC(p)->flags &= ~FL_MARK; +- live++; + } + p++; + } +@@ -1134,10 +1232,6 @@ gc_sweep() + freed += n; + } + } +- if (malloc_increase > malloc_limit) { +- malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed); +- if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT; +- } + malloc_increase = 0; + if (freed < free_min) { + add_heap(); +@@ -1291,7 +1385,7 @@ void + rb_gc_mark_frame(frame) + struct FRAME *frame; + { +- gc_mark((VALUE)frame->node, 0); ++ gc_mark((VALUE)frame->node); + } + + #ifdef __GNUC__ +@@ -1332,12 +1426,13 @@ int rb_setjmp (rb_jmp_buf); + #endif /* __human68k__ or DJGPP */ + #endif /* __GNUC__ */ + ++ ++ + static void +-garbage_collect() ++garbage_collect_0(VALUE *top_frame) + { + struct gc_list *list; +- struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */ +- jmp_buf save_regs_gc_mark; ++ struct FRAME * frame; + SET_STACK_END; + + #ifdef HAVE_NATIVETHREAD +@@ -1354,9 +1449,10 @@ garbage_collect() + if (during_gc) return; + during_gc++; + ++ gc_stack_limit = __stack_grow(STACK_END, GC_LEVEL_MAX); + init_mark_stack(); + +- gc_mark((VALUE)ruby_current_node, 0); ++ gc_mark((VALUE)ruby_current_node); + + /* mark frame stack */ + for (frame = ruby_frame; frame; frame = frame->prev) { +@@ -1369,25 +1465,21 @@ garbage_collect() + } + } + } +- gc_mark((VALUE)ruby_scope, 0); +- gc_mark((VALUE)ruby_dyna_vars, 0); ++ gc_mark((VALUE)ruby_scope); ++ gc_mark((VALUE)ruby_dyna_vars); + if (finalizer_table) { +- mark_tbl(finalizer_table, 0); ++ mark_tbl(finalizer_table); + } + +- FLUSH_REGISTER_WINDOWS; +- /* This assumes that all registers are saved into the jmp_buf (and stack) */ +- setjmp(save_regs_gc_mark); +- mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *)); + #if STACK_GROW_DIRECTION < 0 +- rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start); ++ rb_gc_mark_locations(top_frame, rb_curr_thread->stk_start); + #elif STACK_GROW_DIRECTION > 0 +- rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1); ++ rb_gc_mark_locations(rb_curr_thread->stk_start, top_frame + 1); + #else +- if ((VALUE*)STACK_END < rb_gc_stack_start) +- rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start); ++ if (rb_gc_stack_grow_direction < 0) ++ rb_gc_mark_locations(top_frame, rb_curr_thread->stk_start); + else +- rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1); ++ rb_gc_mark_locations(rb_curr_thread->stk_start, top_frame + 1); + #endif + #ifdef __ia64 + /* mark backing store (flushed register window on the stack) */ +@@ -1396,7 +1488,7 @@ garbage_collect() + #endif + #if defined(__human68k__) || defined(__mc68000__) + rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2), +- (VALUE*)((char*)rb_gc_stack_start + 2)); ++ (VALUE*)((char*)rb_curr_thread->stk_start + 2)); + #endif + rb_gc_mark_threads(); + +@@ -1427,10 +1519,39 @@ garbage_collect() + } + rb_gc_abort_threads(); + } while (!MARK_STACK_EMPTY); +- + gc_sweep(); + } + ++static void ++garbage_collect() ++{ ++ jmp_buf save_regs_gc_mark; ++ VALUE *top = __sp(); ++ FLUSH_REGISTER_WINDOWS; ++ /* This assumes that all registers are saved into the jmp_buf (and stack) */ ++ setjmp(save_regs_gc_mark); ++ ++#if STACK_WIPE_SITES & 0x400 ++# ifdef nativeAllocA ++ if (__stack_past (top, stack_limit)) { ++ /* allocate a large frame to ensure app stack cannot grow into GC stack */ ++ (volatile void*) nativeAllocA(__stack_depth((void*)stack_limit,(void*)top)); ++ } ++ garbage_collect_0(top); ++# else /* no native alloca() available */ ++ garbage_collect_0(top); ++ { ++ VALUE *paddedLimit = __stack_grow(gc_stack_limit, GC_STACK_PAD); ++ if (__stack_past(rb_gc_stack_end, paddedLimit)) ++ rb_gc_stack_end = paddedLimit; ++ } ++ rb_gc_wipe_stack(); /* wipe the whole stack area reserved for this gc */ ++# endif ++#else ++ garbage_collect_0(top); ++#endif ++} ++ + void + rb_gc() + { +@@ -1455,6 +1576,7 @@ rb_gc_start() + return Qnil; + } + ++ + void + ruby_set_stack_size(size) + size_t size; +@@ -1462,6 +1584,29 @@ ruby_set_stack_size(size) + #ifndef STACK_LEVEL_MAX + STACK_LEVEL_MAX = size / sizeof(VALUE); + #endif ++ stack_limit = __stack_grow(rb_gc_stack_start, STACK_LEVEL_MAX-GC_STACK_MAX); ++} ++ ++static void ++set_stack_size(void) ++{ ++#ifdef HAVE_GETRLIMIT ++ struct rlimit rlim; ++ if (getrlimit(RLIMIT_STACK, &rlim) == 0) { ++ if (rlim.rlim_cur > 0 && rlim.rlim_cur != RLIM_INFINITY) { ++ size_t maxStackBytes = rlim.rlim_cur; ++ if (rlim.rlim_cur != maxStackBytes) ++ maxStackBytes = -1; ++ { ++ size_t space = maxStackBytes/5; ++ if (space > 1024*1024) space = 1024*1024; ++ ruby_set_stack_size(maxStackBytes - space); ++ return; ++ } ++ } ++ } ++#endif ++ ruby_set_stack_size(STACK_LEVEL_MAX*sizeof(VALUE)); + } + + void +@@ -1495,7 +1640,7 @@ Init_stack(addr) + memset(&m, 0, sizeof(m)); + VirtualQuery(&m, &m, sizeof(m)); + rb_gc_stack_start = +- STACK_UPPER((VALUE *)&m, (VALUE *)m.BaseAddress, ++ STACK_UPPER((VALUE *)m.BaseAddress, + (VALUE *)((char *)m.BaseAddress + m.RegionSize) - 1); + #elif defined(STACK_END_ADDRESS) + { +@@ -1504,28 +1649,16 @@ Init_stack(addr) + } + #else + if (!addr) addr = (void *)&addr; +- STACK_UPPER(&addr, addr, ++addr); ++ STACK_UPPER(addr, ++addr); + if (rb_gc_stack_start) { +- if (STACK_UPPER(&addr, +- rb_gc_stack_start > addr, ++ if (STACK_UPPER(rb_gc_stack_start > addr, + rb_gc_stack_start < addr)) + rb_gc_stack_start = addr; + return; + } + rb_gc_stack_start = addr; + #endif +-#ifdef HAVE_GETRLIMIT +- { +- struct rlimit rlim; +- +- if (getrlimit(RLIMIT_STACK, &rlim) == 0) { +- unsigned int space = rlim.rlim_cur/5; +- +- if (space > 1024*1024) space = 1024*1024; +- STACK_LEVEL_MAX = (rlim.rlim_cur - space) / sizeof(VALUE); +- } +- } +-#endif ++ set_stack_size(); + } + + void ruby_init_stack(VALUE *addr +@@ -1535,8 +1668,7 @@ void ruby_init_stack(VALUE *addr + ) + { + if (!rb_gc_stack_start || +- STACK_UPPER(&addr, +- rb_gc_stack_start > addr, ++ STACK_UPPER(rb_gc_stack_start > addr, + rb_gc_stack_start < addr)) { + rb_gc_stack_start = addr; + } +@@ -1547,16 +1679,7 @@ void ruby_init_stack(VALUE *addr + } + #endif + #ifdef HAVE_GETRLIMIT +- { +- struct rlimit rlim; +- +- if (getrlimit(RLIMIT_STACK, &rlim) == 0) { +- unsigned int space = rlim.rlim_cur/5; +- +- if (space > 1024*1024) space = 1024*1024; +- STACK_LEVEL_MAX = (rlim.rlim_cur - space) / sizeof(VALUE); +- } +- } ++ set_stack_size(); + #elif defined _WIN32 + { + MEMORY_BASIC_INFORMATION mi; +@@ -1567,7 +1690,7 @@ void ruby_init_stack(VALUE *addr + size = (char *)mi.BaseAddress - (char *)mi.AllocationBase; + space = size / 5; + if (space > 1024*1024) space = 1024*1024; +- STACK_LEVEL_MAX = (size - space) / sizeof(VALUE); ++ ruby_set_stack_size(size - space); + } + } + #endif +@@ -2042,10 +2165,22 @@ Init_GC() + { + VALUE rb_mObSpace; + ++#if !STACK_GROW_DIRECTION ++ rb_gc_stack_end = stack_grow_direction(&rb_mObSpace); ++#endif + rb_mGC = rb_define_module("GC"); + rb_define_singleton_method(rb_mGC, "start", rb_gc_start, 0); + rb_define_singleton_method(rb_mGC, "enable", rb_gc_enable, 0); + rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0); ++#ifdef MBARI_API ++ rb_define_singleton_method(rb_mGC, "limit", gc_getlimit, 0); ++ rb_define_singleton_method(rb_mGC, "limit=", gc_setlimit, 1); ++ rb_define_singleton_method(rb_mGC, "growth", gc_growth, 0); ++ rb_define_singleton_method(rb_mGC, "exorcise", gc_exorcise, 0); ++#else ++ rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0); ++ rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1); ++#endif + rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0); + + rb_mObSpace = rb_define_module("ObjectSpace"); +diff --git a/intern.h b/intern.h +index b251a83..70a7656 100644 +--- a/intern.h ++++ b/intern.h +@@ -238,7 +238,7 @@ VALUE rb_file_directory_p _((VALUE,VALUE)); + /* gc.c */ + NORETURN(void rb_memerror __((void))); + int ruby_stack_check _((void)); +-int ruby_stack_length _((VALUE**)); ++size_t ruby_stack_length _((VALUE *,VALUE**)); + int rb_during_gc _((void)); + char *rb_source_filename _((const char*)); + void rb_gc_mark_locations _((VALUE*, VALUE*)); +diff --git a/missing/alloca.c b/missing/alloca.c +index 39697f1..3facdfe 100644 +--- a/missing/alloca.c ++++ b/missing/alloca.c +@@ -29,6 +29,7 @@ + static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ + #endif + ++#include + #include "config.h" + #ifdef emacs + #ifdef static +@@ -44,11 +45,7 @@ lose + #endif /* static */ + #endif /* emacs */ + +-#ifdef X3J11 + typedef void *pointer; /* generic pointer type */ +-#else +-typedef char *pointer; /* generic pointer type */ +-#endif /* X3J11 */ + + #define NULL 0 /* null pointer constant */ + +@@ -140,8 +137,7 @@ typedef union hdr + static header *last_alloca_header = NULL; /* -> last alloca header */ + + pointer +-alloca (size) /* returns pointer to storage */ +- unsigned size; /* # bytes to allocate */ ++alloca (size_t size) /* returns pointer to storage */ + { + auto char probe; /* probes stack depth: */ + register char *depth = &probe; +diff --git a/node.h b/node.h +index 7d3f756..4a1db92 100644 +--- a/node.h ++++ b/node.h +@@ -409,15 +409,11 @@ struct rb_thread { + + VALUE result; + +- long stk_len; +- long stk_max; +- VALUE *stk_ptr; +- VALUE *stk_pos; ++ size_t stk_len, stk_max; ++ VALUE *stk_ptr, *stk_pos, *stk_start; + #ifdef __ia64 +- long bstr_len; +- long bstr_max; +- VALUE *bstr_ptr; +- VALUE *bstr_pos; ++ size_t bstr_len, bstr_max; ++ VALUE *bstr_ptr, *bstr_pos; + #endif + + struct FRAME *frame; +diff --git a/re.c b/re.c +index 5553d28..129b621 100644 +--- a/re.c ++++ b/re.c +@@ -1419,7 +1419,7 @@ VALUE + rb_reg_regcomp(str) + VALUE str; + { +- volatile VALUE save_str = str; ++ VALUE save_str = str; + if (reg_cache && RREGEXP(reg_cache)->len == RSTRING(str)->len + && case_cache == ruby_ignorecase + && kcode_cache == reg_kcode +@@ -1428,8 +1428,9 @@ rb_reg_regcomp(str) + + case_cache = ruby_ignorecase; + kcode_cache = reg_kcode; +- return reg_cache = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, +- ruby_ignorecase); ++ reg_cache = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, ruby_ignorecase); ++ RB_GC_GUARD(save_str); ++ return reg_cache; + } + + static int +diff --git a/ruby.h b/ruby.h +index 2701f0d..3cf4e19 100644 +--- a/ruby.h ++++ b/ruby.h +@@ -224,6 +224,8 @@ VALUE rb_ull2inum _((unsigned LONG_LONG)); + + #define TYPE(x) rb_type((VALUE)(x)) + ++#define RB_GC_GUARD(v) (*(volatile VALUE *)&(v)) ++ + void rb_check_type _((VALUE,int)); + #define Check_Type(v,t) rb_check_type((VALUE)(v),t) + +diff --git a/rubysig.h b/rubysig.h +index f716824..fae0869 100644 +--- a/rubysig.h ++++ b/rubysig.h +@@ -12,8 +12,80 @@ + + #ifndef SIG_H + #define SIG_H ++ + #include + ++#if defined __ppc__ || defined __powerpc__ || \ ++ defined __ppc64__ || defined __powerpc64__ ++#define __anyPowerPC__ 1 /* for compatibility with older gcc versions */ ++#endif ++ ++/* STACK_WIPE_SITES determines where attempts are made to exorcise ++ "ghost object refereces" from the stack and how the stack is cleared: ++ ++ 0x*001 --> wipe stack just after every thread_switch ++ 0x*002 --> wipe stack just after every EXEC_TAG() ++ 0x*004 --> wipe stack in CHECK_INTS ++ 0x*010 --> wipe stack in while & until loops ++ 0x*020 --> wipe stack before yield() in iterators and outside eval.c ++ 0x*040 --> wipe stack on catch and thread save context ++ 0x*100 --> update stack extent on each object allocation ++ 0x*200 --> update stack extent on each object reallocation ++ 0x*400 --> update stack extent during GC marking passes ++ 0x*800 --> update stack extent on each throw (use with 0x040) ++ 0x1000 --> use inline assembly code for x86, PowerPC, or ARM CPUs ++ ++ 0x0*** --> do not even call rb_wipe_stack() ++ 0x2*** --> call dummy rb_wipe_stack() (for debugging and profiling) ++ 0x4*** --> safe, portable stack clearing in memory allocated with alloca ++ 0x6*** --> use faster, but less safe stack clearing in unallocated stack ++ 0x8*** --> use faster, but less safe stack clearing (with inline code) ++ ++ for most effective gc use 0x*707 ++ for fastest micro-benchmarking use 0x0000 ++ 0x*770 prevents almost all memory leaks caused by ghost references ++ without adding much overhead for stack clearing. ++ Other good trade offs are 0x*270, 0x*703, 0x*303 or even 0x*03 ++ ++ In general, you may lessen the default -mpreferred-stack-boundary ++ only if using less safe stack clearing (0x6***). Lessening the ++ stack alignment with portable stack clearing (0x4***) may fail to clear ++ all ghost references off the stack. ++ ++ When using 0x6*** or 0x8***, the compiler could insert ++ stack push(s) between reading the stack pointer and clearing ++ the ghost references. The register(s) pushed will be ++ cleared by the rb_gc_stack_wipe(), typically resulting in a segfault ++ or an interpreter hang. ++ ++ STACK_WIPE_SITES of 0x8770 works well compiled with gcc on most machines ++ using the recommended CFLAGS="-O2 -fno-stack-protector". However... ++ If it hangs or crashes for you, try changing STACK_WIPE_SITES to 0x4770 ++ and please report your details. i.e. CFLAGS, compiler, version, CPU ++ ++ Note that it is redundant to wipe_stack in looping constructs if ++ also doing so in CHECK_INTS. It is also redundant to wipe_stack on ++ each thread_switch if wiping after every thread save context. ++*/ ++#ifndef STACK_WIPE_SITES ++# ifdef __x86_64__ /* deal with "red zone" by not inlining stack clearing */ ++# define STACK_WIPE_SITES 0x6770 ++# elif defined __anyPowerPC__ /* On any PowerPC, deal with... */ ++# define STACK_WIPE_SITES 0x7764 /* red zone & alloc(0) doesn't return sp */ ++# else ++# define STACK_WIPE_SITES 0x8770 /*normal case, use 0x4770 if problems arise*/ ++# endif ++#endif ++ ++#if (STACK_WIPE_SITES & 0x14) == 0x14 ++#warning wiping stack in CHECK_INTS makes wiping in loops redundant ++#endif ++#if (STACK_WIPE_SITES & 0x41) == 0x41 ++#warning wiping stack after thread save makes wiping on thread_switch redundant ++#endif ++ ++#define STACK_WIPE_METHOD (STACK_WIPE_SITES>>13) ++ + #ifdef _WIN32 + typedef LONG rb_atomic_t; + +@@ -79,9 +151,152 @@ void rb_trap_restore_mask _((void)); + + RUBY_EXTERN int rb_thread_critical; + void rb_thread_schedule _((void)); ++ ++RUBY_EXTERN VALUE *rb_gc_stack_end; ++RUBY_EXTERN int rb_gc_stack_grow_direction; /* -1 for down or 1 for up */ ++ ++#if STACK_GROW_DIRECTION > 0 ++ ++/* clear stack space between end and sp (not including *sp) */ ++#define __stack_zero(end,sp) __stack_zero_up(end,sp) ++ ++/* true if top has grown past limit, i.e. top deeper than limit */ ++#define __stack_past(limit,top) __stack_past_up(limit,top) ++ ++/* depth of mid below stack top */ ++#define __stack_depth(top,mid) __stack_depth_up(top,mid) ++ ++/* stack pointer top adjusted to include depth more items */ ++#define __stack_grow(top,depth) __stack_grow_up(top,depth) ++ ++ ++#elif STACK_GROW_DIRECTION < 0 ++#define __stack_zero(end,sp) __stack_zero_down(end,sp) ++#define __stack_past(limit,top) __stack_past_down(limit,top) ++#define __stack_depth(top,mid) __stack_depth_down(top,mid) ++#define __stack_grow(top,depth) __stack_grow_down(top,depth) ++ ++#else /* limp along if stack direction can't be determined at compile time */ ++#define __stack_zero(end,sp) if (rb_gc_stack_grow_direction<0) \ ++ __stack_zero_down(end,sp); else __stack_zero_up(end,sp); ++#define __stack_past(limit,top) (rb_gc_stack_grow_direction<0 ? \ ++ __stack_past_down(limit,top) : __stack_past_up(limit,top)) ++#define __stack_depth(top,mid) (rb_gc_stack_grow_direction<0 ? \ ++ __stack_depth_down(top,mid) : __stack_depth_up(top,mid)) ++#define __stack_grow(top,depth) (rb_gc_stack_grow_direction<0 ? \ ++ __stack_grow_down(top,depth) : __stack_grow_up(top,depth)) ++#endif ++ ++#define __stack_zero_up(end,sp) while (end >= ++sp) *sp=0 ++#define __stack_past_up(limit,top) ((limit) < (top)) ++#define __stack_depth_up(top,mid) ((top) - (mid)) ++#define __stack_grow_up(top,depth) ((top)+(depth)) ++ ++#define __stack_zero_down(end,sp) while (end <= --sp) *sp=0 ++#define __stack_past_down(limit,top) ((limit) > (top)) ++#define __stack_depth_down(top,mid) ((mid) - (top)) ++#define __stack_grow_down(top,depth) ((top)-(depth)) ++ ++/* Make alloca work the best possible way. */ ++#ifdef __GNUC__ ++# ifndef atarist ++# ifndef alloca ++# define alloca __builtin_alloca ++# endif ++# endif /* atarist */ ++ ++# define nativeAllocA __builtin_alloca ++ ++/* use assembly to get stack pointer quickly */ ++# if STACK_WIPE_SITES & 0x1000 ++# define __defspfn(asmb) \ ++static inline VALUE *__sp(void) __attribute__((always_inline)); \ ++static inline VALUE *__sp(void) \ ++{ \ ++ VALUE *sp; asm(asmb); \ ++ return sp; \ ++} ++# ifdef __anyPowerPC__ ++__defspfn("addi %0, r1, 0": "=r"(sp)) ++# elif defined __i386__ ++__defspfn("movl %%esp, %0": "=r"(sp)) ++# elif defined __x86_64__ ++#warn ===> x86_64 inline assembler is known to crash -- change STACK_WIPE_SITES ++__defspfn("movq %%rsp, %0": "=r"(sp)) ++# elif __arm__ ++__defspfn("mov %0, sp": "=r"(sp)) ++# else ++# define __sp() ((VALUE *)__builtin_alloca(0)) ++# warning No assembly version of __sp() defined for this CPU. ++# endif ++# else ++# define __sp() ((VALUE *)__builtin_alloca(0)) ++# endif ++ ++#else // not GNUC ++ ++# ifdef HAVE_ALLOCA_H ++# include ++# else ++# ifndef _AIX ++# ifndef alloca /* predefined by HP cc +Olibcalls */ ++void *alloca (); ++# endif ++# endif /* AIX */ ++# endif /* HAVE_ALLOCA_H */ ++ ++# if STACK_WIPE_SITES & 0x1000 ++# warning No assembly versions of __sp() defined for this compiler. ++# endif ++# if HAVE_ALLOCA ++# define __sp() ((VALUE *)alloca(0)) ++# define nativeAllocA alloca ++# else ++RUBY_EXTERN VALUE *__sp(void); ++# if STACK_WIPE_SITES ++# define STACK_WIPE_SITES 0 ++# warning Disabled Stack Wiping because there is no native alloca() ++# endif ++# endif ++#endif /* __GNUC__ */ ++ ++ ++/* ++ Zero memory that was (recently) part of the stack, but is no longer. ++ Invoke when stack is deep to mark its extent and when it's shallow to wipe it. ++*/ ++#if STACK_WIPE_METHOD == 0 ++#define rb_gc_wipe_stack() ((void)0) ++#elif STACK_WIPE_METHOD == 4 ++#define rb_gc_wipe_stack() { \ ++ VALUE *end = rb_gc_stack_end; \ ++ VALUE *sp = __sp(); \ ++ rb_gc_stack_end = sp; \ ++ __stack_zero(end, sp); \ ++} ++#else ++RUBY_EXTERN void rb_gc_wipe_stack(void); ++#endif ++ ++/* ++ Update our record of maximum stack extent without zeroing unused stack ++*/ ++#define rb_gc_update_stack_extent() do { \ ++ VALUE *sp = __sp(); \ ++ if __stack_past(rb_gc_stack_end, sp) rb_gc_stack_end = sp; \ ++} while(0) ++ ++ ++#if STACK_WIPE_SITES & 4 ++# define CHECK_INTS_wipe_stack() rb_gc_wipe_stack() ++#else ++# define CHECK_INTS_wipe_stack() (void)0 ++#endif ++ + #if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE) + RUBY_EXTERN int rb_thread_pending; + # define CHECK_INTS do {\ ++ CHECK_INTS_wipe_stack(); \ + if (!(rb_prohibit_interrupt || rb_thread_critical)) {\ + if (rb_thread_pending) rb_thread_schedule();\ + if (rb_trap_pending) rb_trap_exec();\ +@@ -92,13 +307,14 @@ RUBY_EXTERN int rb_thread_pending; + RUBY_EXTERN int rb_thread_tick; + #define THREAD_TICK 500 + #define CHECK_INTS do {\ ++ CHECK_INTS_wipe_stack(); \ + if (!(rb_prohibit_interrupt || rb_thread_critical)) {\ + if (rb_thread_tick-- <= 0) {\ + rb_thread_tick = THREAD_TICK;\ + rb_thread_schedule();\ + }\ ++ if (rb_trap_pending) rb_trap_exec();\ + }\ +- if (rb_trap_pending) rb_trap_exec();\ + } while (0) + #endif + +diff --git a/signal.c b/signal.c +index b6cad9d..bc9deae 100644 +--- a/signal.c ++++ b/signal.c +@@ -389,6 +389,7 @@ rb_f_kill(argc, argv) + rb_sys_fail(0); + } + } ++ CHECK_INTS; /* in case we killed ourselves */ + return INT2FIX(i-1); + } + +diff --git a/test/ruby/suicide.rb b/test/ruby/suicide.rb +index 2687ed0..c7a0a67 100644 +--- a/test/ruby/suicide.rb ++++ b/test/ruby/suicide.rb +@@ -1,2 +1,4 @@ + STDERR.reopen(STDOUT) +-at_exit{Process.kill(:INT, $$)} ++at_exit{Process.kill(:INT, $$); sleep 0} ++# brent@mbari.org says ++# sleep 0 avoids race between process termination and signal reception +diff --git a/version.c b/version.c +index b235673..dbc65b0 100644 +--- a/version.c ++++ b/version.c +@@ -14,23 +14,44 @@ + #include "version.h" + #include + ++#define PRINT(type) puts(ruby_##type) ++#define MKSTR(type) rb_obj_freeze(rb_str_new(ruby_##type, sizeof(ruby_##type)-1)) ++ + const char ruby_version[] = RUBY_VERSION; + const char ruby_release_date[] = RUBY_RELEASE_DATE; + const char ruby_platform[] = RUBY_PLATFORM; + const int ruby_patchlevel = RUBY_PATCHLEVEL; ++const char *ruby_description; ++const char *ruby_copyright; + + void + Init_version() + { +- VALUE v = rb_obj_freeze(rb_str_new2(ruby_version)); +- VALUE d = rb_obj_freeze(rb_str_new2(ruby_release_date)); +- VALUE p = rb_obj_freeze(rb_str_new2(ruby_platform)); ++ static char description[128]; ++ static char copyright[128]; ++ VALUE v = MKSTR(version); ++ VALUE d = MKSTR(release_date); ++ VALUE p = MKSTR(platform); ++ VALUE tmp; + + rb_define_global_const("RUBY_VERSION", v); + rb_define_global_const("RUBY_RELEASE_DATE", d); + rb_define_global_const("RUBY_PLATFORM", p); + rb_define_global_const("RUBY_PATCHLEVEL", INT2FIX(RUBY_PATCHLEVEL)); + ++ snprintf(description, sizeof(description), "ruby %s (%s %s %d) [%s]", ++ RUBY_VERSION, RUBY_RELEASE_DATE, RUBY_RELEASE_STR, ++ RUBY_RELEASE_NUM, RUBY_PLATFORM); ++ ruby_description = description; ++ tmp = rb_obj_freeze(rb_str_new2(description)); ++ rb_define_global_const("RUBY_DESCRIPTION", tmp); ++ ++ snprintf(copyright, sizeof(copyright), "ruby - Copyright (C) %d-%d %s", ++ RUBY_BIRTH_YEAR, RUBY_RELEASE_YEAR, RUBY_AUTHOR); ++ ruby_copyright = copyright; ++ tmp = rb_obj_freeze(rb_str_new2(copyright)); ++ rb_define_global_const("RUBY_COPYRIGHT", tmp); ++ + /* obsolete constants */ + rb_define_global_const("VERSION", v); + rb_define_global_const("RELEASE_DATE", d); +@@ -40,13 +61,13 @@ Init_version() + void + ruby_show_version() + { +- printf("ruby %s (%s patchlevel %d) [%s]\n", RUBY_VERSION, RUBY_RELEASE_DATE, RUBY_PATCHLEVEL, RUBY_PLATFORM); ++ PRINT(description); + fflush(stdout); + } + + void + ruby_show_copyright() + { +- printf("ruby - Copyright (C) 1993-%d Yukihiro Matsumoto\n", RUBY_RELEASE_YEAR); ++ PRINT(copyright); + exit(0); + } +diff --git a/version.h b/version.h +index 88ddd67..fa36fa5 100644 +--- a/version.h ++++ b/version.h +@@ -1,21 +1,43 @@ + #define RUBY_VERSION "1.8.6" +-#define RUBY_RELEASE_DATE "2008-08-11" ++#define RUBY_RELEASE_DATE "2009-3-1" + #define RUBY_VERSION_CODE 186 +-#define RUBY_RELEASE_CODE 20080811 ++#define RUBY_RELEASE_CODE 20090301 + #define RUBY_PATCHLEVEL 287 + + #define RUBY_VERSION_MAJOR 1 + #define RUBY_VERSION_MINOR 8 + #define RUBY_VERSION_TEENY 6 +-#define RUBY_RELEASE_YEAR 2008 +-#define RUBY_RELEASE_MONTH 8 +-#define RUBY_RELEASE_DAY 11 ++#define RUBY_RELEASE_YEAR 2009 ++#define RUBY_RELEASE_MONTH 3 ++#define RUBY_RELEASE_DAY 1 + + #ifdef RUBY_EXTERN + RUBY_EXTERN const char ruby_version[]; + RUBY_EXTERN const char ruby_release_date[]; + RUBY_EXTERN const char ruby_platform[]; + RUBY_EXTERN const int ruby_patchlevel; ++RUBY_EXTERN const char *ruby_description; ++RUBY_EXTERN const char *ruby_copyright; + #endif + ++#define RUBY_AUTHOR "Yukihiro Matsumoto" ++#define RUBY_BIRTH_YEAR 1993 ++#define RUBY_BIRTH_MONTH 2 ++#define RUBY_BIRTH_DAY 24 ++ ++#include "rubysig.h" ++ ++#define string_arg(s) #s ++ ++#ifdef MBARI_API ++#define _mbari_rev_ "MBARI" ++#else ++#define _mbari_rev_ "mbari" ++#endif ++ ++#define MBARI_RELEASE(wipe_sites) _mbari_rev_ " 8B/" string_arg(wipe_sites) ++ ++#define RUBY_RELEASE_STR MBARI_RELEASE(STACK_WIPE_SITES) " on patchlevel" ++#define RUBY_RELEASE_NUM RUBY_PATCHLEVEL ++ + +--- ruby-1.8.6-p287/configure 2008-08-10 17:38:35.000000000 -0700 ++++ ruby-1.8.6-mbari/configure 2009-02-26 22:43:03.000000000 -0800 +@@ -1352,6 +1352,7 @@ + is disabled or omitted entirely, then the package + will be built only for the target platform + --enable-frame-address use GCC __builtin_frame_address(). ++ --enable-mbari-api enable API changes from the MBARI patches. + --disable-largefile omit support for large files + --enable-pthread use pthread library. + --disable-fastthread do not use the fastthread mutex +@@ -1364,6 +1365,7 @@ + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --without-gcc never use gcc ++ --with-wipe-sites=MASK override default STACK_WIPES_SITES mask in rubysig.h + --with-winsock2 link winsock2 (MinGW only) + --with-libc_r link libc_r if possible (FreeBSD only) + --with-default-kcode=CODE specify default value for \$KCODE (utf8|euc|sjis|none) +@@ -2080,6 +2082,35 @@ + _ACEOF + + fi ++# Check whether --enable-mbari-api was given. ++if test "${enable_mbari_api+set}" = set; then ++ enableval=$enable_mbari_api; mbari_api=$enableval ++fi ++ ++if test "$mbari_api" = yes; then ++ cat >>confdefs.h <<\_ACEOF ++#define MBARI_API 1 ++_ACEOF ++ ++fi ++ ++# Check whether --with-wipe-sites was given. ++if test "${with_wipe_sites+set}" = set; then ++ withval=$with_wipe_sites; wipe_sites=$withval ++fi ++ ++if test "$wipe_sites" != ""; then ++ case $wipe_sites in ++ none|no) wipe_sites=0x0;; ++ yes) wipe_sites=;; ++ esac ++ if test -n "$wipe_sites"; then ++ cat >>confdefs.h <<_ACEOF ++#define STACK_WIPE_SITES $wipe_sites ++_ACEOF ++ ++ fi ++fi + + test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" diff --git a/patches/ruby/1.8.6/railsbench.patch b/patches/ruby/1.8.6/railsbench.patch new file mode 100644 index 0000000000..f904cf0ccb --- /dev/null +++ b/patches/ruby/1.8.6/railsbench.patch @@ -0,0 +1,564 @@ +Index: gc.c +=================================================================== +--- gc.c (revision 12920) ++++ gc.c (working copy) +@@ -22,8 +22,16 @@ + #include + #include + ++#ifdef _WIN32 ++#include ++#else ++#include ++#endif ++ + #ifdef HAVE_SYS_TIME_H + #include ++#elif defined(_WIN32) ++#include + #endif + + #ifdef HAVE_SYS_RESOURCE_H +@@ -40,7 +48,6 @@ + #if !defined(setjmp) && defined(HAVE__SETJMP) + #define setjmp(env) _setjmp(env) + #endif +- + /* Make alloca work the best possible way. */ + #ifdef __GNUC__ + # ifndef atarist +@@ -159,8 +166,17 @@ + RUBY_CRITICAL(free(x)); + } + ++#if HAVE_LONG_LONG ++#define GC_TIME_TYPE LONG_LONG ++#else ++#define GC_TIME_TYPE long ++#endif ++ + extern int ruby_in_compile; + static int dont_gc; ++static int gc_statistics = 0; ++static GC_TIME_TYPE gc_time = 0; ++static int gc_collections = 0; + static int during_gc; + static int need_call_final = 0; + static st_table *finalizer_table = 0; +@@ -195,7 +211,7 @@ + * Disables garbage collection, returning true if garbage + * collection was already disabled. + * +- * GC.disable #=> false ++ * GC.disable #=> false or true + * GC.disable #=> true + * + */ +@@ -209,6 +225,104 @@ + return old; + } + ++/* ++ * call-seq: ++ * GC.enable_stats => true or false ++ * ++ * Enables garbage collection statistics, returning true if garbage ++ * collection statistics was already enabled. ++ * ++ * GC.enable_stats #=> false or true ++ * GC.enable_stats #=> true ++ * ++ */ ++ ++VALUE ++rb_gc_enable_stats() ++{ ++ int old = gc_statistics; ++ gc_statistics = Qtrue; ++ return old; ++} ++ ++/* ++ * call-seq: ++ * GC.disable_stats => true or false ++ * ++ * Disables garbage collection statistics, returning true if garbage ++ * collection statistics was already disabled. ++ * ++ * GC.disable_stats #=> false or true ++ * GC.disable_stats #=> true ++ * ++ */ ++ ++VALUE ++rb_gc_disable_stats() ++{ ++ int old = gc_statistics; ++ gc_statistics = Qfalse; ++ return old; ++} ++ ++/* ++ * call-seq: ++ * GC.clear_stats => nil ++ * ++ * Clears garbage collection statistics, returning nil. This resets the number ++ * of collections (GC.collections) and the time used (GC.time) to 0. ++ * ++ * GC.clear_stats #=> nil ++ * ++ */ ++ ++VALUE ++rb_gc_clear_stats() ++{ ++ gc_collections = 0; ++ gc_time = 0; ++ return Qnil; ++} ++ ++/* ++ * call-seq: ++ * GC.collections => Integer ++ * ++ * Returns the number of garbage collections performed while GC statistics collection ++ * was enabled. ++ * ++ * GC.collections #=> 35 ++ * ++ */ ++ ++VALUE ++rb_gc_collections() ++{ ++ return INT2NUM(gc_collections); ++} ++ ++/* ++ * call-seq: ++ * GC.time => Integer ++ * ++ * Returns the time spent during garbage collection while GC statistics collection ++ * was enabled (in micro seconds). ++ * ++ * GC.time #=> 20000 ++ * ++ */ ++ ++VALUE ++rb_gc_time() ++{ ++#if HAVE_LONG_LONG ++ return LL2NUM(gc_time); ++#else ++ return LONG2NUM(gc_time); ++#endif ++} ++ ++ + VALUE rb_mGC; + + static struct gc_list { +@@ -300,7 +414,7 @@ + static RVALUE *freelist = 0; + static RVALUE *deferred_final_list = 0; + +-#define HEAPS_INCREMENT 10 ++static int heaps_increment = 10; + static struct heaps_slot { + void *membase; + RVALUE *slot; +@@ -309,13 +423,165 @@ + static int heaps_length = 0; + static int heaps_used = 0; + +-#define HEAP_MIN_SLOTS 10000 +-static int heap_slots = HEAP_MIN_SLOTS; ++static int heap_min_slots = 10000; ++static int heap_slots = 10000; ++ ++static int heap_free_min = 4096; ++static int heap_slots_increment = 10000; ++static double heap_slots_growth_factor = 1.8; ++ ++static long initial_malloc_limit = GC_MALLOC_LIMIT; ++ ++static int verbose_gc_stats = Qfalse; + +-#define FREE_MIN 4096 ++static FILE* gc_data_file = NULL; + + static RVALUE *himem, *lomem; + ++static void set_gc_parameters() ++{ ++ char *gc_stats_ptr, *min_slots_ptr, *free_min_ptr, *heap_slots_incr_ptr, ++ *heap_incr_ptr, *malloc_limit_ptr, *gc_heap_file_ptr, *heap_slots_growth_factor_ptr; ++ ++ gc_data_file = stderr; ++ ++ gc_stats_ptr = getenv("RUBY_GC_STATS"); ++ if (gc_stats_ptr != NULL) { ++ int gc_stats_i = atoi(gc_stats_ptr); ++ if (gc_stats_i > 0) { ++ verbose_gc_stats = Qtrue; ++ } ++ } ++ ++ gc_heap_file_ptr = getenv("RUBY_GC_DATA_FILE"); ++ if (gc_heap_file_ptr != NULL) { ++ FILE* data_file = fopen(gc_heap_file_ptr, "w"); ++ if (data_file != NULL) { ++ gc_data_file = data_file; ++ } ++ else { ++ fprintf(stderr, ++ "can't open gc log file %s for writing, using default\n", gc_heap_file_ptr); ++ } ++ } ++ ++ min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS"); ++ if (min_slots_ptr != NULL) { ++ int min_slots_i = atoi(min_slots_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_MIN_SLOTS=%s\n", min_slots_ptr); ++ } ++ if (min_slots_i > 0) { ++ heap_slots = min_slots_i; ++ heap_min_slots = min_slots_i; ++ } ++ } ++ ++ free_min_ptr = getenv("RUBY_HEAP_FREE_MIN"); ++ if (free_min_ptr != NULL) { ++ int free_min_i = atoi(free_min_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_FREE_MIN=%s\n", free_min_ptr); ++ } ++ if (free_min_i > 0) { ++ heap_free_min = free_min_i; ++ } ++ } ++ ++ heap_incr_ptr = getenv("RUBY_HEAP_INCREMENT"); ++ if (heap_incr_ptr != NULL) { ++ int heap_incr_i = atoi(heap_incr_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_INCREMENT=%s\n", heap_incr_ptr); ++ } ++ if (heap_incr_i > 0) { ++ heaps_increment = heap_incr_i; ++ } ++ } ++ ++ heap_slots_incr_ptr = getenv("RUBY_HEAP_SLOTS_INCREMENT"); ++ if (heap_slots_incr_ptr != NULL) { ++ int heap_slots_incr_i = atoi(heap_slots_incr_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_SLOTS_INCREMENT=%s\n", heap_slots_incr_ptr); ++ } ++ if (heap_slots_incr_i > 0) { ++ heap_slots_increment = heap_slots_incr_i; ++ } ++ } ++ ++ heap_slots_growth_factor_ptr = getenv("RUBY_HEAP_SLOTS_GROWTH_FACTOR"); ++ if (heap_slots_growth_factor_ptr != NULL) { ++ double heap_slots_growth_factor_d = atoi(heap_slots_growth_factor_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_SLOTS_GROWTH_FACTOR=%s\n", heap_slots_growth_factor_ptr); ++ } ++ if (heap_slots_growth_factor_d > 0) { ++ heap_slots_growth_factor = heap_slots_growth_factor_d; ++ } ++ } ++ ++ malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT"); ++ if (malloc_limit_ptr != NULL) { ++ int malloc_limit_i = atol(malloc_limit_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_GC_MALLOC_LIMIT=%s\n", malloc_limit_ptr); ++ } ++ if (malloc_limit_i > 0) { ++ initial_malloc_limit = malloc_limit_i; ++ } ++ } ++} ++ ++/* ++ * call-seq: ++ * GC.dump => nil ++ * ++ * dumps information about the current GC data structures to the GC log file ++ * ++ * GC.dump #=> nil ++ * ++ */ ++ ++VALUE ++rb_gc_dump() ++{ ++ int i; ++ ++ for (i = 0; i < heaps_used; i++) { ++ int heap_size = heaps[i].limit; ++ fprintf(gc_data_file, "HEAP[%2d]: size=%7d\n", i, heap_size); ++ } ++ ++ return Qnil; ++} ++ ++/* ++ * call-seq: ++ * GC.log String => String ++ * ++ * Logs string to the GC data file and returns it. ++ * ++ * GC.log "manual GC call" #=> "manual GC call" ++ * ++ */ ++ ++VALUE ++rb_gc_log(self, original_str) ++ VALUE self, original_str; ++{ ++ if (original_str == Qnil) { ++ fprintf(gc_data_file, "\n"); ++ } ++ else { ++ VALUE str = StringValue(original_str); ++ char *p = RSTRING(str)->ptr; ++ fprintf(gc_data_file, "%s\n", p); ++ } ++ return original_str; ++} ++ ++ + static void + add_heap() + { +@@ -326,7 +592,7 @@ + struct heaps_slot *p; + int length; + +- heaps_length += HEAPS_INCREMENT; ++ heaps_length += heaps_increment; + length = heaps_length*sizeof(struct heaps_slot); + RUBY_CRITICAL( + if (heaps_used > 0) { +@@ -342,10 +608,10 @@ + for (;;) { + RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1))); + if (p == 0) { +- if (heap_slots == HEAP_MIN_SLOTS) { ++ if (heap_slots == heap_min_slots) { + rb_memerror(); + } +- heap_slots = HEAP_MIN_SLOTS; ++ heap_slots = heap_min_slots; + continue; + } + heaps[heaps_used].membase = p; +@@ -361,8 +627,9 @@ + if (lomem == 0 || lomem > p) lomem = p; + if (himem < pend) himem = pend; + heaps_used++; +- heap_slots *= 1.8; +- if (heap_slots <= 0) heap_slots = HEAP_MIN_SLOTS; ++ heap_slots += heap_slots_increment; ++ heap_slots_increment *= heap_slots_growth_factor; ++ if (heap_slots <= 0) heap_slots = heap_min_slots; + + while (p < pend) { + p->as.free.flags = 0; +@@ -1015,6 +1282,39 @@ + } + } + ++static char* obj_type(int tp) ++{ ++ switch (tp) { ++ case T_NIL : return "NIL"; ++ case T_OBJECT : return "OBJECT"; ++ case T_CLASS : return "CLASS"; ++ case T_ICLASS : return "ICLASS"; ++ case T_MODULE : return "MODULE"; ++ case T_FLOAT : return "FLOAT"; ++ case T_STRING : return "STRING"; ++ case T_REGEXP : return "REGEXP"; ++ case T_ARRAY : return "ARRAY"; ++ case T_FIXNUM : return "FIXNUM"; ++ case T_HASH : return "HASH"; ++ case T_STRUCT : return "STRUCT"; ++ case T_BIGNUM : return "BIGNUM"; ++ case T_FILE : return "FILE"; ++ ++ case T_TRUE : return "TRUE"; ++ case T_FALSE : return "FALSE"; ++ case T_DATA : return "DATA"; ++ case T_MATCH : return "MATCH"; ++ case T_SYMBOL : return "SYMBOL"; ++ ++ case T_BLKTAG : return "BLKTAG"; ++ case T_UNDEF : return "UNDEF"; ++ case T_VARMAP : return "VARMAP"; ++ case T_SCOPE : return "SCOPE"; ++ case T_NODE : return "NODE"; ++ default: return "____"; ++ } ++} ++ + static void + free_unused_heaps() + { +@@ -1045,12 +1345,21 @@ + unsigned long live = 0; + unsigned long free_min = 0; + ++ unsigned long really_freed = 0; ++ int free_counts[256]; ++ int live_counts[256]; ++ int do_gc_stats = gc_statistics & verbose_gc_stats; ++ + for (i = 0; i < heaps_used; i++) { + free_min += heaps[i].limit; + } + free_min = free_min * 0.2; +- if (free_min < FREE_MIN) +- free_min = FREE_MIN; ++ if (free_min < heap_free_min) ++ free_min = heap_free_min; ++ ++ if (do_gc_stats) { ++ for (i = 0 ; i< 256; i++) { free_counts[i] = live_counts[i] = 0; } ++ } + + if (ruby_in_compile && ruby_parser_stack_on_heap()) { + /* should not reclaim nodes during compilation +@@ -1083,6 +1392,9 @@ + if (!(p->as.basic.flags & FL_MARK)) { + if (p->as.basic.flags) { + obj_free((VALUE)p); ++ if (do_gc_stats) { ++ really_freed++; ++ } + } + if (need_call_final && FL_TEST(p, FL_FINALIZE)) { + p->as.free.flags = FL_MARK; /* remain marked */ +@@ -1090,6 +1402,12 @@ + final_list = p; + } + else { ++ if (do_gc_stats) { ++ int obt = p->as.basic.flags & T_MASK; ++ if (obt) { ++ free_counts[obt]++; ++ } ++ } + p->as.free.flags = 0; + p->as.free.next = freelist; + freelist = p; +@@ -1103,6 +1421,9 @@ + else { + RBASIC(p)->flags &= ~FL_MARK; + live++; ++ if (do_gc_stats) { ++ live_counts[RANY((VALUE)p)->as.basic.flags & T_MASK]++; ++ } + } + p++; + } +@@ -1121,7 +1442,7 @@ + } + if (malloc_increase > malloc_limit) { + malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed); +- if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT; ++ if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit; + } + malloc_increase = 0; + if (freed < free_min) { +@@ -1129,6 +1450,20 @@ + } + during_gc = 0; + ++ if (do_gc_stats) { ++ fprintf(gc_data_file, "objects processed: %.7d\n", live+freed); ++ fprintf(gc_data_file, "live objects : %.7d\n", live); ++ fprintf(gc_data_file, "freelist objects : %.7d\n", freed - really_freed); ++ fprintf(gc_data_file, "freed objects : %.7d\n", really_freed); ++ for(i=0; i<256; i++) { ++ if (free_counts[i]>0) { ++ fprintf(gc_data_file, ++ "kept %.7d / freed %.7d objects of type %s\n", ++ live_counts[i], free_counts[i], obj_type(i)); ++ } ++ } ++ } ++ + /* clear finalization list */ + if (final_list) { + deferred_final_list = final_list; +@@ -1323,6 +1658,7 @@ + struct gc_list *list; + struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */ + jmp_buf save_regs_gc_mark; ++ struct timeval gctv1, gctv2; + SET_STACK_END; + + #ifdef HAVE_NATIVETHREAD +@@ -1339,6 +1675,14 @@ + if (during_gc) return; + during_gc++; + ++ if (gc_statistics) { ++ gc_collections++; ++ gettimeofday(&gctv1, NULL); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "Garbage collection started\n"); ++ } ++ } ++ + init_mark_stack(); + + gc_mark((VALUE)ruby_current_node, 0); +@@ -1414,6 +1758,17 @@ + } while (!MARK_STACK_EMPTY); + + gc_sweep(); ++ ++ if (gc_statistics) { ++ GC_TIME_TYPE musecs_used; ++ gettimeofday(&gctv2, NULL); ++ musecs_used = ((GC_TIME_TYPE)(gctv2.tv_sec - gctv1.tv_sec) * 1000000) + (gctv2.tv_usec - gctv1.tv_usec); ++ gc_time += musecs_used; ++ ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "GC time: %d msec\n", musecs_used / 1000); ++ } ++ } + } + + void +@@ -1595,6 +1950,7 @@ + if (!rb_gc_stack_start) { + Init_stack(0); + } ++ set_gc_parameters(); + add_heap(); + } + +@@ -2064,6 +2420,14 @@ + rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0); + rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0); + ++ rb_define_singleton_method(rb_mGC, "enable_stats", rb_gc_enable_stats, 0); ++ rb_define_singleton_method(rb_mGC, "disable_stats", rb_gc_disable_stats, 0); ++ rb_define_singleton_method(rb_mGC, "clear_stats", rb_gc_clear_stats, 0); ++ rb_define_singleton_method(rb_mGC, "collections", rb_gc_collections, 0); ++ rb_define_singleton_method(rb_mGC, "time", rb_gc_time, 0); ++ rb_define_singleton_method(rb_mGC, "dump", rb_gc_dump, 0); ++ rb_define_singleton_method(rb_mGC, "log", rb_gc_log, 1); ++ + rb_mObSpace = rb_define_module("ObjectSpace"); + rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1); + rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0); diff --git a/patches/ruby/1.8.7/hs.patch b/patches/ruby/1.8.7/hs.patch new file mode 100644 index 0000000000..dbdb557e75 --- /dev/null +++ b/patches/ruby/1.8.7/hs.patch @@ -0,0 +1,1135 @@ +diff --git a/eval.c b/eval.c +index b705302..909cd3d 100644 +--- a/eval.c ++++ b/eval.c +@@ -73,6 +73,7 @@ char *strrchr _((const char*,const char)); + #endif + + #include ++#include + + #ifdef __BEOS__ + #include +@@ -1022,7 +1023,7 @@ static struct tag *prot_tag; + _tag.blkid = 0; \ + prot_tag = &_tag + +-#define PROT_NONE Qfalse /* 0 */ ++#define PROT_EMPTY Qfalse /* 0 */ + #define PROT_THREAD Qtrue /* 2 */ + #define PROT_FUNC INT2FIX(0) /* 1 */ + #define PROT_LOOP INT2FIX(1) /* 3 */ +@@ -1234,7 +1235,7 @@ error_print() + + if (NIL_P(ruby_errinfo)) return; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if (EXEC_TAG() == 0) { + errat = get_backtrace(ruby_errinfo); + } +@@ -1395,7 +1396,7 @@ ruby_init() + /* default visibility is private at toplevel */ + SCOPE_SET(SCOPE_PRIVATE); + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + rb_call_inits(); + ruby_class = rb_cObject; +@@ -1529,7 +1530,7 @@ ruby_options(argc, argv) + int state; + + Init_stack((void*)&state); +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + ruby_process_options(argc, argv); + } +@@ -1546,7 +1547,7 @@ void rb_exec_end_proc _((void)); + static void + ruby_finalize_0() + { +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if (EXEC_TAG() == 0) { + rb_trap_exit(); + } +@@ -1584,7 +1585,7 @@ ruby_cleanup(ex) + Init_stack((void *)&state); + ruby_finalize_0(); + errs[0] = ruby_errinfo; +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + PUSH_ITER(ITER_NOT); + if ((state = EXEC_TAG()) == 0) { + rb_thread_cleanup(); +@@ -1635,7 +1636,7 @@ ruby_exec_internal() + { + int state; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + PUSH_ITER(ITER_NOT); + /* default visibility is private at toplevel */ + SCOPE_SET(SCOPE_PRIVATE); +@@ -1857,7 +1858,7 @@ rb_eval_cmd(cmd, arg, level) + } + if (TYPE(cmd) != T_STRING) { + PUSH_ITER(ITER_NOT); +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + ruby_safe_level = level; + if ((state = EXEC_TAG()) == 0) { + val = rb_funcall2(cmd, rb_intern("call"), RARRAY(arg)->len, RARRAY(arg)->ptr); +@@ -1879,7 +1880,7 @@ rb_eval_cmd(cmd, arg, level) + + ruby_safe_level = level; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + val = eval(ruby_top_self, cmd, Qnil, 0, 0); + } +@@ -2386,7 +2387,7 @@ is_defined(self, node, buf) + val = self; + if (node->nd_recv == (NODE *)1) goto check_bound; + case NODE_CALL: +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + val = rb_eval(self, node->nd_recv); + } +@@ -2488,7 +2489,7 @@ is_defined(self, node, buf) + break; + + case NODE_COLON2: +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + val = rb_eval(self, node->nd_head); + } +@@ -2537,7 +2538,7 @@ is_defined(self, node, buf) + goto again; + + default: +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + rb_eval(self, node); + } +@@ -2741,7 +2742,7 @@ call_trace_func(event, node, self, id, klass) + klass = rb_iv_get(klass, "__attached__"); + } + } +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + raised = rb_thread_reset_raised(th); + if ((state = EXEC_TAG()) == 0) { + srcfile = rb_str_new2(ruby_sourcefile?ruby_sourcefile:"(ruby)"); +@@ -3304,7 +3305,7 @@ rb_eval(self, n) + volatile VALUE e_info = ruby_errinfo; + volatile int rescuing = 0; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + retry_entry: + result = rb_eval(self, node->nd_head); +@@ -3353,7 +3354,7 @@ rb_eval(self, n) + break; + + case NODE_ENSURE: +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + result = rb_eval(self, node->nd_head); + } +@@ -3571,7 +3572,7 @@ rb_eval(self, n) + ruby_frame = &frame; + + PUSH_SCOPE(); +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if (node->nd_rval) { + saved_cref = ruby_cref; + ruby_cref = (NODE*)node->nd_rval; +@@ -4197,7 +4198,7 @@ module_setup(module, n) + } + + PUSH_CREF(module); +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + EXEC_EVENT_HOOK(RUBY_EVENT_CLASS, n, ruby_cbase, + ruby_frame->last_func, ruby_frame->last_class); +@@ -4604,7 +4605,7 @@ rb_longjmp(tag, mesg) + VALUE e = ruby_errinfo; + int status; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((status = EXEC_TAG()) == 0) { + StringValue(e); + warn_printf("Exception `%s' at %s:%d - %s\n", +@@ -4978,7 +4979,7 @@ rb_yield_0(val, self, klass, flags, avalue) + var = block->var; + + if (var) { +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + NODE *bvar = NULL; + block_var: +@@ -5051,7 +5052,7 @@ rb_yield_0(val, self, klass, flags, avalue) + ruby_current_node = node; + + PUSH_ITER(block->iter); +- PUSH_TAG(lambda ? PROT_NONE : PROT_YIELD); ++ PUSH_TAG(lambda ? PROT_EMPTY : PROT_YIELD); + if ((state = EXEC_TAG()) == 0) { + redo: + if (nd_type(node) == NODE_CFUNC || nd_type(node) == NODE_IFUNC) { +@@ -5464,7 +5465,7 @@ rb_rescue2(b_proc, data1, r_proc, data2, va_alist) + VALUE eclass; + va_list args; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + switch (state = EXEC_TAG()) { + case TAG_RETRY: + if (!handle) break; +@@ -5522,7 +5523,7 @@ rb_protect(proc, data, state) + VALUE result = Qnil; /* OK */ + int status; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + cont_protect = (VALUE)rb_node_newnode(NODE_MEMO, cont_protect, 0, 0); + if ((status = EXEC_TAG()) == 0) { + result = (*proc)(data); +@@ -5550,7 +5551,7 @@ rb_ensure(b_proc, data1, e_proc, data2) + volatile VALUE result = Qnil; + VALUE retval; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + result = (*b_proc)(data1); + } +@@ -5577,7 +5578,7 @@ rb_with_disable_interrupt(proc, data) + int thr_critical = rb_thread_critical; + + rb_thread_critical = Qtrue; +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((status = EXEC_TAG()) == 0) { + result = (*proc)(data); + } +@@ -6264,7 +6265,7 @@ rb_funcall_rescue(recv, mid, n, va_alist) + + va_init_list(ar, n); + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((status = EXEC_TAG()) == 0) { + result = vafuncall(recv, mid, n, &ar); + } +@@ -6539,7 +6540,7 @@ eval(self, src, scope, file, line) + if (TYPE(ruby_class) == T_ICLASS) { + ruby_class = RBASIC(ruby_class)->klass; + } +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + NODE *node; + +@@ -6698,7 +6699,7 @@ exec_under(func, under, cbase, args) + + mode = scope_vmode; + SCOPE_SET(SCOPE_PUBLIC); +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + val = (*func)(args); + } +@@ -7009,7 +7010,7 @@ rb_load(fname, wrap) + PUSH_SCOPE(); + /* default visibility is private at loading toplevel */ + SCOPE_SET(SCOPE_PRIVATE); +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + state = EXEC_TAG(); + last_func = ruby_frame->last_func; + last_node = ruby_current_node; +@@ -7068,7 +7069,7 @@ rb_load_protect(fname, wrap, state) + { + int status; + +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((status = EXEC_TAG()) == 0) { + rb_load(fname, wrap); + } +@@ -7389,7 +7390,7 @@ rb_require_safe(fname, safe) + saved.node = ruby_current_node; + saved.func = ruby_frame->last_func; + saved.safe = ruby_safe_level; +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + VALUE feature, path; + long handle; +@@ -8097,7 +8098,7 @@ rb_exec_end_proc() + tmp_end_procs = link = ephemeral_end_procs; + ephemeral_end_procs = 0; + while (link) { +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((status = EXEC_TAG()) == 0) { + ruby_safe_level = link->safe; + (*link->func)(link->data); +@@ -8115,7 +8116,7 @@ rb_exec_end_proc() + tmp_end_procs = link = end_procs; + end_procs = 0; + while (link) { +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((status = EXEC_TAG()) == 0) { + ruby_safe_level = link->safe; + (*link->func)(link->data); +@@ -8852,7 +8853,7 @@ proc_invoke(proc, args, self, klass) + ruby_block = &_block; + PUSH_ITER(ITER_CUR); + ruby_frame->iter = ITER_CUR; +- PUSH_TAG(pcall ? PROT_LAMBDA : PROT_NONE); ++ PUSH_TAG(pcall ? PROT_LAMBDA : PROT_EMPTY); + state = EXEC_TAG(); + if (state == 0) { + proc_set_safe_level(proc); +@@ -10179,6 +10180,7 @@ win32_set_exception_list(p) + int rb_thread_pending = 0; + + VALUE rb_cThread; ++static unsigned int rb_thread_stack_size; + + extern VALUE rb_last_status; + +@@ -10406,12 +10408,20 @@ thread_mark(th) + rb_gc_mark(th->thread); + if (th->join) rb_gc_mark(th->join->thread); + +- rb_gc_mark(th->klass); +- rb_gc_mark(th->wrapper); +- rb_gc_mark((VALUE)th->cref); ++ if (curr_thread == th) { ++ rb_gc_mark(ruby_class); ++ rb_gc_mark(ruby_wrapper); ++ rb_gc_mark((VALUE)ruby_cref); ++ rb_gc_mark((VALUE)ruby_scope); ++ rb_gc_mark((VALUE)ruby_dyna_vars); ++ } else { ++ rb_gc_mark(th->klass); ++ rb_gc_mark(th->wrapper); ++ rb_gc_mark((VALUE)th->cref); ++ rb_gc_mark((VALUE)th->scope); ++ rb_gc_mark((VALUE)th->dyna_vars); ++ } + +- rb_gc_mark((VALUE)th->scope); +- rb_gc_mark((VALUE)th->dyna_vars); + rb_gc_mark(th->errinfo); + rb_gc_mark(th->last_status); + rb_gc_mark(th->last_line); +@@ -10421,11 +10431,11 @@ thread_mark(th) + rb_gc_mark_maybe(th->sandbox); + + /* mark data in copied stack */ +- if (th == curr_thread) return; ++ if (th == main_thread) return; + if (th->status == THREAD_KILLED) return; + if (th->stk_len == 0) return; /* stack not active, no need to mark. */ +- if (th->stk_ptr) { +- rb_gc_mark_locations(th->stk_ptr, th->stk_ptr+th->stk_len); ++ if (th->stk_ptr && th != curr_thread) { ++ rb_gc_mark_locations(th->stk_pos, th->stk_base); + #if defined(THINK_C) || defined(__human68k__) + rb_gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2); + #endif +@@ -10435,24 +10445,30 @@ thread_mark(th) + } + #endif + } +- frame = th->frame; ++ ++ if (curr_thread == th) ++ frame = ruby_frame; ++ else ++ frame = th->frame; ++ + while (frame && frame != top_frame) { +- frame = ADJ(frame); + rb_gc_mark_frame(frame); + if (frame->tmp) { + struct FRAME *tmp = frame->tmp; +- + while (tmp && tmp != top_frame) { +- tmp = ADJ(tmp); + rb_gc_mark_frame(tmp); + tmp = tmp->prev; + } + } + frame = frame->prev; + } +- block = th->block; ++ ++ if (curr_thread == th) ++ block = ruby_block; ++ else ++ block = th->block; ++ + while (block) { +- block = ADJ(block); + rb_gc_mark_frame(&block->frame); + block = block->prev; + } +@@ -10515,7 +10531,7 @@ static inline void + stack_free(th) + rb_thread_t th; + { +- if (th->stk_ptr) free(th->stk_ptr); ++ if (th->stk_ptr) munmap(th->stk_ptr, th->stk_size); + th->stk_ptr = 0; + #ifdef __ia64 + if (th->bstr_ptr) free(th->bstr_ptr); +@@ -10576,35 +10592,8 @@ rb_thread_save_context(th) + static VALUE tval; + + len = ruby_stack_length(&pos); +- th->stk_len = 0; +- th->stk_pos = pos; +- if (len > th->stk_max) { +- VALUE *ptr = realloc(th->stk_ptr, sizeof(VALUE) * len); +- if (!ptr) rb_memerror(); +- th->stk_ptr = ptr; +- th->stk_max = len; +- } + th->stk_len = len; +- FLUSH_REGISTER_WINDOWS; +- MEMCPY(th->stk_ptr, th->stk_pos, VALUE, th->stk_len); +-#ifdef __ia64 +- th->bstr_pos = rb_gc_register_stack_start; +- len = (VALUE*)rb_ia64_bsp() - th->bstr_pos; +- th->bstr_len = 0; +- if (len > th->bstr_max) { +- VALUE *ptr = realloc(th->bstr_ptr, sizeof(VALUE) * len); +- if (!ptr) rb_memerror(); +- th->bstr_ptr = ptr; +- th->bstr_max = len; +- } +- th->bstr_len = len; +- rb_ia64_flushrs(); +- MEMCPY(th->bstr_ptr, th->bstr_pos, VALUE, th->bstr_len); +-#endif +-#ifdef SAVE_WIN32_EXCEPTION_LIST +- th->win32_exception_list = win32_get_exception_list(); +-#endif +- ++ th->stk_pos = pos; + th->frame = ruby_frame; + th->scope = ruby_scope; + ruby_scope->flags |= SCOPE_DONT_RECYCLE; +@@ -10714,11 +10703,6 @@ rb_thread_restore_context_0(rb_thread_t th, int exit) + #endif + tmp = th; + ex = exit; +- FLUSH_REGISTER_WINDOWS; +- MEMCPY(tmp->stk_pos, tmp->stk_ptr, VALUE, tmp->stk_len); +-#ifdef __ia64 +- MEMCPY(tmp->bstr_pos, tmp->bstr_ptr, VALUE, tmp->bstr_len); +-#endif + + tval = rb_lastline_get(); + rb_lastline_set(tmp->last_line); +@@ -10809,8 +10793,8 @@ rb_thread_restore_context(th, exit) + rb_thread_t th; + int exit; + { +- if (!th->stk_ptr) rb_bug("unsaved context"); +- stack_extend(th, exit); ++ if (!th->stk_ptr && th != main_thread) rb_bug("unsaved context"); ++ rb_thread_restore_context_0(th, exit); + } + + static void +@@ -10829,7 +10813,6 @@ rb_thread_die(th) + { + th->thgroup = 0; + th->status = THREAD_KILLED; +- stack_free(th); + } + + static void +@@ -12096,6 +12079,7 @@ rb_thread_group(thread) + \ + th->stk_ptr = 0;\ + th->stk_len = 0;\ ++ th->stk_size = 0;\ + th->stk_max = 0;\ + th->wait_for = 0;\ + IA64_INIT(th->bstr_ptr = 0);\ +@@ -12143,6 +12127,48 @@ rb_thread_alloc(klass) + THREAD_ALLOC(th); + th->thread = Data_Wrap_Struct(klass, thread_mark, thread_free, th); + ++ /* if main_thread != NULL, then this is NOT the main thread, so ++ * we create a heap-stack ++ */ ++ if (main_thread) { ++ /* Allocate stack, don't forget to add 1 extra word because of the MATH below */ ++ unsigned int pagesize = getpagesize(); ++ unsigned int total_size = rb_thread_stack_size + pagesize + sizeof(int); ++ void *stack_area = NULL; ++ ++ stack_area = mmap(NULL, total_size, PROT_READ | PROT_WRITE | PROT_EXEC, ++ MAP_PRIVATE | MAP_ANON, -1, 0); ++ ++ if (stack_area == MAP_FAILED) { ++ fprintf(stderr, "Thread stack allocation failed!\n"); ++ rb_memerror(); ++ } ++ ++ th->stk_ptr = th->stk_pos = stack_area; ++ th->stk_size = total_size; ++ ++ if (mprotect(th->stk_ptr, pagesize, PROT_NONE) == -1) { ++ fprintf(stderr, "Failed to create thread guard region: %s\n", strerror(errno)); ++ rb_memerror(); ++ } ++ ++ th->guard = th->stk_ptr + (pagesize/sizeof(VALUE *)); ++ ++ /* point stk_base at the top of the stack */ ++ /* ASSUMPTIONS: ++ * 1.) The address returned by malloc is "suitably aligned" for anything on this system ++ * 2.) Adding a value that is "aligned" for this platform should not unalign the address ++ * returned from malloc. ++ * 3.) Don't push anything on to the stack, otherwise it'll get unaligned. ++ * 4.) x86_64 ABI says aligned AFTER arguments have been pushed. You *must* then do a call[lq] ++ * or push[lq] something else on to the stack if you inted to do a ret. ++ */ ++ th->stk_base = th->stk_ptr + ((total_size - sizeof(int))/sizeof(VALUE *)); ++ th->stk_len = rb_thread_stack_size; ++ } else { ++ th->stk_ptr = th->stk_pos = rb_gc_stack_start; ++ } ++ + for (vars = th->dyna_vars; vars; vars = vars->next) { + if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; + FL_SET(vars, DVAR_DONT_RECYCLE); +@@ -12246,17 +12272,22 @@ rb_thread_stop_timer() + int rb_thread_tick = THREAD_TICK; + #endif + ++struct thread_start_args { ++ VALUE (*fn)(); ++ void *arg; ++ rb_thread_t th; ++} new_th; ++ ++static VALUE ++rb_thread_start_2(); ++ + static VALUE + rb_thread_start_0(fn, arg, th) + VALUE (*fn)(); + void *arg; + rb_thread_t th; + { +- volatile rb_thread_t th_save = th; + volatile VALUE thread = th->thread; +- struct BLOCK *volatile saved_block = 0; +- enum rb_thread_status status; +- int state; + + if (OBJ_FROZEN(curr_thread->thgroup)) { + rb_raise(rb_eThreadError, +@@ -12284,16 +12315,41 @@ rb_thread_start_0(fn, arg, th) + return thread; + } + +- if (ruby_block) { /* should nail down higher blocks */ +- struct BLOCK dummy; ++ new_th.fn = fn; ++ new_th.arg = arg; ++ new_th.th = th; ++ ++#if defined(__i386__) ++ __asm__ __volatile__ ("movl %0, %%esp\n\t" ++ "calll *%1\n" ++ :: "r" (th->stk_base), ++ "r" (rb_thread_start_2)); ++#elif defined(__x86_64__) ++ __asm__ __volatile__ ("movq %0, %%rsp\n\t" ++ "callq *%1\n" ++ :: "r" (th->stk_base), ++ "r" (rb_thread_start_2)); ++#else ++ #error unsupported architecture! ++#endif ++ /* NOTREACHED */ ++ return 0; ++} + +- dummy.prev = ruby_block; +- blk_copy_prev(&dummy); +- saved_block = ruby_block = dummy.prev; +- } +- scope_dup(ruby_scope); ++static VALUE ++rb_thread_start_2() ++{ ++ volatile rb_thread_t th = new_th.th; ++ volatile rb_thread_t th_save = th; ++ volatile VALUE thread = th->thread; ++ struct BLOCK *volatile saved_block = 0; ++ enum rb_thread_status status; ++ int state; ++ struct tag *tag; ++ struct RVarmap *vars; ++ struct FRAME dummy_frame; + +- if (!th->next) { ++ if (!th->next) { + /* merge in thread list */ + th->prev = curr_thread; + curr_thread->next->prev = th; +@@ -12301,13 +12357,27 @@ rb_thread_start_0(fn, arg, th) + curr_thread->next = th; + th->priority = curr_thread->priority; + th->thgroup = curr_thread->thgroup; ++ } ++ curr_thread = th; ++ ++ dummy_frame = *ruby_frame; ++ dummy_frame.prev = top_frame; ++ ruby_frame = &dummy_frame; ++ ++ if (ruby_block) { /* should nail down higher blocks */ ++ struct BLOCK dummy; ++ ++ dummy.prev = ruby_block; ++ blk_copy_prev(&dummy); ++ saved_block = ruby_block = dummy.prev; + } + ++ scope_dup(ruby_scope); ++ + PUSH_TAG(PROT_THREAD); + if ((state = EXEC_TAG()) == 0) { + if (THREAD_SAVE_CONTEXT(th) == 0) { +- curr_thread = th; +- th->result = (*fn)(arg, th); ++ th->result = (*new_th.fn)(new_th.arg, th); + } + th = th_save; + } +@@ -12644,6 +12714,43 @@ rb_thread_cleanup() + END_FOREACH_FROM(curr, th); + } + ++/* ++ * call-seq: ++ * Thread.stack_size => fixnum ++ * ++ * Returns the thread stack size in bytes ++ */ ++static VALUE ++rb_thread_stacksize_get() ++{ ++ return INT2FIX(rb_thread_stack_size); ++} ++ ++/* ++ * call-seq: ++ * Thread.stack_size= fixnum => Qnil ++ * ++ * Sets the global thread stacksize and returns Qnil. ++ */ ++static VALUE ++rb_thread_stacksize_set(obj, val) ++ VALUE obj; ++ VALUE val; ++{ ++ ++ unsigned int size = FIX2UINT(val); ++ ++ /* 16byte alignment works for both x86 and x86_64 */ ++ if (size & (~0xf)) { ++ size += 0x10; ++ size = size & (~0xf); ++ } ++ ++ rb_thread_stack_size = size; ++ ++ return Qnil; ++} ++ + int rb_thread_critical; + + +@@ -13473,7 +13580,7 @@ rb_exec_recursive(func, obj, arg) + int state; + + hash = recursive_push(hash, objid); +- PUSH_TAG(PROT_NONE); ++ PUSH_TAG(PROT_EMPTY); + if ((state = EXEC_TAG()) == 0) { + result = (*func) (obj, arg, Qfalse); + } +@@ -13500,6 +13607,8 @@ Init_Thread() + { + VALUE cThGroup; + ++ rb_thread_stack_size = (1024 * 1024); ++ + recursive_key = rb_intern("__recursive_key__"); + rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError); + rb_cThread = rb_define_class("Thread", rb_cObject); +@@ -13524,6 +13633,9 @@ Init_Thread() + rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0); + rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1); + ++ rb_define_singleton_method(rb_cThread, "stack_size", rb_thread_stacksize_get, 0); ++ rb_define_singleton_method(rb_cThread, "stack_size=", rb_thread_stacksize_set, 1); ++ + rb_define_method(rb_cThread, "run", rb_thread_run, 0); + rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0); + rb_define_method(rb_cThread, "kill", rb_thread_kill, 0); +diff --git a/gc.c b/gc.c +index a564f0b..d6d654d 100644 +--- a/gc.c ++++ b/gc.c +@@ -506,12 +506,12 @@ stack_end_address(VALUE **stack_end_p) + # define STACK_END (stack_end) + #endif + #if STACK_GROW_DIRECTION < 0 +-# define STACK_LENGTH (rb_gc_stack_start - STACK_END) ++# define STACK_LENGTH(start) ((start) - STACK_END) + #elif STACK_GROW_DIRECTION > 0 +-# define STACK_LENGTH (STACK_END - rb_gc_stack_start + 1) ++# define STACK_LENGTH(start) (STACK_END - (start) + 1) + #else +-# define STACK_LENGTH ((STACK_END < rb_gc_stack_start) ? rb_gc_stack_start - STACK_END\ +- : STACK_END - rb_gc_stack_start + 1) ++# define STACK_LENGTH(start) ((STACK_END < (start)) ? (start) - STACK_END\ ++ : STACK_END - (start) + 1) + #endif + #if STACK_GROW_DIRECTION > 0 + # define STACK_UPPER(x, a, b) a +@@ -534,27 +534,36 @@ stack_grow_direction(addr) + + #define GC_WATER_MARK 512 + +-#define CHECK_STACK(ret) do {\ ++#define CHECK_STACK(ret, start) do {\ + SET_STACK_END;\ +- (ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\ ++ (ret) = (STACK_LENGTH(start) > STACK_LEVEL_MAX + GC_WATER_MARK);\ + } while (0) + + size_t + ruby_stack_length(p) + VALUE **p; + { +- SET_STACK_END; +- if (p) *p = STACK_UPPER(STACK_END, rb_gc_stack_start, STACK_END); +- return STACK_LENGTH; ++ SET_STACK_END; ++ VALUE *start; ++ if (rb_curr_thread == rb_main_thread) { ++ start = rb_gc_stack_start; ++ } else { ++ start = rb_curr_thread->stk_base; ++ } ++ if (p) *p = STACK_UPPER(STACK_END, start, STACK_END); ++ return STACK_LENGTH(start); + } + + int + ruby_stack_check() + { +- int ret; +- +- CHECK_STACK(ret); +- return ret; ++ int ret; ++ if (rb_curr_thread == rb_main_thread) { ++ CHECK_STACK(ret, rb_gc_stack_start); ++ } else { ++ CHECK_STACK(ret, rb_curr_thread->stk_base); ++ } ++ return ret; + } + + #define MARK_STACK_MAX 1024 +@@ -1441,10 +1450,13 @@ garbage_collect() + + init_mark_stack(); + +- gc_mark((VALUE)ruby_current_node, 0); +- + /* mark frame stack */ +- for (frame = ruby_frame; frame; frame = frame->prev) { ++ if (rb_curr_thread == rb_main_thread) ++ frame = ruby_frame; ++ else ++ frame = rb_main_thread->frame; ++ ++ for (; frame; frame = frame->prev) { + rb_gc_mark_frame(frame); + if (frame->tmp) { + struct FRAME *tmp = frame->tmp; +@@ -1454,16 +1466,35 @@ garbage_collect() + } + } + } +- gc_mark((VALUE)ruby_scope, 0); +- gc_mark((VALUE)ruby_dyna_vars, 0); ++ ++ if (rb_curr_thread == rb_main_thread) { ++ gc_mark((VALUE)ruby_current_node, 0); ++ gc_mark((VALUE)ruby_scope, 0); ++ gc_mark((VALUE)ruby_dyna_vars, 0); ++ } else { ++ gc_mark((VALUE)rb_main_thread->node, 0); ++ gc_mark((VALUE)rb_main_thread->scope, 0); ++ gc_mark((VALUE)rb_main_thread->dyna_vars, 0); ++ ++ /* scan the current thread's stack */ ++ rb_gc_mark_locations((VALUE*)STACK_END, rb_curr_thread->stk_base); ++ } ++ + if (finalizer_table) { +- mark_tbl(finalizer_table, 0); ++ mark_tbl(finalizer_table, 0); + } + + FLUSH_REGISTER_WINDOWS; + /* This assumes that all registers are saved into the jmp_buf (and stack) */ + rb_setjmp(save_regs_gc_mark); + mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *)); ++ ++ /* If this is not the main thread, we need to scan the C stack, so ++ * set STACK_END to the end of the C stack. ++ */ ++ if (rb_curr_thread != rb_main_thread) ++ STACK_END = rb_main_thread->stk_pos; ++ + #if STACK_GROW_DIRECTION < 0 + rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start); + #elif STACK_GROW_DIRECTION > 0 +@@ -1483,6 +1514,7 @@ garbage_collect() + rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2), + (VALUE*)((char*)rb_gc_stack_start + 2)); + #endif ++ + rb_gc_mark_threads(); + + /* mark protected global variables */ +diff --git a/lib/logger.rb b/lib/logger.rb +index 15d95fc..5a6d467 100644 +--- a/lib/logger.rb ++++ b/lib/logger.rb +@@ -170,7 +170,7 @@ require 'monitor' + + class Logger + VERSION = "1.2.6" +- id, name, rev = %w$Id$ ++ id, name, rev = %w$Id logger.rb 1234$ + ProgName = "#{name.chomp(",v")}/#{rev}" + + class Error < RuntimeError; end +diff --git a/node.h b/node.h +index c209fa5..740e66a 100644 +--- a/node.h ++++ b/node.h +@@ -411,8 +411,11 @@ struct rb_thread { + + size_t stk_len; + size_t stk_max; ++ size_t stk_size; + VALUE *stk_ptr; + VALUE *stk_pos; ++ VALUE *stk_base; ++ VALUE *guard; + #ifdef __ia64 + size_t bstr_len; + size_t bstr_max; +diff --git a/signal.c b/signal.c +index fb21fd3..acac6a7 100644 +--- a/signal.c ++++ b/signal.c +@@ -14,6 +14,7 @@ + + #include "ruby.h" + #include "rubysig.h" ++#include "node.h" + #include + #include + +@@ -428,15 +429,22 @@ typedef RETSIGTYPE (*sighandler_t)_((int)); + static sighandler_t + ruby_signal(signum, handler) + int signum; +- sighandler_t handler; ++ void *handler; + { + struct sigaction sigact, old; + + rb_trap_accept_nativethreads[signum] = 0; + +- sigact.sa_handler = handler; ++ if (signum == SIGSEGV || signum == SIGBUS) { ++ sigact.sa_sigaction = handler; ++ sigact.sa_flags = (SA_ONSTACK | SA_RESETHAND | SA_SIGINFO); ++ } else { ++ sigact.sa_handler = handler; ++ sigact.sa_flags = 0; ++ } ++ + sigemptyset(&sigact.sa_mask); +- sigact.sa_flags = 0; ++ + # ifdef SA_NOCLDWAIT + if (signum == SIGCHLD && handler == SIG_IGN) + sigact.sa_flags |= SA_NOCLDWAIT; +@@ -599,7 +607,132 @@ sighandler(sig) + } + } + ++#include ++#ifdef HAVE_STDARG_PROTOTYPES ++#include ++#define va_init_list(a,b) va_start(a,b) ++#else ++#include ++#define va_init_list(a,b) va_start(a) ++#endif ++ ++void ++#ifdef HAVE_STDARG_PROTOTYPES ++sig_printf(const char *fmt, ...) ++#else ++ sig_printf(fmt, va_alist) ++ const char *fmt; ++ va_dcl ++#endif ++{ ++ char buf[BUFSIZ]; ++ va_list args; ++ FILE *out = stderr; ++ ++ va_init_list(args, fmt); ++ vfprintf(out, fmt, args); ++ va_end(args); ++ fprintf(out, "\n"); ++} ++ ++static void ++dump_machine_state(uc) ++ ucontext_t *uc; ++{ ++ const char *dump64 = ++ " ----------------- Register state dump ----------------------\n" ++ "rax = 0x%.16x rbx = 0x%.16x rcx = 0x%.16x rdx = 0x%.16x\n" ++ "rdi = 0x%.16x rsi = 0x%.16x rbp = 0x%.16x rsp = 0x%.16x\n" ++ "r8 = 0x%.16x r9 = 0x%.16x r10 = 0x%.16x r11 = 0x%.16x\n" ++ "r12 = 0x%.16x r13 = 0x%.16x r14 = 0x%.16x r15 = 0x%.16x\n" ++ "rip = 0x%.16x rflags = 0x%.16x cs = 0x%.16x fs = 0x%.16x\n" ++ "gs = 0x%.16x"; ++ ++ const char *dump32 = ++ " ----------------- Register state dump -------------------\n" ++ "eax = 0x%.8x ebx = 0x%.8x ecx = 0x%.8x edx = 0x%.8x\n" ++ "edi = 0x%.8x esi = 0x%.8x ebp = 0x%.8x esp = 0x%.8x\n" ++ "ss = 0x%.8x eflags = 0x%.8x eip = 0x%.8x cs = 0x%.8x\n" ++ "ds = 0x%.8x es = 0x%.8x fs = 0x%.8x gs = 0x%.8x\n"; ++ ++#if defined(__LP64__) && defined(__APPLE__) ++ sig_printf(dump64, uc->uc_mcontext->__ss.__rax, uc->uc_mcontext->__ss.__rbx, ++ uc->uc_mcontext->__ss.__rcx, uc->uc_mcontext->__ss.__rdx, uc->uc_mcontext->__ss.__rdi, ++ uc->uc_mcontext->__ss.__rsi, uc->uc_mcontext->__ss.__rbp, uc->uc_mcontext->__ss.__rsp, ++ uc->uc_mcontext->__ss.__r8, uc->uc_mcontext->__ss.__r9, uc->uc_mcontext->__ss.__r10, ++ uc->uc_mcontext->__ss.__r11, uc->uc_mcontext->__ss.__r12, uc->uc_mcontext->__ss.__r13, ++ uc->uc_mcontext->__ss.__r14, uc->uc_mcontext->__ss.__r15, uc->uc_mcontext->__ss.__rip, ++ uc->uc_mcontext->__ss.__rflags, uc->uc_mcontext->__ss.__cs, uc->uc_mcontext->__ss.__fs, ++ uc->uc_mcontext->__ss.__gs); ++#elif !defined(__LP64__) && defined(__APPLE__) ++ sig_printf(dump32, uc->uc_mcontext->__ss.__eax, uc->uc_mcontext->__ss.__ebx, ++ uc->uc_mcontext->__ss.__ecx, uc->uc_mcontext->__ss.__edx, ++ uc->uc_mcontext->__ss.__edi, uc->uc_mcontext->__ss.__esi, ++ uc->uc_mcontext->__ss.__ebp, uc->uc_mcontext->__ss.__esp, ++ uc->uc_mcontext->__ss.__ss, uc->uc_mcontext->__ss.__eflags, ++ uc->uc_mcontext->__ss.__eip, uc->uc_mcontext->__ss.__cs, ++ uc->uc_mcontext->__ss.__ds, uc->uc_mcontext->__ss.__es, ++ uc->uc_mcontext->__ss.__fs, uc->uc_mcontext->__ss.__gs); ++#elif defined(__i386__) ++ sig_printf(dump32, uc->uc_mcontext.gregs[REG_EAX], uc->uc_mcontext.gregs[REG_EBX], ++ uc->uc_mcontext.gregs[REG_ECX], uc->uc_mcontext.gregs[REG_EDX], ++ uc->uc_mcontext.gregs[REG_EDI], uc->uc_mcontext.gregs[REG_ESI], ++ uc->uc_mcontext.gregs[REG_EBP], uc->uc_mcontext.gregs[REG_ESP], ++ uc->uc_mcontext.gregs[REG_SS], uc->uc_mcontext.gregs[REG_EFL], ++ uc->uc_mcontext.gregs[REG_EIP], uc->uc_mcontext.gregs[REG_EIP], ++ uc->uc_mcontext.gregs[REG_DS], uc->uc_mcontext.gregs[REG_ES], ++ uc->uc_mcontext.gregs[REG_FS], uc->uc_mcontext.gregs[REG_FS]); ++#elif defined(__x86_64__) ++ sig_printf(dump64, uc->uc_mcontext.gregs[REG_RAX], uc->uc_mcontext.gregs[REG_RBX], ++ uc->uc_mcontext.gregs[REG_RCX], uc->uc_mcontext.gregs[REG_RDX], ++ uc->uc_mcontext.gregs[REG_RDI], uc->uc_mcontext.gregs[REG_RSI], ++ uc->uc_mcontext.gregs[REG_RBP], uc->uc_mcontext.gregs[REG_RSP], ++ uc->uc_mcontext.gregs[REG_R8], uc->uc_mcontext.gregs[REG_R9], ++ uc->uc_mcontext.gregs[REG_R10], uc->uc_mcontext.gregs[REG_R11], ++ uc->uc_mcontext.gregs[REG_R12], uc->uc_mcontext.gregs[REG_R13], ++ uc->uc_mcontext.gregs[REG_R14], uc->uc_mcontext.gregs[REG_R15], ++ uc->uc_mcontext.gregs[REG_RIP], uc->uc_mcontext.gregs[REG_EFL], ++ uc->uc_mcontext.gregs[REG_CSGSFS]); ++#else ++#endif ++} ++ ++static int ++check_guard(caddr_t fault_addr, rb_thread_t th) { ++ if(fault_addr <= (caddr_t)rb_curr_thread->guard && ++ fault_addr >= (caddr_t)rb_curr_thread->stk_ptr) { ++ return 1; ++ } ++ return 0; ++} ++ + #ifdef SIGBUS ++#ifdef POSIX_SIGNAL ++static void sigbus _((int, siginfo_t*, void*)); ++static void ++sigbus(sig, ip, context) ++ int sig; ++ siginfo_t *ip; ++ void *context; ++{ ++#if defined(HAVE_NATIVETHREAD) && defined(HAVE_NATIVETHREAD_KILL) ++ if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) { ++ sigsend_to_ruby_thread(sig); ++ return; ++ } ++#endif ++ ++ dump_machine_state(context); ++ if (check_guard((caddr_t)ip->si_addr, rb_curr_thread)) { ++ /* we hit the guard page, print out a warning to help app developers */ ++ rb_bug("Thread stack overflow! Try increasing it!"); ++ } else { ++ rb_bug("Bus Error"); ++ } ++} ++ ++#else /* !defined(POSIX_SIGNAL) */ ++ + static RETSIGTYPE sigbus _((int)); + static RETSIGTYPE + sigbus(sig) +@@ -615,8 +748,38 @@ sigbus(sig) + rb_bug("Bus Error"); + } + #endif ++#endif ++ + + #ifdef SIGSEGV ++#ifdef POSIX_SIGNAL ++static void sigsegv _((int, siginfo_t*, void*)); ++static void ++sigsegv(sig, ip, context) ++ int sig; ++ siginfo_t *ip; ++ void *context; ++{ ++#if defined(HAVE_NATIVETHREAD) && defined(HAVE_NATIVETHREAD_KILL) ++ if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) { ++ sigsend_to_ruby_thread(sig); ++ return; ++ } ++#endif ++ ++ extern int ruby_gc_stress; ++ ruby_gc_stress = 0; ++ dump_machine_state(context); ++ if (check_guard((caddr_t)ip->si_addr, rb_curr_thread)) { ++ /* we hit the guard page, print out a warning to help app developers */ ++ rb_bug("Thread stack overflow! Try increasing it!"); ++ } else { ++ rb_bug("Segmentation fault"); ++ } ++} ++ ++#else /* !defined(POSIX_SIGNAL) */ ++ + static RETSIGTYPE sigsegv _((int)); + static RETSIGTYPE + sigsegv(sig) +@@ -634,6 +797,7 @@ sigsegv(sig) + rb_bug("Segmentation fault"); + } + #endif ++#endif + + #ifdef SIGPIPE + static RETSIGTYPE sigpipe _((int)); +@@ -705,7 +869,8 @@ static VALUE + trap(arg) + struct trap_arg *arg; + { +- sighandler_t func, oldfunc; ++ sighandler_t oldfunc; ++ void *func; + VALUE command, oldcmd; + int sig = -1; + const char *s; +@@ -952,6 +1117,20 @@ sig_list() + } + + static void ++create_sigstack() ++{ ++ stack_t ss; ++ ss.ss_size = SIGSTKSZ; ++ ss.ss_sp = malloc(ss.ss_size); ++ ss.ss_flags = 0; ++ if (sigaltstack(&ss, NULL) < 0) { ++ free(ss.ss_sp); ++ fprintf(stderr, "Couldn't create signal stack! Error %d: %s\n", errno, strerror(errno)); ++ exit(1); ++ } ++} ++ ++static void + install_sighandler(signum, handler) + int signum; + sighandler_t handler; +@@ -960,7 +1139,7 @@ install_sighandler(signum, handler) + + old = ruby_signal(signum, handler); + if (old != SIG_DFL) { +- ruby_signal(signum, old); ++ ruby_signal(signum, old); + } + } + +@@ -1089,6 +1268,8 @@ Init_signal() + rb_alias(rb_eSignal, rb_intern("signm"), rb_intern("message")); + rb_define_method(rb_eInterrupt, "initialize", interrupt_init, -1); + ++ create_sigstack(); ++ + install_sighandler(SIGINT, sighandler); + #ifdef SIGHUP + install_sighandler(SIGHUP, sighandler); diff --git a/patches/ruby/1.8.7/osx-arch-fix.patch b/patches/ruby/1.8.7/osx-arch-fix.patch new file mode 100644 index 0000000000..0f5db9e33c --- /dev/null +++ b/patches/ruby/1.8.7/osx-arch-fix.patch @@ -0,0 +1,13 @@ +diff --git a/Makefile.in b/Makefile.in +index 656ae90..f976cf1 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -45,7 +45,7 @@ XLDFLAGS = @XLDFLAGS@ $(EXTLDFLAGS) + EXTLIBS = + LIBS = @LIBS@ $(EXTLIBS) + MISSING = @LIBOBJS@ @ALLOCA@ +-LDSHARED = @LIBRUBY_LDSHARED@ ++LDSHARED = @LIBRUBY_LDSHARED@ $(LDFLAGS) + DLDFLAGS = @LIBRUBY_DLDFLAGS@ $(EXTLDFLAGS) @ARCH_FLAG@ + SOLIBS = @SOLIBS@ + MAINLIBS = @MAINLIBS@ diff --git a/patches/ruby/1.8.7/p72/mbari-1.patch b/patches/ruby/1.8.7/p72/mbari-1.patch new file mode 100644 index 0000000000..f87b8391e0 --- /dev/null +++ b/patches/ruby/1.8.7/p72/mbari-1.patch @@ -0,0 +1,441 @@ +diff -ru ruby-1.8.7-p72/ChangeLog ruby-1.8.7-mbari/ChangeLog +--- ruby-1.8.7-p72/ChangeLog 2008-08-10 17:37:21.000000000 -0700 ++++ ruby-1.8.7-mbari/ChangeLog 2008-12-09 01:24:37.000000000 -0800 +@@ -1,3 +1,20 @@ ++Tue Dec 9 8:11:36 2008 Brent Roman ++ ++ * eval.c: added Continuation.thread method ++ * cc_mark frees the continuation's stack if its thread is dead ++ avoids recursive gc that segfaults [see Dec 5th, 2007 ruby-core] ++ ++ * added cast in PUSH_FRAME() to eliminate gcc 4.2 compiler warnings ++ ++ * THREAD_DATA() replaces rb_thread_check() in most contexts ++ ++ * rb_thread_check now complains when passed a Continuation ++ (no longer need redundant check in thgroup_add() ++ ++ * rb_callcc() assigns th->thread before scope_dup() ++ this avoids segfaults if this scope_dup() triggers a gc pass ++ ++ + Fri Aug 8 10:53:52 2008 Tanaka Akira + + * lib/resolv.rb: randomize source port and transaction id. +diff -ru ruby-1.8.7-p72/eval.c ruby-1.8.7-mbari/eval.c +--- ruby-1.8.7-p72/eval.c 2008-08-03 20:24:26.000000000 -0700 ++++ ruby-1.8.7-mbari/eval.c 2008-12-10 20:42:40.000000000 -0800 +@@ -2,8 +2,8 @@ + + eval.c - + +- $Author: shyouhei $ +- $Date: 2008-08-04 12:24:26 +0900 (Mon, 04 Aug 2008) $ ++ $Author: brent $ ++ $Date: 2008/12/11 04:42:40 $ + created at: Thu Jun 10 14:22:17 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -766,11 +766,11 @@ + _frame.argc = 0; \ + _frame.flags = 0; \ + _frame.uniq = frame_unique++; \ +- ruby_frame = &_frame ++ ruby_frame = (struct FRAME *)&_frame + + #define POP_FRAME() \ + ruby_current_node = _frame.node; \ +- ruby_frame = _frame.prev; \ ++ ruby_frame = _frame.prev; \ + } while (0) + + struct BLOCK { +@@ -10485,16 +10485,57 @@ + } END_FOREACH_FROM(main_thread, th); + } + +-static void +-thread_free(th) ++ ++static inline void ++stack_free(th) + rb_thread_t th; + { +- if (th->stk_ptr) free(th->stk_ptr); +- th->stk_ptr = 0; ++ if (th->stk_ptr) { ++ free(th->stk_ptr); ++ th->stk_ptr = 0; ++ } + #ifdef __ia64 +- if (th->bstr_ptr) free(th->bstr_ptr); +- th->bstr_ptr = 0; ++ if (th->bstr_ptr) { ++ free(th->bstr_ptr); ++ th->bstr_ptr = 0; ++ } + #endif ++} ++ ++static void ++rb_thread_die(th) ++ rb_thread_t th; ++{ ++ th->thgroup = 0; ++ th->status = THREAD_KILLED; ++ stack_free(th); ++} ++ ++#define THREAD_DATA(threadObject) ((rb_thread_t)RDATA(threadObject)->data) ++ ++static inline void ++cc_purge(cc) ++ rb_thread_t cc; ++{ /* free continuation's stack if it has just died */ ++ if (cc->thread != Qnil && THREAD_DATA(cc->thread)->status == THREAD_KILLED) { ++ cc->thread = Qnil; ++ rb_thread_die(cc); /* can't possibly activate this stack */ ++ } ++} ++ ++static void ++cc_mark(cc) ++ rb_thread_t cc; ++{ /* mark this continuation's stack only if its parent thread is still alive */ ++ cc_purge(cc); ++ thread_mark(cc); ++} ++ ++static void ++thread_free(th) ++ rb_thread_t th; ++{ ++ stack_free(th); + if (th->locals) st_free_table(th->locals); + if (th->status != THREAD_KILLED) { + if (th->prev) th->prev->next = th->next; +@@ -10511,7 +10552,7 @@ + rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)", + rb_obj_classname(data)); + } +- return (rb_thread_t)RDATA(data)->data; ++ return THREAD_DATA(data); + } + + static VALUE rb_thread_raise _((int, VALUE*, rb_thread_t)); +@@ -10782,16 +10823,6 @@ + } + + static void +-rb_thread_die(th) +- rb_thread_t th; +-{ +- th->thgroup = 0; +- th->status = THREAD_KILLED; +- if (th->stk_ptr) free(th->stk_ptr); +- th->stk_ptr = 0; +-} +- +-static void + rb_thread_remove(th) + rb_thread_t th; + { +@@ -11454,7 +11485,7 @@ + { + VALUE limit; + double delay = DELAY_INFTY; +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + rb_scan_args(argc, argv, "01", &limit); + if (!NIL_P(limit)) delay = rb_num2dbl(limit); +@@ -11566,7 +11597,7 @@ + rb_thread_wakeup_alive(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (th->status == THREAD_KILLED) + return Qnil; +@@ -11641,7 +11672,7 @@ + rb_thread_kill(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + rb_kill_thread(th, 0); + return thread; +@@ -11665,7 +11696,7 @@ + rb_thread_kill_bang(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + rb_kill_thread(th, THREAD_NO_ENSURE); + return thread; + } +@@ -11837,7 +11868,7 @@ + rb_thread_priority(thread) + VALUE thread; + { +- return INT2NUM(rb_thread_check(thread)->priority); ++ return INT2NUM(THREAD_DATA(thread)->priority); + } + + +@@ -11871,7 +11902,7 @@ + rb_thread_t th; + + rb_secure(4); +- th = rb_thread_check(thread); ++ th = THREAD_DATA(thread); + + th->priority = NUM2INT(prio); + rb_thread_schedule(); +@@ -11897,7 +11928,7 @@ + { + rb_thread_t th; + +- th = rb_thread_check(thread); ++ th = THREAD_DATA(thread); + if (th == curr_thread) { + return INT2NUM(ruby_safe_level); + } +@@ -11974,7 +12005,7 @@ + rb_thread_abort_exc(thread) + VALUE thread; + { +- return rb_thread_check(thread)->abort?Qtrue:Qfalse; ++ return THREAD_DATA(thread)->abort?Qtrue:Qfalse; + } + + +@@ -11992,7 +12023,7 @@ + VALUE thread, val; + { + rb_secure(4); +- rb_thread_check(thread)->abort = RTEST(val); ++ THREAD_DATA(thread)->abort = RTEST(val); + return val; + } + +@@ -12011,7 +12042,7 @@ + rb_thread_group(thread) + VALUE thread; + { +- VALUE group = rb_thread_check(thread)->thgroup; ++ VALUE group = THREAD_DATA(thread)->thgroup; + if (!group) { + group = Qnil; + } +@@ -12397,7 +12428,7 @@ + if (!rb_block_given_p()) { + rb_raise(rb_eThreadError, "must be called with a block"); + } +- th = rb_thread_check(thread); ++ th = THREAD_DATA(thread); + if (th->stk_max) { + NODE *node = th->node; + if (!node) { +@@ -12446,7 +12477,7 @@ + rb_thread_value(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + while (!rb_thread_join(th, DELAY_INFTY)); + +@@ -12481,7 +12512,7 @@ + rb_thread_status(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (rb_thread_dead(th)) { + if (!NIL_P(th->errinfo) && (th->flags & RAISED_EXCEPTION)) +@@ -12509,7 +12540,7 @@ + rb_thread_alive_p(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (rb_thread_dead(th)) return Qfalse; + return Qtrue; +@@ -12532,7 +12563,7 @@ + rb_thread_stop_p(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (rb_thread_dead(th)) return Qtrue; + if (th->status == THREAD_STOPPED) return Qtrue; +@@ -12766,7 +12797,7 @@ + VALUE *argv; + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (ruby_safe_level > th->safe) { + rb_secure(4); +@@ -12783,7 +12814,7 @@ + rb_thread_t th; + VALUE val; + +- th = rb_thread_check(thread); ++ th = THREAD_DATA(thread); + if (ruby_safe_level >= 4 && th != curr_thread) { + rb_raise(rb_eSecurityError, "Insecure: thread locals"); + } +@@ -12829,7 +12860,7 @@ + ID id; + VALUE val; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (ruby_safe_level >= 4 && th != curr_thread) { + rb_raise(rb_eSecurityError, "Insecure: can't modify thread locals"); +@@ -12882,7 +12913,7 @@ + rb_thread_key_p(thread, id) + VALUE thread, id; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + + if (!th->locals) return Qfalse; + if (st_lookup(th->locals, rb_to_id(id), 0)) +@@ -12918,7 +12949,7 @@ + rb_thread_keys(thread) + VALUE thread; + { +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + VALUE ary = rb_ary_new(); + + if (th->locals) { +@@ -12939,7 +12970,7 @@ + VALUE thread; + { + const char *cname = rb_obj_classname(thread); +- rb_thread_t th = rb_thread_check(thread); ++ rb_thread_t th = THREAD_DATA(thread); + const char *status = thread_status_name(th->status); + VALUE str; + size_t len = strlen(cname)+7+16+9+1; +@@ -13044,14 +13075,15 @@ + struct RVarmap *vars; + + THREAD_ALLOC(th); +- cont = Data_Wrap_Struct(rb_cCont, thread_mark, thread_free, th); ++ /* must finish th initialization before any possible gc */ ++ th->thread = curr_thread->thread; /* brent@mbari.org */ ++ th->thgroup = cont_protect; ++ cont = Data_Wrap_Struct(rb_cCont, cc_mark, thread_free, th); + + scope_dup(ruby_scope); + for (tag=prot_tag; tag; tag=tag->prev) { + scope_dup(tag->scope); + } +- th->thread = curr_thread->thread; +- th->thgroup = cont_protect; + + for (vars = ruby_dyna_vars; vars; vars = vars->next) { + if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; +@@ -13088,7 +13120,7 @@ + VALUE *argv; + VALUE cont; + { +- rb_thread_t th = rb_thread_check(cont); ++ rb_thread_t th = THREAD_DATA(cont); + + if (th->thread != curr_thread->thread) { + rb_raise(rb_eRuntimeError, "continuation called across threads"); +@@ -13112,6 +13144,30 @@ + return Qnil; + } + ++ ++/* ++ * call-seq: ++ * cont.thread ++ * ++ * Returns the thread on which this continuation can be called ++ * (or nil if that thread has died) ++ * ++ * t = Thread.new {callcc{|c| $x=c}; sleep 5} ++ * sleep 1 ++ * $x.thread #=> t ++ * sleep 10 ++ * $x.thread #=> nil ++ */ ++static VALUE ++rb_cont_thread(cont) ++ VALUE cont; ++{ ++ rb_thread_t th = THREAD_DATA(cont); ++ cc_purge(th); ++ return th->thread; ++} ++ ++ + struct thgroup { + int enclosed; + VALUE group; +@@ -13264,10 +13320,6 @@ + + rb_secure(4); + th = rb_thread_check(thread); +- if (!th->next || !th->prev) { +- rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)", +- rb_obj_classname(thread)); +- } + + if (OBJ_FROZEN(group)) { + rb_raise(rb_eThreadError, "can't move to the frozen thread group"); +@@ -13469,6 +13521,7 @@ + rb_undef_method(CLASS_OF(rb_cCont), "new"); + rb_define_method(rb_cCont, "call", rb_cont_call, -1); + rb_define_method(rb_cCont, "[]", rb_cont_call, -1); ++ rb_define_method(rb_cCont, "thread", rb_cont_thread, 0); + rb_define_global_function("callcc", rb_callcc, 0); + rb_global_variable(&cont_protect); + +diff -ru ruby-1.8.7-p72/version.h ruby-1.8.7-mbari/version.h +--- ruby-1.8.7-p72/version.h 2008-08-10 17:37:21.000000000 -0700 ++++ ruby-1.8.7-mbari/version.h 2008-12-09 00:40:58.000000000 -0800 +@@ -1,15 +1,15 @@ + #define RUBY_VERSION "1.8.7" +-#define RUBY_RELEASE_DATE "2008-08-11" ++#define RUBY_RELEASE_DATE "2008-12-09" + #define RUBY_VERSION_CODE 187 +-#define RUBY_RELEASE_CODE 20080811 ++#define RUBY_RELEASE_CODE 20081209 + #define RUBY_PATCHLEVEL 72 + + #define RUBY_VERSION_MAJOR 1 + #define RUBY_VERSION_MINOR 8 + #define RUBY_VERSION_TEENY 7 + #define RUBY_RELEASE_YEAR 2008 +-#define RUBY_RELEASE_MONTH 8 +-#define RUBY_RELEASE_DAY 11 ++#define RUBY_RELEASE_MONTH 12 ++#define RUBY_RELEASE_DAY 9 + + #ifdef RUBY_EXTERN + RUBY_EXTERN const char ruby_version[]; +@@ -25,7 +25,7 @@ + #define RUBY_BIRTH_MONTH 2 + #define RUBY_BIRTH_DAY 24 + +-#define RUBY_RELEASE_STR "patchlevel" ++#define RUBY_RELEASE_STR "MBARI 1 on patchlevel" + #define RUBY_RELEASE_NUM RUBY_PATCHLEVEL + + diff --git a/patches/ruby/1.8.7/p72/mbari-2.patch b/patches/ruby/1.8.7/p72/mbari-2.patch new file mode 100644 index 0000000000..6e5606088b --- /dev/null +++ b/patches/ruby/1.8.7/p72/mbari-2.patch @@ -0,0 +1,296 @@ +diff -rux '*.o' ruby-1.8.7-p72/ChangeLog ruby-1.8.7-mbari/ChangeLog +--- ruby-1.8.7-p72/ChangeLog 2008-12-12 21:32:52.000000000 -0800 ++++ ruby-1.8.7-mbari/ChangeLog 2008-12-12 21:58:04.000000000 -0800 +@@ -1,3 +1,14 @@ ++Tue Dec 12 6:11:36 2008 Brent Roman ++ ++ * eval.c: exclude other thread's stack frames from current one ++ ++ * gc.c: STACK_LENGTH macro takes start parameter ++ ++ * node.h: added stk_start pointer to ruby thread struct ++ ++ * intern.h: stack_length takes base pointer as parameter ++ ++ + Tue Dec 9 8:11:36 2008 Brent Roman + + * eval.c: added Continuation.thread method +diff -rux '*.o' ruby-1.8.7-p72/eval.c ruby-1.8.7-mbari/eval.c +--- ruby-1.8.7-p72/eval.c 2008-12-12 21:32:52.000000000 -0800 ++++ ruby-1.8.7-mbari/eval.c 2008-12-12 22:34:34.000000000 -0800 +@@ -3,7 +3,7 @@ + eval.c - + + $Author: brent $ +- $Date: 2008/12/11 04:42:40 $ ++ $Date: 2008/12/13 06:34:34 $ + created at: Thu Jun 10 14:22:17 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -5141,6 +5141,7 @@ + tt->retval = result; + JUMP_TAG(TAG_BREAK); + } ++ if (tt->tag == PROT_THREAD) break; + tt = tt->prev; + } + proc_jump_error(TAG_BREAK, result); +@@ -6572,6 +6573,7 @@ + + scope_dup(ruby_scope); + for (tag=prot_tag; tag; tag=tag->prev) { ++ if (tag->tag == PROT_THREAD) break; + scope_dup(tag->scope); + } + for (vars = ruby_dyna_vars; vars; vars = vars->next) { +@@ -10367,14 +10369,19 @@ + return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6; + } + +-#define STACK(addr) (th->stk_pos<(VALUE*)(addr) && (VALUE*)(addr)stk_pos+th->stk_len) +-#define ADJ(addr) (void*)(STACK(addr)?(((VALUE*)(addr)-th->stk_pos)+th->stk_ptr):(VALUE*)(addr)) ++ ++#define ADJ(addr) \ ++ if ((size_t)((void *)addr - stkBase) < stkSize) addr=(void *)addr + stkShift ++ + static void + thread_mark(th) + rb_thread_t th; + { + struct FRAME *frame; + struct BLOCK *block; ++ void *stkBase; ++ ptrdiff_t stkShift; ++ size_t stkSize; + + rb_gc_mark(th->result); + rb_gc_mark(th->thread); +@@ -10409,15 +10416,26 @@ + } + #endif + } ++ ++ stkBase = (void *)th->stk_start; ++ stkSize = th->stk_len * sizeof(VALUE); ++#if STACK_GROW_DIRECTION == 0 ++ if ((VALUE *)&th < rb_gc_stack_start) ++#endif ++#if STACK_GROW_DIRECTION <= 0 ++ stkBase -= stkSize; ++#endif ++ stkShift = (void *)th->stk_ptr - stkBase; ++ + frame = th->frame; + while (frame && frame != top_frame) { +- frame = ADJ(frame); ++ ADJ(frame); + rb_gc_mark_frame(frame); + if (frame->tmp) { + struct FRAME *tmp = frame->tmp; + + while (tmp && tmp != top_frame) { +- tmp = ADJ(tmp); ++ ADJ(tmp); + rb_gc_mark_frame(tmp); + tmp = tmp->prev; + } +@@ -10426,7 +10444,7 @@ + } + block = th->block; + while (block) { +- block = ADJ(block); ++ ADJ(block); + rb_gc_mark_frame(&block->frame); + block = block->prev; + } +@@ -10579,13 +10597,10 @@ + rb_thread_save_context(th) + rb_thread_t th; + { +- VALUE *pos; + int len; + static VALUE tval; + +- len = ruby_stack_length(&pos); +- th->stk_len = 0; +- th->stk_pos = pos; ++ len = ruby_stack_length(th->stk_start,&th->stk_pos); + if (len > th->stk_max) { + VALUE *ptr = realloc(th->stk_ptr, sizeof(VALUE) * len); + if (!ptr) rb_memerror(); +@@ -12065,6 +12080,7 @@ + th->result = 0;\ + th->flags = 0;\ + \ ++ th->stk_start = rb_gc_stack_start;\ + th->stk_ptr = 0;\ + th->stk_len = 0;\ + th->stk_max = 0;\ +@@ -12234,6 +12250,16 @@ + "can't start a new thread (frozen ThreadGroup)"); + } + ++ ++ th->stk_start = /* establish start of new thread's stack */ ++#if STACK_GROW_DIRECTION > 0 ++ (VALUE *)ruby_frame; ++#elif STACK_GROW_DIRECTION < 0 ++ (VALUE *)(ruby_frame+1); ++#else ++ (VALUE *)(ruby_frame+((VALUE *)(&arg)prev = top_frame; /* hide parent thread's frames */ ++ ruby_frame->tmp = 0; + curr_thread = th; + th->result = (*fn)(arg, th); + } +@@ -12388,9 +12416,6 @@ + VALUE klass; + { + rb_thread_t th = rb_thread_alloc(klass); +- volatile VALUE *pos; +- +- pos = th->stk_pos; + rb_obj_call_init(th->thread, argc, argv); + if (th->stk_pos == 0) { + rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'", +@@ -13082,6 +13107,7 @@ + + scope_dup(ruby_scope); + for (tag=prot_tag; tag; tag=tag->prev) { ++ if (tag->tag == PROT_THREAD) break; + scope_dup(tag->scope); + } + +diff -rux '*.o' ruby-1.8.7-p72/gc.c ruby-1.8.7-mbari/gc.c +--- ruby-1.8.7-p72/gc.c 2008-08-03 20:24:26.000000000 -0700 ++++ ruby-1.8.7-mbari/gc.c 2008-12-12 21:47:46.000000000 -0800 +@@ -2,8 +2,8 @@ + + gc.c - + +- $Author: shyouhei $ +- $Date: 2008-08-04 12:24:26 +0900 (Mon, 04 Aug 2008) $ ++ $Author: brent $ ++ $Date: 2008/12/13 05:47:46 $ + created at: Tue Oct 5 09:44:46 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -506,12 +506,12 @@ + # define STACK_END (stack_end) + #endif + #if STACK_GROW_DIRECTION < 0 +-# define STACK_LENGTH (rb_gc_stack_start - STACK_END) ++# define STACK_LENGTH(start) ((start) - STACK_END) + #elif STACK_GROW_DIRECTION > 0 +-# define STACK_LENGTH (STACK_END - rb_gc_stack_start + 1) ++# define STACK_LENGTH(start) (STACK_END - (start) + 1) + #else +-# define STACK_LENGTH ((STACK_END < rb_gc_stack_start) ? rb_gc_stack_start - STACK_END\ +- : STACK_END - rb_gc_stack_start + 1) ++# define STACK_LENGTH(start) ((STACK_END < (start)) ? (start) - STACK_END\ ++ : STACK_END - (start) + 1) + #endif + #if STACK_GROW_DIRECTION > 0 + # define STACK_UPPER(x, a, b) a +@@ -536,16 +536,16 @@ + + #define CHECK_STACK(ret) do {\ + SET_STACK_END;\ +- (ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\ ++ (ret) = (STACK_LENGTH(rb_gc_stack_start) > STACK_LEVEL_MAX + GC_WATER_MARK);\ + } while (0) + + int +-ruby_stack_length(p) +- VALUE **p; ++ruby_stack_length(start, base) ++ VALUE *start, **base; + { + SET_STACK_END; +- if (p) *p = STACK_UPPER(STACK_END, rb_gc_stack_start, STACK_END); +- return STACK_LENGTH; ++ if (base) *base = STACK_UPPER(STACK_END, start, STACK_END); ++ return STACK_LENGTH(start); + } + + int +diff -rux '*.o' ruby-1.8.7-p72/intern.h ruby-1.8.7-mbari/intern.h +--- ruby-1.8.7-p72/intern.h 2008-07-06 20:29:28.000000000 -0700 ++++ ruby-1.8.7-mbari/intern.h 2008-12-12 21:03:16.000000000 -0800 +@@ -251,7 +251,7 @@ + /* gc.c */ + NORETURN(void rb_memerror __((void))); + int ruby_stack_check _((void)); +-int ruby_stack_length _((VALUE**)); ++int ruby_stack_length _((VALUE *,VALUE**)); + int rb_during_gc _((void)); + char *rb_source_filename _((const char*)); + void rb_gc_mark_locations _((VALUE*, VALUE*)); +diff -rux '*.o' ruby-1.8.7-p72/node.h ruby-1.8.7-mbari/node.h +--- ruby-1.8.7-p72/node.h 2008-07-06 23:17:24.000000000 -0700 ++++ ruby-1.8.7-mbari/node.h 2008-12-12 21:02:23.000000000 -0800 +@@ -2,8 +2,8 @@ + + node.h - + +- $Author: shyouhei $ +- $Date: 2008-07-07 15:17:24 +0900 (Mon, 07 Jul 2008) $ ++ $Author: brent $ ++ $Date: 2008/12/13 05:02:23 $ + created at: Fri May 28 15:14:02 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -409,10 +409,8 @@ + + VALUE result; + +- long stk_len; +- long stk_max; +- VALUE *stk_ptr; +- VALUE *stk_pos; ++ long stk_len, stk_max; ++ VALUE *stk_ptr, *stk_pos, *stk_start; + #ifdef __ia64 + long bstr_len; + long bstr_max; +diff -rux '*.o' ruby-1.8.7-p72/version.h ruby-1.8.7-mbari/version.h +--- ruby-1.8.7-p72/version.h 2008-12-12 21:32:52.000000000 -0800 ++++ ruby-1.8.7-mbari/version.h 2008-12-12 21:31:44.000000000 -0800 +@@ -1,7 +1,7 @@ + #define RUBY_VERSION "1.8.7" +-#define RUBY_RELEASE_DATE "2008-12-09" ++#define RUBY_RELEASE_DATE "2008-12-12" + #define RUBY_VERSION_CODE 187 +-#define RUBY_RELEASE_CODE 20081209 ++#define RUBY_RELEASE_CODE 20081212 + #define RUBY_PATCHLEVEL 72 + + #define RUBY_VERSION_MAJOR 1 +@@ -9,7 +9,7 @@ + #define RUBY_VERSION_TEENY 7 + #define RUBY_RELEASE_YEAR 2008 + #define RUBY_RELEASE_MONTH 12 +-#define RUBY_RELEASE_DAY 9 ++#define RUBY_RELEASE_DAY 12 + + #ifdef RUBY_EXTERN + RUBY_EXTERN const char ruby_version[]; +@@ -25,7 +25,7 @@ + #define RUBY_BIRTH_MONTH 2 + #define RUBY_BIRTH_DAY 24 + +-#define RUBY_RELEASE_STR "MBARI 1 on patchlevel" ++#define RUBY_RELEASE_STR "MBARI 2 on patchlevel" + #define RUBY_RELEASE_NUM RUBY_PATCHLEVEL + + diff --git a/patches/ruby/1.8.7/p72/mbari-3.patch b/patches/ruby/1.8.7/p72/mbari-3.patch new file mode 100644 index 0000000000..4beba34818 --- /dev/null +++ b/patches/ruby/1.8.7/p72/mbari-3.patch @@ -0,0 +1,473 @@ +diff -rux '*.o' ruby-1.8.7-p72/ChangeLog ruby-1.8.7-mbari/ChangeLog +--- ruby-1.8.7-p72/ChangeLog 2008-12-13 23:32:29.000000000 -0800 ++++ ruby-1.8.7-mbari/ChangeLog 2008-12-13 23:17:30.000000000 -0800 +@@ -1,3 +1,18 @@ ++Tue Dec 13 6:10:36 2008 Brent Roman ++ ++ * eval.c: update stack extent just before and after every setjmp ++ ++ * gc.c: replaced rb_gc_stress with gc_getlimit and setlimit ++ update stack extent after every xmalloc and xrealloc ++ export rb_gc_stack_grow_direction if not known at compile time ++ removed dynamic adjustment of malloc_limit ++ removed workaround for obsolete gcc 2.7.2.3 bug ++ ++ * signal.h: don't try to clear stress after segsegv. It's a too late. ++ ++ * rubysig.h: CHECK_INTS clears ghost references off stack ++ ++ + Tue Dec 12 6:11:36 2008 Brent Roman + + * eval.c: exclude other thread's stack frames from current one +diff -rux '*.o' ruby-1.8.7-p72/eval.c ruby-1.8.7-mbari/eval.c +--- ruby-1.8.7-p72/eval.c 2008-12-13 23:32:29.000000000 -0800 ++++ ruby-1.8.7-mbari/eval.c 2008-12-13 23:23:06.000000000 -0800 +@@ -3,7 +3,7 @@ + eval.c - + + $Author: brent $ +- $Date: 2008/12/13 06:34:34 $ ++ $Date: 2008/12/14 07:23:06 $ + created at: Thu Jun 10 14:22:17 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -1027,7 +1027,14 @@ + #define PROT_LAMBDA INT2FIX(2) /* 5 */ + #define PROT_YIELD INT2FIX(3) /* 7 */ + + #define EXEC_TAG() ruby_setjmp(((void)0), prot_tag->buf) ++ ++static inline ++int up_stk_extent(int status) ++{ ++ rb_gc_update_stack_extent(); ++ return status; ++} + + #define JUMP_TAG(st) do { \ + ruby_frame = prot_tag->frame; \ +@@ -10419,7 +10426,7 @@ + stkBase = (void *)th->stk_start; + stkSize = th->stk_len * sizeof(VALUE); + #if STACK_GROW_DIRECTION == 0 +- if ((VALUE *)&th < rb_gc_stack_start) ++ if (rb_gc_stack_grow_direction < 0) + #endif + #if STACK_GROW_DIRECTION <= 0 + stkBase -= stkSize; +@@ -10697,8 +10704,8 @@ + return 1; + } + +-#define THREAD_SAVE_CONTEXT(th) \ +- (rb_thread_switch(ruby_setjmp(rb_thread_save_context(th), (th)->context))) ++#define THREAD_SAVE_CONTEXT(th) (rb_thread_switch(up_stk_extent( \ ++ ruby_setjmp(rb_thread_save_context(th), (th)->context)))) + + NORETURN(static void rb_thread_restore_context _((rb_thread_t,int))); + NORETURN(NOINLINE(static void rb_thread_restore_context_0(rb_thread_t,int,void*))); +diff -rux '*.o' ruby-1.8.7-p72/gc.c ruby-1.8.7-mbari/gc.c +--- ruby-1.8.7-p72/gc.c 2008-12-13 23:32:29.000000000 -0800 ++++ ruby-1.8.7-mbari/gc.c 2008-12-13 23:23:34.000000000 -0800 +@@ -3,7 +3,7 @@ + gc.c - + + $Author: brent $ +- $Date: 2008/12/13 05:47:46 $ ++ $Date: 2008/12/14 07:23:34 $ + created at: Tue Oct 5 09:44:46 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -70,13 +70,66 @@ + #endif + #endif + +-static unsigned long malloc_increase = 0; ++ ++size_t rb_gc_malloc_increase = 0; ++#define malloc_increase rb_gc_malloc_increase + static unsigned long malloc_limit = GC_MALLOC_LIMIT; ++size_t rb_gc_malloc_limit = GC_MALLOC_LIMIT-GC_MALLOC_LIMIT/8; ++ ++/* ++ * call-seq: ++ * GC.limit => increase limit in bytes ++ * ++ * Get the # of bytes that may be allocated before triggering ++ * a mark and sweep by the garbarge collector to reclaim unused storage. ++ * ++ */ ++static VALUE gc_getlimit(VALUE mod) ++{ ++ return ULONG2NUM(malloc_limit); ++} ++ ++/* ++ * call-seq: ++ * GC.limit= => updated increase limit in bytes ++ * ++ * Set the # of bytes that may be allocated before triggering ++ * a mark and sweep by the garbarge collector to reclaim unused storage. ++ * Attempts to set the GC.limit= less than 0 will be ignored. ++ * ++ * GC.limit=5000000 #=> 5000000 ++ * GC.limit #=> 5000000 ++ * GC.limit=-50 #=> 5000000 ++ * GC.limit=0 #=> 0 ++ * ++ */ ++static VALUE gc_setlimit(VALUE mod, VALUE newLimit) ++{ ++ long limit = NUM2LONG(newLimit); ++ if (limit < 0) return gc_getlimit(mod); ++ malloc_limit = limit; ++ rb_gc_malloc_limit = malloc_limit - malloc_limit/8; ++ return newLimit; ++} ++ ++ ++/* ++ * call-seq: ++ * GC.increase ++ * ++ * Get # of bytes that have been allocated since the last mark & sweep ++ * ++ */ ++static VALUE gc_increase(VALUE mod) ++{ ++ return ULONG2NUM(malloc_increase); ++} ++ ++ + static void run_final(); + static VALUE nomem_error; + static void garbage_collect(); + +-int ruby_gc_stress = 0; + + NORETURN(void rb_exc_jump _((VALUE))); + +@@ -97,40 +150,6 @@ + rb_exc_raise(nomem_error); + } + +-/* +- * call-seq: +- * GC.stress => true or false +- * +- * returns current status of GC stress mode. +- */ +- +-static VALUE +-gc_stress_get(self) +- VALUE self; +-{ +- return ruby_gc_stress ? Qtrue : Qfalse; +-} +- +-/* +- * call-seq: +- * GC.stress = bool => bool +- * +- * updates GC stress mode. +- * +- * When GC.stress = true, GC is invoked for all GC opportunity: +- * all memory and object allocation. +- * +- * Since it makes Ruby very slow, it is only for debugging. +- */ +- +-static VALUE +-gc_stress_set(self, bool) +- VALUE self, bool; +-{ +- rb_secure(2); +- ruby_gc_stress = RTEST(bool); +- return bool; +-} + + void * + ruby_xmalloc(size) +@@ -143,8 +162,9 @@ + } + if (size == 0) size = 1; + +- if (ruby_gc_stress || (malloc_increase+size) > malloc_limit) { ++ if ((malloc_increase+=size) > malloc_limit) { + garbage_collect(); ++ malloc_increase = size; + } + RUBY_CRITICAL(mem = malloc(size)); + if (!mem) { +@@ -154,8 +174,7 @@ + rb_memerror(); + } + } +- malloc_increase += size; +- ++ rb_gc_update_stack_extent(); + return mem; + } + +@@ -183,7 +202,10 @@ + } + if (!ptr) return xmalloc(size); + if (size == 0) size = 1; +- if (ruby_gc_stress) garbage_collect(); ++ if ((malloc_increase+=size) > malloc_limit) { ++ garbage_collect(); ++ malloc_increase = size; ++ } + RUBY_CRITICAL(mem = realloc(ptr, size)); + if (!mem) { + garbage_collect(); +@@ -192,8 +214,7 @@ + rb_memerror(); + } + } +- malloc_increase += size; +- ++ rb_gc_update_stack_extent(); + return mem; + } + +@@ -433,7 +454,7 @@ + if (during_gc) + rb_bug("object allocation during garbage collection phase"); + +- if (ruby_gc_stress || !freelist) garbage_collect(); ++ if (!malloc_limit || !freelist) garbage_collect(); + + obj = (VALUE)freelist; + freelist = freelist->as.free.next; +@@ -468,6 +489,9 @@ + VALUE *rb_gc_register_stack_start = 0; + #endif + ++VALUE *rb_gc_stack_end = (VALUE *)STACK_GROW_DIRECTION; ++ ++ + #ifdef DJGPP + /* set stack size (http://www.delorie.com/djgpp/v2faq/faq15_9.html) */ + unsigned int _stklen = 0x180000; /* 1.5 kB */ +@@ -518,18 +542,15 @@ + #elif STACK_GROW_DIRECTION < 0 + # define STACK_UPPER(x, a, b) b + #else +-static int grow_direction; ++int rb_gc_stack_grow_direction; + static int + stack_grow_direction(addr) + VALUE *addr; + { + SET_STACK_END; +- +- if (STACK_END > addr) return grow_direction = 1; +- return grow_direction = -1; ++ return rb_gc_stack_grow_direction = STACK_END > addr ? 1 : -1; + } +-# define stack_growup_p(x) ((grow_direction ? grow_direction : stack_grow_direction(x)) > 0) +-# define STACK_UPPER(x, a, b) (stack_growup_p(x) ? a : b) ++# define STACK_UPPER(x, a, b) (rb_gc_stack_grow_direction > 0 ? a : b) + #endif + + #define GC_WATER_MARK 512 +@@ -1097,13 +1118,12 @@ + RVALUE *p, *pend, *final_list; + int freed = 0; + int i; +- unsigned long live = 0; + unsigned long free_min = 0; + + for (i = 0; i < heaps_used; i++) { + free_min += heaps[i].limit; + } +- free_min = free_min * 0.2; ++ free_min /= 5; + if (free_min < FREE_MIN) + free_min = FREE_MIN; + +@@ -1157,7 +1177,6 @@ + } + else { + RBASIC(p)->flags &= ~FL_MARK; +- live++; + } + p++; + } +@@ -1174,10 +1193,6 @@ + freed += n; + } + } +- if (malloc_increase > malloc_limit) { +- malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed); +- if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT; +- } + malloc_increase = 0; + if (freed < free_min) { + add_heap(); +@@ -1373,7 +1388,7 @@ + garbage_collect() + { + struct gc_list *list; +- struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */ ++ struct FRAME * frame; + jmp_buf save_regs_gc_mark; + SET_STACK_END; + +@@ -1421,7 +1436,7 @@ + #elif STACK_GROW_DIRECTION > 0 + rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1); + #else +- if ((VALUE*)STACK_END < rb_gc_stack_start) ++ if (rb_gc_stack_grow_direction < 0) + rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start); + else + rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1); +@@ -2086,12 +2101,16 @@ + { + VALUE rb_mObSpace; + ++#if !STACK_GROW_DIRECTION ++ rb_gc_stack_end = stack_grow_direction(&rb_mObSpace); ++#endif + rb_mGC = rb_define_module("GC"); + rb_define_singleton_method(rb_mGC, "start", rb_gc_start, 0); + rb_define_singleton_method(rb_mGC, "enable", rb_gc_enable, 0); + rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0); +- rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0); +- rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1); ++ rb_define_singleton_method(rb_mGC, "limit", gc_getlimit, 0); ++ rb_define_singleton_method(rb_mGC, "limit=", gc_setlimit, 1); ++ rb_define_singleton_method(rb_mGC, "increase", gc_increase, 0); + rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0); + + rb_mObSpace = rb_define_module("ObjectSpace"); +diff -rux '*.o' ruby-1.8.7-p72/rubysig.h ruby-1.8.7-mbari/rubysig.h +--- ruby-1.8.7-p72/rubysig.h 2007-02-12 15:01:19.000000000 -0800 ++++ ruby-1.8.7-mbari/rubysig.h 2008-12-13 23:24:10.000000000 -0800 +@@ -2,8 +2,8 @@ + + rubysig.h - + +- $Author: shyouhei $ +- $Date: 2007-02-13 08:01:19 +0900 (Tue, 13 Feb 2007) $ ++ $Author: brent $ ++ $Date: 2008/12/14 07:24:10 $ + created at: Wed Aug 16 01:15:38 JST 1995 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -81,7 +81,50 @@ + void rb_thread_schedule _((void)); + #if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE) + RUBY_EXTERN int rb_thread_pending; ++ ++EXTERN size_t rb_gc_malloc_increase; ++EXTERN size_t rb_gc_malloc_limit; ++EXTERN VALUE *rb_gc_stack_end; ++EXTERN int *rb_gc_stack_grow_direction; /* -1 for down or 1 for up */ ++#define __stack_zero_up(end,sp) while (end >= ++sp) *sp=0 ++#define __stack_grown_up (rb_gc_stack_end > (VALUE *)alloca(0)) ++#define __stack_zero_down(end,sp) while (end <= --sp) *sp=0 ++#define __stack_grown_down (rb_gc_stack_end < (VALUE *)alloca(0)) ++ ++#if STACK_GROW_DIRECTION > 0 ++#define __stack_zero(end,sp) __stack_zero_up(end,sp) ++#define __stack_grown __stack_grown_up ++#elif STACK_GROW_DIRECTION < 0 ++#define __stack_zero(end,sp) __stack_zero_down(end,sp) ++#define __stack_grown __stack_grown_down ++#else /* limp along if stack direction can't be determined at compile time */ ++#define __stack_zero(end,sp) if (rb_gc_stack_grow_direction<0) \ ++ __stack_zero_down(end,sp); else __stack_zero_up(end,sp); ++#define __stack_grown \ ++ (rb_gc_stack_grow_direction<0 ? __stack_grown_down : __stack_grown_up) ++#endif ++ ++/* ++ zero the memory that was (recently) part of the stack ++ but is no longer. Invoke when stack is deep to mark its extent ++ and when it is shallow to wipe it ++*/ ++#define rb_gc_wipe_stack() { \ ++ VALUE *sp = alloca(0); \ ++ VALUE *end = rb_gc_stack_end; \ ++ rb_gc_stack_end = sp; \ ++ __stack_zero(end, sp); \ ++} ++ ++/* ++ Update our record of maximum stack extent without zeroing unused stack ++*/ ++#define rb_gc_update_stack_extent() \ ++ if __stack_grown rb_gc_stack_end = alloca(0); ++ ++ + # define CHECK_INTS do {\ ++ rb_gc_wipe_stack(); \ + if (!(rb_prohibit_interrupt || rb_thread_critical)) {\ + if (rb_thread_pending) rb_thread_schedule();\ + if (rb_trap_pending) rb_trap_exec();\ +@@ -92,6 +135,7 @@ + RUBY_EXTERN int rb_thread_tick; + #define THREAD_TICK 500 + #define CHECK_INTS do {\ ++ rb_gc_wipe_stack(); \ + if (!(rb_prohibit_interrupt || rb_thread_critical)) {\ + if (rb_thread_tick-- <= 0) {\ + rb_thread_tick = THREAD_TICK;\ +diff -rux '*.o' ruby-1.8.7-p72/signal.c ruby-1.8.7-mbari/signal.c +--- ruby-1.8.7-p72/signal.c 2008-06-06 03:39:57.000000000 -0700 ++++ ruby-1.8.7-mbari/signal.c 2008-12-13 23:24:39.000000000 -0800 +@@ -2,8 +2,8 @@ + + signal.c - + +- $Author: knu $ +- $Date: 2008-06-06 19:39:57 +0900 (Fri, 06 Jun 2008) $ ++ $Author: brent $ ++ $Date: 2008/12/14 07:24:39 $ + created at: Tue Dec 20 10:13:44 JST 1994 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -629,8 +629,6 @@ + } + #endif + +- extern int ruby_gc_stress; +- ruby_gc_stress = 0; + rb_bug("Segmentation fault"); + } + #endif +diff -rux '*.o' ruby-1.8.7-p72/version.h ruby-1.8.7-mbari/version.h +--- ruby-1.8.7-p72/version.h 2008-12-13 23:32:29.000000000 -0800 ++++ ruby-1.8.7-mbari/version.h 2008-12-13 20:47:17.000000000 -0800 +@@ -1,7 +1,7 @@ + #define RUBY_VERSION "1.8.7" +-#define RUBY_RELEASE_DATE "2008-12-12" ++#define RUBY_RELEASE_DATE "2008-12-13" + #define RUBY_VERSION_CODE 187 +-#define RUBY_RELEASE_CODE 20081212 ++#define RUBY_RELEASE_CODE 20081213 + #define RUBY_PATCHLEVEL 72 + + #define RUBY_VERSION_MAJOR 1 +@@ -9,7 +9,7 @@ + #define RUBY_VERSION_TEENY 7 + #define RUBY_RELEASE_YEAR 2008 + #define RUBY_RELEASE_MONTH 12 +-#define RUBY_RELEASE_DAY 12 ++#define RUBY_RELEASE_DAY 13 + + #ifdef RUBY_EXTERN + RUBY_EXTERN const char ruby_version[]; +@@ -25,7 +25,7 @@ + #define RUBY_BIRTH_MONTH 2 + #define RUBY_BIRTH_DAY 24 + +-#define RUBY_RELEASE_STR "MBARI 2 on patchlevel" ++#define RUBY_RELEASE_STR "MBARI 3 on patchlevel" + #define RUBY_RELEASE_NUM RUBY_PATCHLEVEL + + diff --git a/patches/ruby/1.8.7/p72/mbari-4.patch b/patches/ruby/1.8.7/p72/mbari-4.patch new file mode 100644 index 0000000000..24aa642aca --- /dev/null +++ b/patches/ruby/1.8.7/p72/mbari-4.patch @@ -0,0 +1,2251 @@ +diff -rux '*.o' ruby-1.8.7-p72/ChangeLog ruby-1.8.7-mbari/ChangeLog +--- ruby-1.8.7-p72/ChangeLog 2008-12-16 00:47:25.000000000 -0800 ++++ ruby-1.8.7-mbari/ChangeLog 2008-12-16 23:06:21.000000000 -0800 +@@ -1,3 +1,11 @@ ++Tue Dec 15 9:15:36 2008 Brent Roman ++ ++ * eval.c: factored rb_eval() into many separate non-inlined ++ functions to reduce the size of its stack frame when ++ compiled with gcc. ++ Factored callcc into 2 functions. ++ ++ + Tue Dec 13 6:10:36 2008 Brent Roman + + * eval.c: update stack extent just before and after every setjmp +diff -rux '*.o' ruby-1.8.7-p72/eval.c ruby-1.8.7-mbari/eval.c +--- ruby-1.8.7-p72/eval.c 2008-12-16 00:47:25.000000000 -0800 ++++ ruby-1.8.7-mbari/eval.c 2008-12-16 23:28:08.000000000 -0800 +@@ -3,7 +3,7 @@ + eval.c - + + $Author: brent $ +- $Date: 2008/12/14 07:23:06 $ ++ $Date: 2008/12/17 07:28:08 $ + created at: Thu Jun 10 14:22:17 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -219,7 +219,7 @@ + VALUE rb_cBinding; + static VALUE proc_invoke _((VALUE,VALUE,VALUE,VALUE)); + static VALUE rb_f_binding _((VALUE)); +-static void rb_f_END _((void)); ++NOINLINE(static void rb_f_END _((void))); + static VALUE rb_f_block_given_p _((void)); + static VALUE block_pass _((VALUE,NODE*)); + +@@ -1240,12 +1240,7 @@ + if (NIL_P(ruby_errinfo)) return; + + PUSH_TAG(PROT_NONE); +- if (EXEC_TAG() == 0) { +- errat = get_backtrace(ruby_errinfo); +- } +- else { +- errat = Qnil; +- } ++ errat = EXEC_TAG() == 0 ? get_backtrace(ruby_errinfo) : Qnil; + if (EXEC_TAG()) goto error; + if (NIL_P(errat)){ + ruby_set_current_source(); +@@ -1926,8 +1921,8 @@ + return rb_const_defined(cref->nd_clss, id); + } + +-static VALUE +-ev_const_get(cref, id, self) ++NOINLINE(static VALUE ++ev_const_get(cref, id, self)) + NODE *cref; + ID id; + VALUE self; +@@ -2942,40 +2937,960 @@ + } + } + +-static VALUE +-rb_eval(self, n) +- VALUE self; +- NODE *n; ++ ++/* ++ functions factored out of rb_eval() to reduce its stack frame size ++*/ ++NOINLINE(static VALUE eval_match2(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE l = rb_eval(self,node->nd_recv); ++ VALUE r = rb_eval(self,node->nd_value); ++ return rb_reg_match(l, r); ++} ++ ++NOINLINE(static VALUE ++eval_match3(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE r = rb_eval(self,node->nd_recv); ++ VALUE l = rb_eval(self,node->nd_value); ++ return TYPE(l) == T_STRING ? rb_reg_match(r, l) : rb_funcall(l, match, 1, r); ++} ++ ++ ++NOINLINE(static void ++eval_opt_n(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ int state; ++ PUSH_TAG(PROT_LOOP); ++ switch (state = EXEC_TAG()) { ++ case 0: ++ opt_n_next: ++ while (!NIL_P(rb_gets())) { ++ opt_n_redo: ++ rb_eval(self, node->nd_body); ++ } ++ break; ++ ++ case TAG_REDO: ++ state = 0; ++ goto opt_n_redo; ++ case TAG_NEXT: ++ state = 0; ++ goto opt_n_next; ++ case TAG_BREAK: ++ state = 0; ++ default: ++ break; ++ } ++ POP_TAG(); ++ if (state) JUMP_TAG(state); ++} ++ ++ ++NOINLINE(static NODE * ++eval_when(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ do { ++ NODE *tag = node->nd_head; ++ while (tag) { ++ EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self, ++ ruby_frame->last_func, ++ ruby_frame->last_class); ++ if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) { ++ VALUE v = rb_eval(self, tag->nd_head->nd_head); ++ long i; ++ ++ if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v); ++ for (i=0; ilen; i++) { ++ if (RTEST(RARRAY(v)->ptr[i])) return node->nd_body; ++ } ++ tag = tag->nd_next; ++ continue; ++ } ++ if (RTEST(rb_eval(self, tag->nd_head))) return node->nd_body; ++ tag = tag->nd_next; ++ } ++ } while ((node = node->nd_next) && nd_type(node) == NODE_WHEN); ++ return node; ++} ++ ++ ++NOINLINE (static NODE * ++eval_case(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE val = rb_eval(self, node->nd_head); ++ node = node->nd_body; ++ while (node) { ++ NODE *tag; ++ ++ if (nd_type(node) != NODE_WHEN) break; ++ tag = node->nd_head; ++ while (tag) { ++ EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self, ++ ruby_frame->last_func, ++ ruby_frame->last_class); ++ if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) { ++ VALUE v = rb_eval(self, tag->nd_head->nd_head); ++ long i; ++ ++ if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v); ++ for (i=0; ilen; i++) { ++ if (RTEST(rb_funcall2(RARRAY(v)->ptr[i], eqq, 1, &val))) ++ return node->nd_body; ++ } ++ tag = tag->nd_next; ++ continue; ++ } ++ if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head), eqq, 1, &val))) ++ return node->nd_body; ++ tag = tag->nd_next; ++ } ++ node = node->nd_next; ++ } ++ return node; ++} ++ ++ ++NOINLINE (static VALUE ++eval_while(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ int state; ++ volatile VALUE result = Qnil; ++ PUSH_TAG(PROT_LOOP); ++ switch (state = EXEC_TAG()) { ++ case 0: ++ if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond))) ++ goto while_out; ++ do { ++ while_redo: ++ rb_eval(self, node->nd_body); ++ while_next: ++ ; ++ } while (RTEST(rb_eval(self, node->nd_cond))); ++ break; ++ ++ case TAG_REDO: ++ state = 0; ++ goto while_redo; ++ case TAG_NEXT: ++ state = 0; ++ goto while_next; ++ case TAG_BREAK: ++ if (TAG_DST()) { ++ state = 0; ++ result = prot_tag->retval; ++ } ++ /* fall through */ ++ default: ++ break; ++ } ++while_out: ++ POP_TAG(); ++ if (state) JUMP_TAG(state); ++ return result; ++} ++ ++ ++NOINLINE (static VALUE ++eval_until(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ int state; ++ volatile VALUE result = Qnil; ++ PUSH_TAG(PROT_LOOP); ++ switch (state = EXEC_TAG()) { ++ case 0: ++ if (node->nd_state && RTEST(rb_eval(self, node->nd_cond))) ++ goto until_out; ++ do { ++ until_redo: ++ rb_eval(self, node->nd_body); ++ until_next: ++ ; ++ } while (!RTEST(rb_eval(self, node->nd_cond))); ++ break; ++ ++ case TAG_REDO: ++ state = 0; ++ goto until_redo; ++ case TAG_NEXT: ++ state = 0; ++ goto until_next; ++ case TAG_BREAK: ++ if (TAG_DST()) { ++ state = 0; ++ result = prot_tag->retval; ++ } ++ /* fall through */ ++ default: ++ break; ++ } ++ until_out: ++ POP_TAG(); ++ if (state) JUMP_TAG(state); ++ return result; ++} ++ ++ ++NOINLINE (static VALUE ++eval_iter(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ int state; ++ volatile VALUE result = Qnil; ++ ++ PUSH_TAG(PROT_LOOP); ++ PUSH_BLOCK(node->nd_var, node->nd_body); ++ ++ state = EXEC_TAG(); ++ switch (state) { ++ case TAG_RETRY: ++ state = 0; /* fall thru to case 0 */ ++ case 0: ++ PUSH_ITER(ITER_PRE); ++ if (nd_type(node) == NODE_ITER) { ++ result = rb_eval(self, node->nd_iter); ++ } ++ else { ++ VALUE recv; ++ ++ _block.flags &= ~BLOCK_D_SCOPE; ++ BEGIN_CALLARGS; ++ recv = rb_eval(self, node->nd_iter); ++ END_CALLARGS; ++ ruby_current_node = node; ++ SET_CURRENT_SOURCE(); ++ result = rb_call(CLASS_OF(recv),recv,each,0,0,0,self); ++ } ++ POP_ITER(); ++ break; ++ ++ case TAG_BREAK: ++ if (TAG_DST()) { ++ result = prot_tag->retval; ++ state = 0; ++ } ++ } ++ POP_BLOCK(); ++ POP_TAG(); ++ if (state) JUMP_TAG(state); ++ return result; ++} ++ ++ ++NOINLINE (static VALUE ++eval_rescue(self, node)) ++ VALUE self; ++ NODE *node; + { +- NODE * volatile contnode = 0; +- NODE * volatile node = n; ++ volatile VALUE e_info = ruby_errinfo; ++ volatile int rescuing = 0; + int state; + volatile VALUE result = Qnil; +- st_data_t data; + +-#define RETURN(v) do { \ +- result = (v); \ +- goto finish; \ +-} while (0) ++ PUSH_TAG(PROT_NONE); ++ if ((state = EXEC_TAG()) == 0) { ++ retry_entry: ++ result = rb_eval(self, node->nd_head); ++ } ++ else if (rescuing) { ++ if (rescuing < 0) { ++ /* in rescue argument, just reraise */ ++ } ++ else if (state == TAG_RETRY) { ++ rescuing = state = 0; ++ ruby_errinfo = e_info; ++ goto retry_entry; ++ } ++ else if (state != TAG_RAISE) { ++ result = prot_tag->retval; ++ } ++ } ++ else if (state == TAG_RAISE) { ++ NODE *resq = node->nd_resq; + +- again: +- if (!node) RETURN(Qnil); ++ rescuing = -1; ++ while (resq) { ++ ruby_current_node = resq; ++ if (handle_rescue(self, resq)) { ++ state = 0; ++ rescuing = 1; ++ result = rb_eval(self, resq->nd_body); ++ break; ++ } ++ resq = resq->nd_head; /* next rescue */ ++ } ++ } ++ else { ++ result = prot_tag->retval; ++ } ++ POP_TAG(); ++ if (state != TAG_RAISE) ruby_errinfo = e_info; ++ if (state) { ++ JUMP_TAG(state); ++ } ++ /* no exception raised */ ++ if (!rescuing && node->nd_else) { /* else clause given */ ++ result = Qundef; /* caller must eval this! */ ++ } ++ return result; ++} + ++ ++NOINLINE (static VALUE ++eval_ensure(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ int state; ++ volatile VALUE result = Qnil; ++ ++ PUSH_TAG(PROT_NONE); ++ if ((state = EXEC_TAG()) == 0) { ++ result = rb_eval(self, node->nd_head); ++ } ++ POP_TAG(); ++ if (node->nd_ensr && !thread_no_ensure()) { ++ VALUE retval = prot_tag->retval; /* save retval */ ++ VALUE errinfo = ruby_errinfo; ++ ++ rb_eval(self, node->nd_ensr); ++ return_value(retval); ++ ruby_errinfo = errinfo; ++ } ++ if (state) JUMP_TAG(state); ++ return result; ++} ++ ++ ++NOINLINE (static VALUE ++eval_dot(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE beg = rb_eval(self, node->nd_beg); ++ VALUE end = rb_eval(self, node->nd_end); ++ return rb_range_new(beg, end, nd_type(node) == NODE_DOT3); ++} ++ ++ ++NOINLINE (static VALUE ++eval_flip2(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE *flip = rb_svar(node->nd_cnt); ++ if (!flip) rb_bug("unexpected local variable"); ++ if (!RTEST(*flip)) { ++ if (!RTEST(rb_eval(self, node->nd_beg))) ++ return Qfalse; ++ *flip = RTEST(rb_eval(self, node->nd_end))?Qfalse:Qtrue; ++ } ++ else if (RTEST(rb_eval(self, node->nd_end))) ++ *flip = Qfalse; ++ return Qtrue; ++} ++ ++ ++NOINLINE (static VALUE ++eval_flip3(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE *flip = rb_svar(node->nd_cnt); ++ if (!flip) rb_bug("unexpected local variable"); ++ if (!RTEST(*flip)) ++ return *flip = (RTEST(rb_eval(self, node->nd_beg)) ? Qtrue : Qfalse); ++ if (RTEST(rb_eval(self, node->nd_end))) ++ *flip = Qfalse; ++ return Qtrue; ++} ++ ++ ++NOINLINE (static VALUE ++eval_attrasgn(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE recv; ++ int argc; VALUE *argv; /* used in SETUP_ARGS */ ++ int scope; ++ TMP_PROTECT; ++ ++ BEGIN_CALLARGS; ++ if (node->nd_recv == (NODE *)1) { ++ recv = self; ++ scope = 1; ++ } ++ else { ++ recv = rb_eval(self, node->nd_recv); ++ scope = 0; ++ } ++ SETUP_ARGS(node->nd_args); ++ END_CALLARGS; ++ ++ ruby_current_node = node; ++ SET_CURRENT_SOURCE(); ++ rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,scope,self); ++ return argv[argc-1]; ++} ++ ++ ++NOINLINE (static VALUE ++eval_call(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE recv; ++ int argc; VALUE *argv; /* used in SETUP_ARGS */ ++ TMP_PROTECT; ++ ++ BEGIN_CALLARGS; ++ recv = rb_eval(self, node->nd_recv); ++ SETUP_ARGS(node->nd_args); ++ END_CALLARGS; ++ ++ ruby_current_node = node; ++ SET_CURRENT_SOURCE(); ++ return rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0,self); ++} ++ ++ ++NOINLINE (static VALUE ++eval_fcall(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ int argc; VALUE *argv; /* used in SETUP_ARGS */ ++ TMP_PROTECT; ++ ++ BEGIN_CALLARGS; ++ SETUP_ARGS(node->nd_args); ++ END_CALLARGS; ++ ++ ruby_current_node = node; ++ SET_CURRENT_SOURCE(); ++ return rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1,self); ++} ++ ++NOINLINE (static VALUE ++eval_super(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ int argc; VALUE *argv; /* used in SETUP_ARGS */ ++ TMP_PROTECT; ++ ++ if (ruby_frame->last_class == 0) { ++ if (ruby_frame->last_func) { ++ rb_name_error(ruby_frame->last_func, ++ "superclass method `%s' disabled", ++ rb_id2name(ruby_frame->orig_func)); ++ } ++ else { ++ rb_raise(rb_eNoMethodError, "super called outside of method"); ++ } ++ } ++ if (nd_type(node) == NODE_ZSUPER) { ++ argc = ruby_frame->argc; ++ if (argc && DMETHOD_P()) { ++ if (TYPE(RBASIC(ruby_scope)->klass) != T_ARRAY || ++ RARRAY(RBASIC(ruby_scope)->klass)->len != argc) { ++ rb_raise(rb_eRuntimeError, ++ "super: specify arguments explicitly"); ++ } ++ argv = RARRAY(RBASIC(ruby_scope)->klass)->ptr; ++ } ++ else if (!ruby_scope->local_vars) { ++ argc = 0; ++ argv = 0; ++ } ++ else { ++ argv = ruby_scope->local_vars + 2; ++ } ++ } ++ else { ++ BEGIN_CALLARGS; ++ SETUP_ARGS(node->nd_args); ++ END_CALLARGS; ++ ruby_current_node = node; ++ } ++ ++ SET_CURRENT_SOURCE(); ++ return rb_call_super(argc, argv); ++} ++ ++ ++NOINLINE (static VALUE ++eval_scope(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ int state; ++ volatile VALUE result = Qnil; ++ struct FRAME frame; ++ NODE *saved_cref = 0; ++ ++ frame = *ruby_frame; ++ frame.tmp = ruby_frame; ++ ruby_frame = &frame; ++ ++ PUSH_SCOPE(); ++ PUSH_TAG(PROT_NONE); ++ if (node->nd_rval) { ++ saved_cref = ruby_cref; ++ ruby_cref = (NODE*)node->nd_rval; ++ } ++ if (node->nd_tbl) { ++ VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1); ++ *vars++ = (VALUE)node; ++ ruby_scope->local_vars = vars; ++ rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]); ++ ruby_scope->local_tbl = node->nd_tbl; ++ } ++ else { ++ ruby_scope->local_vars = 0; ++ ruby_scope->local_tbl = 0; ++ } ++ if ((state = EXEC_TAG()) == 0) { ++ result = rb_eval(self, node->nd_next); ++ } ++ POP_TAG(); ++ POP_SCOPE(); ++ ruby_frame = frame.tmp; ++ if (saved_cref) ++ ruby_cref = saved_cref; ++ if (state) JUMP_TAG(state); ++ return result; ++} ++ ++NOINLINE (static VALUE ++eval_op_asgn1(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ int argc; VALUE *argv; /* used in SETUP_ARGS */ ++ VALUE recv, val, tmp; ++ NODE *rval; ++ TMP_PROTECT; ++ ++ recv = rb_eval(self, node->nd_recv); ++ rval = node->nd_args->nd_head; ++ SETUP_ARGS0(node->nd_args->nd_body, 1); ++ val = rb_funcall3(recv, aref, argc, argv); ++ switch (node->nd_mid) { ++ case 0: /* OR */ ++ if (RTEST(val)) return val; ++ val = rb_eval(self, rval); ++ break; ++ case 1: /* AND */ ++ if (!RTEST(val)) return val; ++ val = rb_eval(self, rval); ++ break; ++ default: ++ tmp = rb_eval(self, rval); ++ val = rb_funcall3(val, node->nd_mid, 1, &tmp); ++ } ++ argv[argc] = val; ++ rb_funcall2(recv, aset, argc+1, argv); ++ return val; ++} ++ ++ ++NOINLINE (static VALUE ++eval_op_asgn2(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ ID id = node->nd_next->nd_vid; ++ VALUE recv, val, tmp; ++ ++ recv = rb_eval(self, node->nd_recv); ++ val = rb_funcall3(recv, id, 0, 0); ++ switch (node->nd_next->nd_mid) { ++ case 0: /* OR */ ++ if (RTEST(val)) return val; ++ val = rb_eval(self, node->nd_value); ++ break; ++ case 1: /* AND */ ++ if (!RTEST(val)) return val; ++ val = rb_eval(self, node->nd_value); ++ break; ++ default: ++ tmp = rb_eval(self, node->nd_value); ++ val = rb_funcall3(val, node->nd_next->nd_mid, 1, &tmp); ++ } ++ ++ rb_funcall2(recv, node->nd_next->nd_aid, 1, &val); ++ return val; ++} ++ ++ ++NOINLINE (static VALUE ++eval_hash(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ NODE *list; ++ VALUE hash = rb_hash_new(); ++ VALUE key, val; ++ ++ list = node->nd_head; ++ while (list) { ++ key = rb_eval(self, list->nd_head); ++ list = list->nd_next; ++ if (list == 0) ++ rb_bug("odd number list for Hash"); ++ val = rb_eval(self, list->nd_head); ++ list = list->nd_next; ++ rb_hash_aset(hash, key, val); ++ } ++ return hash; ++} ++ ++ ++NOINLINE (static VALUE ++eval_array(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE ary; ++ long i; ++ ++ i = node->nd_alen; ++ ary = rb_ary_new2(i); ++ for (i=0;node;node=node->nd_next) { ++ RARRAY(ary)->ptr[i++] = rb_eval(self, node->nd_head); ++ RARRAY(ary)->len = i; ++ } ++ return ary; ++} ++ ++ ++NOINLINE (static VALUE ++eval_slit(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE str, str2; ++ NODE *list = node->nd_next; ++ ++ str = rb_str_new3(node->nd_lit); ++ while (list) { ++ if (list->nd_head) { ++ switch (nd_type(list->nd_head)) { ++ case NODE_STR: ++ str2 = list->nd_head->nd_lit; ++ break; ++ default: ++ str2 = rb_eval(self, list->nd_head); ++ break; ++ } ++ rb_str_append(str, str2); ++ OBJ_INFECT(str, str2); ++ } ++ list = list->nd_next; ++ } ++ switch (nd_type(node)) { ++ case NODE_DREGX: ++ return rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, ++ node->nd_cflag); ++ case NODE_DREGX_ONCE: /* regexp expand once */ ++ str2 = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, ++ node->nd_cflag); ++ nd_set_type(node, NODE_LIT); ++ return node->nd_lit = str2; ++ case NODE_LIT: ++ /* other thread may replace NODE_DREGX_ONCE to NODE_LIT */ ++ return Qundef; ++ case NODE_DXSTR: ++ return rb_funcall(self, '`', 1, str); ++ case NODE_DSYM: ++ return rb_str_intern(str); ++ } ++ return str; ++} ++ ++ ++NOINLINE (static void ++eval_defn(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ NODE *body, *defn; ++ VALUE origin = 0; ++ int noex; ++ ++ if (NIL_P(ruby_class)) { ++ rb_raise(rb_eTypeError, "no class/module to add method"); ++ } ++ if (ruby_class == rb_cObject && node->nd_mid == init) { ++ rb_warn("redefining Object#initialize may cause infinite loop"); ++ } ++ if (node->nd_mid == __id__ || node->nd_mid == __send__) { ++ rb_warn("redefining `%s' may cause serious problem", ++ rb_id2name(node->nd_mid)); ++ } ++ rb_frozen_class_p(ruby_class); ++ body = search_method(ruby_class, node->nd_mid, &origin); ++ if (body){ ++ if (RTEST(ruby_verbose) && ruby_class == origin && body->nd_cnt == 0 && body->nd_body) { ++ rb_warning("method redefined; discarding old %s", rb_id2name(node->nd_mid)); ++ } ++ } ++ ++ if (SCOPE_TEST(SCOPE_PRIVATE) || node->nd_mid == init) { ++ noex = NOEX_PRIVATE; ++ } ++ else if (SCOPE_TEST(SCOPE_PROTECTED)) { ++ noex = NOEX_PROTECTED; ++ } ++ else { ++ noex = NOEX_PUBLIC; ++ } ++ if (body && origin == ruby_class && body->nd_body == 0) { ++ noex |= NOEX_NOSUPER; ++ } ++ ++ defn = rb_copy_node_scope(node->nd_defn, ruby_cref); ++ rb_add_method(ruby_class, node->nd_mid, defn, noex); ++ if (scope_vmode == SCOPE_MODFUNC) { ++ rb_add_method(rb_singleton_class(ruby_class), ++ node->nd_mid, defn, NOEX_PUBLIC); ++ } ++} ++ ++ ++NOINLINE (static void ++eval_defs(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE recv = rb_eval(self, node->nd_recv); ++ VALUE klass; ++ NODE *body = 0, *defn; ++ st_data_t data; ++ ++ if (ruby_safe_level >= 4 && !OBJ_TAINTED(recv)) { ++ rb_raise(rb_eSecurityError, "Insecure: can't define singleton method"); ++ } ++ if (FIXNUM_P(recv) || SYMBOL_P(recv)) { ++ rb_raise(rb_eTypeError, ++ "can't define singleton method \"%s\" for %s", ++ rb_id2name(node->nd_mid), ++ rb_obj_classname(recv)); ++ } ++ ++ if (OBJ_FROZEN(recv)) rb_error_frozen("object"); ++ klass = rb_singleton_class(recv); ++ if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, &data)) { ++ body = (NODE *)data; ++ if (ruby_safe_level >= 4) { ++ rb_raise(rb_eSecurityError, "redefining method prohibited"); ++ } ++ if (RTEST(ruby_verbose)) { ++ rb_warning("redefine %s", rb_id2name(node->nd_mid)); ++ } ++ } ++ defn = rb_copy_node_scope(node->nd_defn, ruby_cref); ++ rb_add_method(klass, node->nd_mid, defn, ++ NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0)); ++} ++ ++ ++NOINLINE (static VALUE ++eval_class(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE super, klass, tmp, cbase; ++ ID cname; ++ int gen = Qfalse; ++ ++ cbase = class_prefix(self, node->nd_cpath); ++ cname = node->nd_cpath->nd_mid; ++ ++ if (NIL_P(ruby_cbase)) { ++ rb_raise(rb_eTypeError, "no outer class/module"); ++ } ++ if (node->nd_super) { ++ super = rb_eval(self, node->nd_super); ++ rb_check_inheritable(super); ++ } ++ else { ++ super = 0; ++ } ++ ++ if (rb_const_defined_at(cbase, cname)) { ++ klass = rb_const_get_at(cbase, cname); ++ if (TYPE(klass) != T_CLASS) { ++ rb_raise(rb_eTypeError, "%s is not a class", ++ rb_id2name(cname)); ++ } ++ if (super) { ++ tmp = rb_class_real(RCLASS(klass)->super); ++ if (tmp != super) { ++ rb_raise(rb_eTypeError, "superclass mismatch for class %s", ++ rb_id2name(cname)); ++ } ++ super = 0; ++ } ++ if (ruby_safe_level >= 4) { ++ rb_raise(rb_eSecurityError, "extending class prohibited"); ++ } ++ } ++ else { ++ if (!super) super = rb_cObject; ++ klass = rb_define_class_id(cname, super); ++ rb_set_class_path(klass, cbase, rb_id2name(cname)); ++ rb_const_set(cbase, cname, klass); ++ gen = Qtrue; ++ } ++ if (ruby_wrapper) { ++ rb_extend_object(klass, ruby_wrapper); ++ rb_include_module(klass, ruby_wrapper); ++ } ++ if (super && gen) { ++ rb_class_inherited(super, klass); ++ } ++ return module_setup(klass, node); ++} ++ ++ ++NOINLINE (static VALUE ++eval_module(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE module, cbase; ++ ID cname; ++ ++ if (NIL_P(ruby_cbase)) { ++ rb_raise(rb_eTypeError, "no outer class/module"); ++ } ++ cbase = class_prefix(self, node->nd_cpath); ++ cname = node->nd_cpath->nd_mid; ++ if (rb_const_defined_at(cbase, cname)) { ++ module = rb_const_get_at(cbase, cname); ++ if (TYPE(module) != T_MODULE) { ++ rb_raise(rb_eTypeError, "%s is not a module", ++ rb_id2name(cname)); ++ } ++ if (ruby_safe_level >= 4) { ++ rb_raise(rb_eSecurityError, "extending module prohibited"); ++ } ++ } ++ else { ++ module = rb_define_module_id(cname); ++ rb_set_class_path(module, cbase, rb_id2name(cname)); ++ rb_const_set(cbase, cname, module); ++ } ++ if (ruby_wrapper) { ++ rb_extend_object(module, ruby_wrapper); ++ rb_include_module(module, ruby_wrapper); ++ } ++ ++ return module_setup(module, node); ++} ++ ++ ++NOINLINE (static VALUE ++eval_sclass(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE klass, result; ++ ++ result = rb_eval(self, node->nd_recv); ++ if (FIXNUM_P(result) || SYMBOL_P(result)) { ++ rb_raise(rb_eTypeError, "no virtual class for %s", ++ rb_obj_classname(result)); ++ } ++ if (ruby_safe_level >= 4 && !OBJ_TAINTED(result)) ++ rb_raise(rb_eSecurityError, "Insecure: can't extend object"); ++ klass = rb_singleton_class(result); ++ ++ if (ruby_wrapper) { ++ rb_extend_object(klass, ruby_wrapper); ++ rb_include_module(klass, ruby_wrapper); ++ } ++ ++ return module_setup(klass, node); ++} ++ ++ ++NOINLINE (static VALUE ++eval_defined(self, node)) ++ VALUE self; ++ NODE *node; ++{ ++ char buf[20]; ++ const char *desc = is_defined(self, node->nd_head, buf); ++ return desc ? rb_str_new2(desc) : Qnil; ++} ++ ++ ++NOINLINE (static void ++eval_cvar_set(result, node, bool)) ++ VALUE result, bool; ++ NODE *node; ++{ ++ rb_cvar_set(cvar_cbase(), node->nd_vid, result, bool); ++} ++ ++ ++NOINLINE (static void ++eval_cdecl(self, node, result)) ++ VALUE self, result; ++ NODE *node; ++{ ++ if (node->nd_vid == 0) ++ rb_const_set(class_prefix(self, node->nd_else), ++ node->nd_else->nd_mid, result); ++ else ++ rb_const_set(ruby_cbase, node->nd_vid, result); ++} ++ ++ ++static VALUE ++rb_eval(self, node) ++ VALUE self; ++ NODE *node; ++{ ++ VALUE result; ++ ++again: ++ CHECK_INTS; ++ result = Qnil; ++ if (node) { + ruby_current_node = node; ++ + switch (nd_type(node)) { + case NODE_BLOCK: +- if (contnode) { +- result = rb_eval(self, node); +- break; ++ while (node->nd_next) { ++ rb_eval(self, node->nd_head); ++ node = node->nd_next; + } +- contnode = node->nd_next; + node = node->nd_head; + goto again; + + case NODE_POSTEXE: + rb_f_END(); + nd_set_type(node, NODE_NIL); /* exec just once */ +- result = Qnil; + break; + + /* begin .. end without clauses */ +@@ -2990,65 +3905,33 @@ + + /* nodes for speed-up(literal match) */ + case NODE_MATCH2: +- { +- VALUE l = rb_eval(self,node->nd_recv); +- VALUE r = rb_eval(self,node->nd_value); +- result = rb_reg_match(l, r); +- } ++ result = eval_match2(self, node); + break; + + /* nodes for speed-up(literal match) */ + case NODE_MATCH3: +- { +- VALUE r = rb_eval(self,node->nd_recv); +- VALUE l = rb_eval(self,node->nd_value); +- if (TYPE(l) == T_STRING) { +- result = rb_reg_match(r, l); +- } +- else { +- result = rb_funcall(l, match, 1, r); +- } +- } ++ result = eval_match3(self,node); + break; + + /* node for speed-up(top-level loop for -n/-p) */ + case NODE_OPT_N: +- PUSH_TAG(PROT_LOOP); +- switch (state = EXEC_TAG()) { +- case 0: +- opt_n_next: +- while (!NIL_P(rb_gets())) { +- opt_n_redo: +- rb_eval(self, node->nd_body); +- } +- break; +- +- case TAG_REDO: +- state = 0; +- goto opt_n_redo; +- case TAG_NEXT: +- state = 0; +- goto opt_n_next; +- case TAG_BREAK: +- state = 0; +- default: +- break; +- } +- POP_TAG(); +- if (state) JUMP_TAG(state); +- RETURN(Qnil); ++ eval_opt_n(self, node); ++ break; + + case NODE_SELF: +- RETURN(self); ++ result = self; ++ break; + + case NODE_NIL: +- RETURN(Qnil); ++ break; + + case NODE_TRUE: +- RETURN(Qtrue); ++ result = Qtrue; ++ break; + + case NODE_FALSE: +- RETURN(Qfalse); ++ result = Qfalse; ++ break; + + case NODE_IF: + if (RTEST(rb_eval(self, node->nd_cond))) { +@@ -3066,150 +3949,20 @@ + goto again; + + case NODE_WHEN: +- while (node) { +- NODE *tag; +- +- if (nd_type(node) != NODE_WHEN) goto again; +- tag = node->nd_head; +- while (tag) { +- EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self, +- ruby_frame->last_func, +- ruby_frame->last_class); +- if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) { +- VALUE v = rb_eval(self, tag->nd_head->nd_head); +- long i; +- +- if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v); +- for (i=0; ilen; i++) { +- if (RTEST(RARRAY(v)->ptr[i])) { +- node = node->nd_body; +- goto again; +- } +- } +- tag = tag->nd_next; +- continue; +- } +- if (RTEST(rb_eval(self, tag->nd_head))) { +- node = node->nd_body; +- goto again; +- } +- tag = tag->nd_next; +- } +- node = node->nd_next; +- } +- RETURN(Qnil); ++ if (node = eval_when(self, node)) goto again; ++ break; + + case NODE_CASE: +- { +- VALUE val; +- +- val = rb_eval(self, node->nd_head); +- node = node->nd_body; +- while (node) { +- NODE *tag; +- +- if (nd_type(node) != NODE_WHEN) { +- goto again; +- } +- tag = node->nd_head; +- while (tag) { +- EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self, +- ruby_frame->last_func, +- ruby_frame->last_class); +- if (tag->nd_head && nd_type(tag->nd_head) == NODE_WHEN) { +- VALUE v = rb_eval(self, tag->nd_head->nd_head); +- long i; +- +- if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v); +- for (i=0; ilen; i++) { +- if (RTEST(rb_funcall2(RARRAY(v)->ptr[i], eqq, 1, &val))){ +- node = node->nd_body; +- goto again; +- } +- } +- tag = tag->nd_next; +- continue; +- } +- if (RTEST(rb_funcall2(rb_eval(self, tag->nd_head), eqq, 1, &val))) { +- node = node->nd_body; +- goto again; +- } +- tag = tag->nd_next; +- } +- node = node->nd_next; +- } +- } +- RETURN(Qnil); ++ if (node = eval_case(self, node)) goto again; ++ break; + + case NODE_WHILE: +- PUSH_TAG(PROT_LOOP); +- result = Qnil; +- switch (state = EXEC_TAG()) { +- case 0: +- if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond))) +- goto while_out; +- do { +- while_redo: +- rb_eval(self, node->nd_body); +- while_next: +- ; +- } while (RTEST(rb_eval(self, node->nd_cond))); +- break; +- +- case TAG_REDO: +- state = 0; +- goto while_redo; +- case TAG_NEXT: +- state = 0; +- goto while_next; +- case TAG_BREAK: +- if (TAG_DST()) { +- state = 0; +- result = prot_tag->retval; +- } +- /* fall through */ +- default: +- break; +- } +- while_out: +- POP_TAG(); +- if (state) JUMP_TAG(state); +- RETURN(result); ++ result = eval_while(self,node); ++ break; + + case NODE_UNTIL: +- PUSH_TAG(PROT_LOOP); +- result = Qnil; +- switch (state = EXEC_TAG()) { +- case 0: +- if (node->nd_state && RTEST(rb_eval(self, node->nd_cond))) +- goto until_out; +- do { +- until_redo: +- rb_eval(self, node->nd_body); +- until_next: +- ; +- } while (!RTEST(rb_eval(self, node->nd_cond))); +- break; +- +- case TAG_REDO: +- state = 0; +- goto until_redo; +- case TAG_NEXT: +- state = 0; +- goto until_next; +- case TAG_BREAK: +- if (TAG_DST()) { +- state = 0; +- result = prot_tag->retval; +- } +- /* fall through */ +- default: +- break; +- } +- until_out: +- POP_TAG(); +- if (state) JUMP_TAG(state); +- RETURN(result); ++ result = eval_until(self,node); ++ break; + + case NODE_BLOCK_PASS: + result = block_pass(self, node); +@@ -3217,47 +3970,7 @@ + + case NODE_ITER: + case NODE_FOR: +- { +- PUSH_TAG(PROT_LOOP); +- PUSH_BLOCK(node->nd_var, node->nd_body); +- +- state = EXEC_TAG(); +- if (state == 0) { +- iter_retry: +- PUSH_ITER(ITER_PRE); +- if (nd_type(node) == NODE_ITER) { +- result = rb_eval(self, node->nd_iter); +- } +- else { +- VALUE recv; +- +- _block.flags &= ~BLOCK_D_SCOPE; +- BEGIN_CALLARGS; +- recv = rb_eval(self, node->nd_iter); +- END_CALLARGS; +- ruby_current_node = node; +- SET_CURRENT_SOURCE(); +- result = rb_call(CLASS_OF(recv),recv,each,0,0,0,self); +- } +- POP_ITER(); +- } +- else if (state == TAG_BREAK && TAG_DST()) { +- result = prot_tag->retval; +- state = 0; +- } +- else if (state == TAG_RETRY) { +- state = 0; +- goto iter_retry; +- } +- POP_BLOCK(); +- POP_TAG(); +- switch (state) { +- case 0: +- break; +- default: +- JUMP_TAG(state); +- } +- } ++ result = eval_iter(self, node); + break; + + case NODE_BREAK: +@@ -3265,17 +3978,14 @@ + break; + + case NODE_NEXT: +- CHECK_INTS; + next_jump(rb_eval(self, node->nd_stts)); + break; + + case NODE_REDO: +- CHECK_INTS; + JUMP_TAG(TAG_REDO); + break; + + case NODE_RETRY: +- CHECK_INTS; + JUMP_TAG(TAG_RETRY); + break; + +@@ -3305,73 +4015,15 @@ + break; + + case NODE_RESCUE: +- { +- volatile VALUE e_info = ruby_errinfo; +- volatile int rescuing = 0; +- +- PUSH_TAG(PROT_NONE); +- if ((state = EXEC_TAG()) == 0) { +- retry_entry: +- result = rb_eval(self, node->nd_head); +- } +- else if (rescuing) { +- if (rescuing < 0) { +- /* in rescue argument, just reraise */ +- } +- else if (state == TAG_RETRY) { +- rescuing = state = 0; +- ruby_errinfo = e_info; +- goto retry_entry; +- } +- else if (state != TAG_RAISE) { +- result = prot_tag->retval; +- } +- } +- else if (state == TAG_RAISE) { +- NODE *resq = node->nd_resq; +- +- rescuing = -1; +- while (resq) { +- ruby_current_node = resq; +- if (handle_rescue(self, resq)) { +- state = 0; +- rescuing = 1; +- result = rb_eval(self, resq->nd_body); +- break; +- } +- resq = resq->nd_head; /* next rescue */ +- } +- } +- else { +- result = prot_tag->retval; +- } +- POP_TAG(); +- if (state != TAG_RAISE) ruby_errinfo = e_info; +- if (state) { +- JUMP_TAG(state); +- } +- /* no exception raised */ +- if (!rescuing && (node = node->nd_else)) { /* else clause given */ +- goto again; +- } +- } ++ result = eval_rescue(self,node); ++ if (result == Qundef) { /* handle else clause w/o recursion */ ++ node = node->nd_else; ++ goto again; ++ } + break; + + case NODE_ENSURE: +- PUSH_TAG(PROT_NONE); +- if ((state = EXEC_TAG()) == 0) { +- result = rb_eval(self, node->nd_head); +- } +- POP_TAG(); +- if (node->nd_ensr && !thread_no_ensure()) { +- VALUE retval = prot_tag->retval; /* save retval */ +- VALUE errinfo = ruby_errinfo; +- +- rb_eval(self, node->nd_ensr); +- return_value(retval); +- ruby_errinfo = errinfo; +- } +- if (state) JUMP_TAG(state); ++ result = eval_ensure(self,node); + break; + + case NODE_AND: +@@ -3387,56 +4039,20 @@ + goto again; + + case NODE_NOT: +- if (RTEST(rb_eval(self, node->nd_body))) result = Qfalse; +- else result = Qtrue; ++ result = RTEST(rb_eval(self, node->nd_body)) ? Qfalse : Qtrue; + break; + + case NODE_DOT2: + case NODE_DOT3: +- { +- VALUE beg = rb_eval(self, node->nd_beg); +- VALUE end = rb_eval(self, node->nd_end); +- result = rb_range_new(beg, end, nd_type(node) == NODE_DOT3); +- } +- break; ++ result = eval_dot(self,node); ++ break; + + case NODE_FLIP2: /* like AWK */ +- { +- VALUE *flip = rb_svar(node->nd_cnt); +- if (!flip) rb_bug("unexpected local variable"); +- if (!RTEST(*flip)) { +- if (RTEST(rb_eval(self, node->nd_beg))) { +- *flip = RTEST(rb_eval(self, node->nd_end))?Qfalse:Qtrue; +- result = Qtrue; +- } +- else { +- result = Qfalse; +- } +- } +- else { +- if (RTEST(rb_eval(self, node->nd_end))) { +- *flip = Qfalse; +- } +- result = Qtrue; +- } +- } ++ result = eval_flip2(self,node); + break; + + case NODE_FLIP3: /* like SED */ +- { +- VALUE *flip = rb_svar(node->nd_cnt); +- if (!flip) rb_bug("unexpected local variable"); +- if (!RTEST(*flip)) { +- result = RTEST(rb_eval(self, node->nd_beg)) ? Qtrue : Qfalse; +- *flip = result; +- } +- else { +- if (RTEST(rb_eval(self, node->nd_end))) { +- *flip = Qfalse; +- } +- result = Qtrue; +- } +- } ++ result = eval_flip3(self,node); + break; + + case NODE_RETURN: +@@ -3444,75 +4060,25 @@ + break; + + case NODE_ARGSCAT: +- { +- VALUE args = rb_eval(self, node->nd_head); +- result = rb_ary_concat(args, splat_value(rb_eval(self, node->nd_body))); +- } ++ result = rb_eval(self, node->nd_head); ++ result = rb_ary_concat(result, splat_value(rb_eval(self, node->nd_body))); + break; + + case NODE_ARGSPUSH: +- { +- VALUE args = rb_ary_dup(rb_eval(self, node->nd_head)); +- result = rb_ary_push(args, rb_eval(self, node->nd_body)); +- } ++ result = rb_ary_dup(rb_eval(self, node->nd_head)); ++ result = rb_ary_push(result, rb_eval(self, node->nd_body)); + break; + + case NODE_ATTRASGN: +- { +- VALUE recv; +- int argc; VALUE *argv; /* used in SETUP_ARGS */ +- int scope; +- TMP_PROTECT; +- +- BEGIN_CALLARGS; +- if (node->nd_recv == (NODE *)1) { +- recv = self; +- scope = 1; +- } +- else { +- recv = rb_eval(self, node->nd_recv); +- scope = 0; +- } +- SETUP_ARGS(node->nd_args); +- END_CALLARGS; +- +- ruby_current_node = node; +- SET_CURRENT_SOURCE(); +- rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,scope,self); +- result = argv[argc-1]; +- } +- break; ++ result = eval_attrasgn(self,node); ++ break; + + case NODE_CALL: +- { +- VALUE recv; +- int argc; VALUE *argv; /* used in SETUP_ARGS */ +- TMP_PROTECT; +- +- BEGIN_CALLARGS; +- recv = rb_eval(self, node->nd_recv); +- SETUP_ARGS(node->nd_args); +- END_CALLARGS; +- +- ruby_current_node = node; +- SET_CURRENT_SOURCE(); +- result = rb_call(CLASS_OF(recv),recv,node->nd_mid,argc,argv,0,self); +- } ++ result = eval_call(self,node); + break; + + case NODE_FCALL: +- { +- int argc; VALUE *argv; /* used in SETUP_ARGS */ +- TMP_PROTECT; +- +- BEGIN_CALLARGS; +- SETUP_ARGS(node->nd_args); +- END_CALLARGS; +- +- ruby_current_node = node; +- SET_CURRENT_SOURCE(); +- result = rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1,self); +- } ++ result = eval_fcall(self,node); + break; + + case NODE_VCALL: +@@ -3522,142 +4088,19 @@ + + case NODE_SUPER: + case NODE_ZSUPER: +- { +- int argc; VALUE *argv; /* used in SETUP_ARGS */ +- TMP_PROTECT; +- +- if (ruby_frame->last_class == 0) { +- if (ruby_frame->last_func) { +- rb_name_error(ruby_frame->last_func, +- "superclass method `%s' disabled", +- rb_id2name(ruby_frame->orig_func)); +- } +- else { +- rb_raise(rb_eNoMethodError, "super called outside of method"); +- } +- } +- if (nd_type(node) == NODE_ZSUPER) { +- argc = ruby_frame->argc; +- if (argc && DMETHOD_P()) { +- if (TYPE(RBASIC(ruby_scope)->klass) != T_ARRAY || +- RARRAY(RBASIC(ruby_scope)->klass)->len != argc) { +- rb_raise(rb_eRuntimeError, +- "super: specify arguments explicitly"); +- } +- argv = RARRAY(RBASIC(ruby_scope)->klass)->ptr; +- } +- else if (!ruby_scope->local_vars) { +- argc = 0; +- argv = 0; +- } +- else { +- argv = ruby_scope->local_vars + 2; +- } +- } +- else { +- BEGIN_CALLARGS; +- SETUP_ARGS(node->nd_args); +- END_CALLARGS; +- ruby_current_node = node; +- } +- +- SET_CURRENT_SOURCE(); +- result = rb_call_super(argc, argv); +- } ++ result = eval_super(self,node); + break; + + case NODE_SCOPE: +- { +- struct FRAME frame; +- NODE *saved_cref = 0; +- +- frame = *ruby_frame; +- frame.tmp = ruby_frame; +- ruby_frame = &frame; +- +- PUSH_SCOPE(); +- PUSH_TAG(PROT_NONE); +- if (node->nd_rval) { +- saved_cref = ruby_cref; +- ruby_cref = (NODE*)node->nd_rval; +- } +- if (node->nd_tbl) { +- VALUE *vars = ALLOCA_N(VALUE, node->nd_tbl[0]+1); +- *vars++ = (VALUE)node; +- ruby_scope->local_vars = vars; +- rb_mem_clear(ruby_scope->local_vars, node->nd_tbl[0]); +- ruby_scope->local_tbl = node->nd_tbl; +- } +- else { +- ruby_scope->local_vars = 0; +- ruby_scope->local_tbl = 0; +- } +- if ((state = EXEC_TAG()) == 0) { +- result = rb_eval(self, node->nd_next); +- } +- POP_TAG(); +- POP_SCOPE(); +- ruby_frame = frame.tmp; +- if (saved_cref) +- ruby_cref = saved_cref; +- if (state) JUMP_TAG(state); +- } +- break; ++ result = eval_scope(self,node); ++ break; + + case NODE_OP_ASGN1: +- { +- int argc; VALUE *argv; /* used in SETUP_ARGS */ +- VALUE recv, val, tmp; +- NODE *rval; +- TMP_PROTECT; +- +- recv = rb_eval(self, node->nd_recv); +- rval = node->nd_args->nd_head; +- SETUP_ARGS0(node->nd_args->nd_body, 1); +- val = rb_funcall3(recv, aref, argc, argv); +- switch (node->nd_mid) { +- case 0: /* OR */ +- if (RTEST(val)) RETURN(val); +- val = rb_eval(self, rval); +- break; +- case 1: /* AND */ +- if (!RTEST(val)) RETURN(val); +- val = rb_eval(self, rval); +- break; +- default: +- tmp = rb_eval(self, rval); +- val = rb_funcall3(val, node->nd_mid, 1, &tmp); +- } +- argv[argc] = val; +- rb_funcall2(recv, aset, argc+1, argv); +- result = val; +- } ++ result = eval_op_asgn1(self,node); + break; + + case NODE_OP_ASGN2: +- { +- ID id = node->nd_next->nd_vid; +- VALUE recv, val, tmp; +- +- recv = rb_eval(self, node->nd_recv); +- val = rb_funcall3(recv, id, 0, 0); +- switch (node->nd_next->nd_mid) { +- case 0: /* OR */ +- if (RTEST(val)) RETURN(val); +- val = rb_eval(self, node->nd_value); +- break; +- case 1: /* AND */ +- if (!RTEST(val)) RETURN(val); +- val = rb_eval(self, node->nd_value); +- break; +- default: +- tmp = rb_eval(self, node->nd_value); +- val = rb_funcall3(val, node->nd_next->nd_mid, 1, &tmp); +- } +- +- rb_funcall2(recv, node->nd_next->nd_aid, 1, &val); +- result = val; +- } ++ result = eval_op_asgn2(self,node); + break; + + case NODE_OP_ASGN_AND: +@@ -3706,26 +4149,21 @@ + break; + + case NODE_CDECL: +- result = rb_eval(self, node->nd_value); +- if (node->nd_vid == 0) { +- rb_const_set(class_prefix(self, node->nd_else), node->nd_else->nd_mid, result); +- } +- else { +- rb_const_set(ruby_cbase, node->nd_vid, result); +- } ++ result = rb_eval(self, node->nd_value); ++ eval_cdecl(self, node, result); + break; + + case NODE_CVDECL: + if (NIL_P(ruby_cbase)) { + rb_raise(rb_eTypeError, "no class/module to define class variable"); + } +- result = rb_eval(self, node->nd_value); +- rb_cvar_set(cvar_cbase(), node->nd_vid, result, Qtrue); ++ result = rb_eval(self, node->nd_value); ++ eval_cvar_set(result, node, Qtrue); + break; + + case NODE_CVASGN: +- result = rb_eval(self, node->nd_value); +- rb_cvar_set(cvar_cbase(), node->nd_vid, result, Qfalse); ++ result = rb_eval(self, node->nd_value); ++ eval_cvar_set(result, node, Qfalse); + break; + + case NODE_LVAR: +@@ -3768,26 +4206,21 @@ + break; + + case NODE_COLON2: +- { +- VALUE klass; +- +- klass = rb_eval(self, node->nd_head); +- if (rb_is_const_id(node->nd_mid)) { +- switch (TYPE(klass)) { +- case T_CLASS: +- case T_MODULE: +- result = rb_const_get_from(klass, node->nd_mid); +- break; +- default: +- rb_raise(rb_eTypeError, "%s is not a class/module", +- RSTRING(rb_obj_as_string(klass))->ptr); +- break; +- } +- } +- else { +- result = rb_funcall(klass, node->nd_mid, 0, 0); ++ result = rb_eval(self, node->nd_head); ++ if (rb_is_const_id(node->nd_mid)) { ++ switch (TYPE(result)) { ++ case T_CLASS: ++ case T_MODULE: ++ result = rb_const_get_from(result, node->nd_mid); ++ break; ++ default: ++ rb_raise(rb_eTypeError, "%s is not a class/module", ++ RSTRING(rb_obj_as_string(result))->ptr); ++ break; + } + } ++ else ++ result = rb_funcall(result, node->nd_mid, 0, 0); + break; + + case NODE_COLON3: +@@ -3818,23 +4251,7 @@ + break; + + case NODE_HASH: +- { +- NODE *list; +- VALUE hash = rb_hash_new(); +- VALUE key, val; +- +- list = node->nd_head; +- while (list) { +- key = rb_eval(self, list->nd_head); +- list = list->nd_next; +- if (list == 0) +- rb_bug("odd number list for Hash"); +- val = rb_eval(self, list->nd_head); +- list = list->nd_next; +- rb_hash_aset(hash, key, val); +- } +- result = hash; +- } ++ result = eval_hash(self,node); + break; + + case NODE_ZARRAY: /* zero length list */ +@@ -3842,19 +4259,7 @@ + break; + + case NODE_ARRAY: +- { +- VALUE ary; +- long i; +- +- i = node->nd_alen; +- ary = rb_ary_new2(i); +- for (i=0;node;node=node->nd_next) { +- RARRAY(ary)->ptr[i++] = rb_eval(self, node->nd_head); +- RARRAY(ary)->len = i; +- } +- +- result = ary; +- } ++ result = eval_array(self,node); + break; + + case NODE_STR: +@@ -3870,51 +4275,8 @@ + case NODE_DREGX: + case NODE_DREGX_ONCE: + case NODE_DSYM: +- { +- VALUE str, str2; +- NODE *list = node->nd_next; +- +- str = rb_str_new3(node->nd_lit); +- while (list) { +- if (list->nd_head) { +- switch (nd_type(list->nd_head)) { +- case NODE_STR: +- str2 = list->nd_head->nd_lit; +- break; +- default: +- str2 = rb_eval(self, list->nd_head); +- break; +- } +- rb_str_append(str, str2); +- OBJ_INFECT(str, str2); +- } +- list = list->nd_next; +- } +- switch (nd_type(node)) { +- case NODE_DREGX: +- result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, +- node->nd_cflag); +- break; +- case NODE_DREGX_ONCE: /* regexp expand once */ +- result = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, +- node->nd_cflag); +- nd_set_type(node, NODE_LIT); +- node->nd_lit = result; +- break; +- case NODE_LIT: +- /* other thread may replace NODE_DREGX_ONCE to NODE_LIT */ +- goto again; +- case NODE_DXSTR: +- result = rb_funcall(self, '`', 1, str); +- break; +- case NODE_DSYM: +- result = rb_str_intern(str); +- break; +- default: +- result = str; +- break; +- } +- } ++ result = eval_slit(self, node); ++ if (result == Qundef) goto again; + break; + + case NODE_XSTR: +@@ -3926,84 +4288,13 @@ + break; + + case NODE_DEFN: +- if (node->nd_defn) { +- NODE *body, *defn; +- VALUE origin = 0; +- int noex; +- +- if (NIL_P(ruby_class)) { +- rb_raise(rb_eTypeError, "no class/module to add method"); +- } +- if (ruby_class == rb_cObject && node->nd_mid == init) { +- rb_warn("redefining Object#initialize may cause infinite loop"); +- } +- if (node->nd_mid == __id__ || node->nd_mid == __send__) { +- rb_warn("redefining `%s' may cause serious problem", +- rb_id2name(node->nd_mid)); +- } +- rb_frozen_class_p(ruby_class); +- body = search_method(ruby_class, node->nd_mid, &origin); +- if (body){ +- if (RTEST(ruby_verbose) && ruby_class == origin && body->nd_cnt == 0 && body->nd_body) { +- rb_warning("method redefined; discarding old %s", rb_id2name(node->nd_mid)); +- } +- } +- +- if (SCOPE_TEST(SCOPE_PRIVATE) || node->nd_mid == init) { +- noex = NOEX_PRIVATE; +- } +- else if (SCOPE_TEST(SCOPE_PROTECTED)) { +- noex = NOEX_PROTECTED; +- } +- else { +- noex = NOEX_PUBLIC; +- } +- if (body && origin == ruby_class && body->nd_body == 0) { +- noex |= NOEX_NOSUPER; +- } +- +- defn = rb_copy_node_scope(node->nd_defn, ruby_cref); +- rb_add_method(ruby_class, node->nd_mid, defn, noex); +- if (scope_vmode == SCOPE_MODFUNC) { +- rb_add_method(rb_singleton_class(ruby_class), +- node->nd_mid, defn, NOEX_PUBLIC); +- } +- result = Qnil; +- } ++ if (node->nd_defn) ++ eval_defn(self,node); + break; + + case NODE_DEFS: +- if (node->nd_defn) { +- VALUE recv = rb_eval(self, node->nd_recv); +- VALUE klass; +- NODE *body = 0, *defn; +- +- if (ruby_safe_level >= 4 && !OBJ_TAINTED(recv)) { +- rb_raise(rb_eSecurityError, "Insecure: can't define singleton method"); +- } +- if (FIXNUM_P(recv) || SYMBOL_P(recv)) { +- rb_raise(rb_eTypeError, +- "can't define singleton method \"%s\" for %s", +- rb_id2name(node->nd_mid), +- rb_obj_classname(recv)); +- } +- +- if (OBJ_FROZEN(recv)) rb_error_frozen("object"); +- klass = rb_singleton_class(recv); +- if (st_lookup(RCLASS(klass)->m_tbl, node->nd_mid, &data)) { +- body = (NODE *)data; +- if (ruby_safe_level >= 4) { +- rb_raise(rb_eSecurityError, "redefining method prohibited"); +- } +- if (RTEST(ruby_verbose)) { +- rb_warning("redefine %s", rb_id2name(node->nd_mid)); +- } +- } +- defn = rb_copy_node_scope(node->nd_defn, ruby_cref); +- rb_add_method(klass, node->nd_mid, defn, +- NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0)); +- result = Qnil; +- } ++ if (node->nd_defn) ++ eval_defs(self,node); + break; + + case NODE_UNDEF: +@@ -4011,7 +4302,6 @@ + rb_raise(rb_eTypeError, "no class to undef method"); + } + rb_undef(ruby_class, rb_to_id(rb_eval(self, node->u2.node))); +- result = Qnil; + break; + + case NODE_ALIAS: +@@ -4020,134 +4310,26 @@ + } + rb_alias(ruby_class, rb_to_id(rb_eval(self, node->u1.node)), + rb_to_id(rb_eval(self, node->u2.node))); +- result = Qnil; + break; + + case NODE_VALIAS: + rb_alias_variable(node->u1.id, node->u2.id); +- result = Qnil; + break; + + case NODE_CLASS: +- { +- VALUE super, klass, tmp, cbase; +- ID cname; +- int gen = Qfalse; +- +- cbase = class_prefix(self, node->nd_cpath); +- cname = node->nd_cpath->nd_mid; +- +- if (NIL_P(ruby_cbase)) { +- rb_raise(rb_eTypeError, "no outer class/module"); +- } +- if (node->nd_super) { +- super = rb_eval(self, node->nd_super); +- rb_check_inheritable(super); +- } +- else { +- super = 0; +- } +- +- if (rb_const_defined_at(cbase, cname)) { +- klass = rb_const_get_at(cbase, cname); +- if (TYPE(klass) != T_CLASS) { +- rb_raise(rb_eTypeError, "%s is not a class", +- rb_id2name(cname)); +- } +- if (super) { +- tmp = rb_class_real(RCLASS(klass)->super); +- if (tmp != super) { +- rb_raise(rb_eTypeError, "superclass mismatch for class %s", +- rb_id2name(cname)); +- } +- super = 0; +- } +- if (ruby_safe_level >= 4) { +- rb_raise(rb_eSecurityError, "extending class prohibited"); +- } +- } +- else { +- if (!super) super = rb_cObject; +- klass = rb_define_class_id(cname, super); +- rb_set_class_path(klass, cbase, rb_id2name(cname)); +- rb_const_set(cbase, cname, klass); +- gen = Qtrue; +- } +- if (ruby_wrapper) { +- rb_extend_object(klass, ruby_wrapper); +- rb_include_module(klass, ruby_wrapper); +- } +- if (super && gen) { +- rb_class_inherited(super, klass); +- } +- result = module_setup(klass, node); +- } ++ result = eval_class(self,node); + break; + + case NODE_MODULE: +- { +- VALUE module, cbase; +- ID cname; +- +- if (NIL_P(ruby_cbase)) { +- rb_raise(rb_eTypeError, "no outer class/module"); +- } +- cbase = class_prefix(self, node->nd_cpath); +- cname = node->nd_cpath->nd_mid; +- if (rb_const_defined_at(cbase, cname)) { +- module = rb_const_get_at(cbase, cname); +- if (TYPE(module) != T_MODULE) { +- rb_raise(rb_eTypeError, "%s is not a module", +- rb_id2name(cname)); +- } +- if (ruby_safe_level >= 4) { +- rb_raise(rb_eSecurityError, "extending module prohibited"); +- } +- } +- else { +- module = rb_define_module_id(cname); +- rb_set_class_path(module, cbase, rb_id2name(cname)); +- rb_const_set(cbase, cname, module); +- } +- if (ruby_wrapper) { +- rb_extend_object(module, ruby_wrapper); +- rb_include_module(module, ruby_wrapper); +- } +- +- result = module_setup(module, node); +- } ++ result = eval_module(self,node); + break; + + case NODE_SCLASS: +- { +- VALUE klass; +- +- result = rb_eval(self, node->nd_recv); +- if (FIXNUM_P(result) || SYMBOL_P(result)) { +- rb_raise(rb_eTypeError, "no virtual class for %s", +- rb_obj_classname(result)); +- } +- if (ruby_safe_level >= 4 && !OBJ_TAINTED(result)) +- rb_raise(rb_eSecurityError, "Insecure: can't extend object"); +- klass = rb_singleton_class(result); +- +- if (ruby_wrapper) { +- rb_extend_object(klass, ruby_wrapper); +- rb_include_module(klass, ruby_wrapper); +- } +- +- result = module_setup(klass, node); +- } ++ result = eval_sclass(self,node); + break; + + case NODE_DEFINED: +- { +- char buf[20]; +- const char *desc = is_defined(self, node->nd_head, buf); +- +- if (desc) result = rb_str_new2(desc); +- else result = Qnil; +- } ++ result = eval_defined(self,node); + break; + + case NODE_NEWLINE: +@@ -4160,14 +4342,8 @@ + default: + unknown_node(node); + } +- finish: +- CHECK_INTS; +- if (contnode) { +- node = contnode; +- contnode = 0; +- goto again; +- } +- return result; ++ } ++ return result; + } + + static VALUE +@@ -13081,6 +13257,32 @@ + + VALUE rb_cCont; + ++ ++static rb_thread_t prep4callcc(void) ++{ ++ rb_thread_t th; ++ struct tag *tag; ++ struct RVarmap *vars; ++ ++ THREAD_ALLOC(th); ++ /* must finish th initialization before any possible gc */ ++ th->thread = curr_thread->thread; /* brent@mbari.org */ ++ th->thgroup = cont_protect; ++ ++ scope_dup(ruby_scope); ++ for (tag=prot_tag; tag; tag=tag->prev) { ++ if (tag->tag == PROT_THREAD) break; ++ scope_dup(tag->scope); ++ } ++ ++ for (vars = ruby_dyna_vars; vars; vars = vars->next) { ++ if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; ++ FL_SET(vars, DVAR_DONT_RECYCLE); ++ } ++ return th; ++} ++ ++ + /* + * call-seq: + * callcc {|cont| block } => obj +@@ -13099,37 +13301,14 @@ + rb_callcc(self) + VALUE self; + { +- volatile VALUE cont; +- rb_thread_t th; +- volatile rb_thread_t th_save; +- struct tag *tag; +- struct RVarmap *vars; +- +- THREAD_ALLOC(th); +- /* must finish th initialization before any possible gc */ +- th->thread = curr_thread->thread; /* brent@mbari.org */ +- th->thgroup = cont_protect; +- cont = Data_Wrap_Struct(rb_cCont, cc_mark, thread_free, th); +- +- scope_dup(ruby_scope); +- for (tag=prot_tag; tag; tag=tag->prev) { +- if (tag->tag == PROT_THREAD) break; +- scope_dup(tag->scope); +- } +- +- for (vars = ruby_dyna_vars; vars; vars = vars->next) { +- if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break; +- FL_SET(vars, DVAR_DONT_RECYCLE); +- } +- th_save = th; +- if (THREAD_SAVE_CONTEXT(th)) { +- return th_save->result; +- } +- else { +- return rb_yield(cont); +- } ++ rb_thread_t th = prep4callcc(); ++ return THREAD_SAVE_CONTEXT(th) ? ++ th->result ++ : ++ rb_yield(Data_Wrap_Struct(rb_cCont, cc_mark, thread_free, th)); + } + ++ + /* + * call-seq: + * cont.call(args, ...) +diff -rux '*.o' ruby-1.8.7-p72/version.h ruby-1.8.7-mbari/version.h +--- ruby-1.8.7-p72/version.h 2008-12-16 00:47:26.000000000 -0800 ++++ ruby-1.8.7-mbari/version.h 2008-12-16 20:02:42.000000000 -0800 +@@ -1,7 +1,7 @@ + #define RUBY_VERSION "1.8.7" +-#define RUBY_RELEASE_DATE "2008-12-13" ++#define RUBY_RELEASE_DATE "2008-12-16" + #define RUBY_VERSION_CODE 187 +-#define RUBY_RELEASE_CODE 20081213 ++#define RUBY_RELEASE_CODE 20081216 + #define RUBY_PATCHLEVEL 72 + + #define RUBY_VERSION_MAJOR 1 +@@ -9,7 +9,7 @@ + #define RUBY_VERSION_TEENY 7 + #define RUBY_RELEASE_YEAR 2008 + #define RUBY_RELEASE_MONTH 12 +-#define RUBY_RELEASE_DAY 13 ++#define RUBY_RELEASE_DAY 16 + + #ifdef RUBY_EXTERN + RUBY_EXTERN const char ruby_version[]; +@@ -25,7 +25,7 @@ + #define RUBY_BIRTH_MONTH 2 + #define RUBY_BIRTH_DAY 24 + +-#define RUBY_RELEASE_STR "MBARI 3 on patchlevel" ++#define RUBY_RELEASE_STR "MBARI 4 on patchlevel" + #define RUBY_RELEASE_NUM RUBY_PATCHLEVEL + + diff --git a/patches/ruby/1.8.7/p72/mbari-5.patch b/patches/ruby/1.8.7/p72/mbari-5.patch new file mode 100644 index 0000000000..637c2e4b9d --- /dev/null +++ b/patches/ruby/1.8.7/p72/mbari-5.patch @@ -0,0 +1,192 @@ +diff -rux '*.o' ruby-1.8.7-p72/ChangeLog ruby-1.8.7-mbari/ChangeLog +--- ruby-1.8.7-p72/ChangeLog 2008-12-17 23:46:07.000000000 -0800 ++++ ruby-1.8.7-mbari/ChangeLog 2008-12-17 23:42:22.000000000 -0800 +@@ -1,3 +1,7 @@ ++Tue Dec 17 4:15:36 2008 Brent Roman ++ ++ * eval.c: streamlined rb_thread_restore_context() to ensure O(1) time ++ + Tue Dec 15 9:15:36 2008 Brent Roman + + * eval.c: factored rb_eval() into many separate non-inlined + +diff -rux '*.o' ruby-1.8.7-p72/eval.c ruby-1.8.7-mbari/eval.c +--- ruby-1.8.7-p72/eval.c 2008-12-17 23:46:07.000000000 -0800 ++++ ruby-1.8.7-mbari/eval.c 2008-12-17 23:44:48.000000000 -0800 +@@ -3,7 +3,7 @@ + eval.c - + + $Author: brent $ +- $Date: 2008/12/17 07:28:08 $ ++ $Date: 2008/12/18 07:44:48 $ + created at: Thu Jun 10 14:22:17 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -10884,11 +10884,10 @@ + ruby_setjmp(rb_thread_save_context(th), (th)->context)))) + + NORETURN(static void rb_thread_restore_context _((rb_thread_t,int))); +-NORETURN(NOINLINE(static void rb_thread_restore_context_0(rb_thread_t,int,void*))); +-NORETURN(NOINLINE(static void stack_extend(rb_thread_t, int, VALUE *))); ++NORETURN(NOINLINE(static void rb_thread_restore_context_0(rb_thread_t,int))); + + static void +-rb_thread_restore_context_0(rb_thread_t th, int exit, void *vp) ++rb_thread_restore_context_0(rb_thread_t th, int exit) + { + static rb_thread_t tmp; + static int ex; +@@ -10945,9 +10944,9 @@ + static volatile int C(k), C(l), C(m), C(n), C(o); + static volatile int C(p), C(q), C(r), C(s), C(t); + int rb_dummy_false = 0; +-NORETURN(NOINLINE(static void register_stack_extend(rb_thread_t, int, void *, VALUE *))); ++NORETURN(NOINLINE(static void register_stack_extend(rb_thread_t, int, VALUE *))); + static void +-register_stack_extend(rb_thread_t th, int exit, void *vp, VALUE *curr_bsp) ++register_stack_extend(rb_thread_t th, int exit, VALUE *curr_bsp) + { + if (rb_dummy_false) { + /* use registers as much as possible */ +@@ -10961,52 +10960,68 @@ + E(p) = E(q) = E(r) = E(s) = E(t) = 0; + } + if (curr_bsp < th->bstr_pos+th->bstr_len) { +- register_stack_extend(th, exit, &exit, (VALUE*)rb_ia64_bsp()); ++ register_stack_extend(th, exit, (VALUE*)rb_ia64_bsp()); + } +- rb_thread_restore_context_0(th, exit, &exit); ++ rb_thread_restore_context_0(th, exit); + } + #undef C + #undef E + #endif + +-# if defined(_MSC_VER) && _MSC_VER >= 1300 +-__declspec(noinline) static void stack_extend(rb_thread_t, int, VALUE*); +-# endif +-static void +-stack_extend(rb_thread_t th, int exit, VALUE *addr_in_prev_frame) +-{ +-#define STACK_PAD_SIZE 1024 +- VALUE space[STACK_PAD_SIZE]; +- +-#if STACK_GROW_DIRECTION < 0 +- if (addr_in_prev_frame > th->stk_pos) stack_extend(th, exit, &space[0]); +-#elif STACK_GROW_DIRECTION > 0 +- if (addr_in_prev_frame < th->stk_pos + th->stk_len) stack_extend(th, exit, &space[STACK_PAD_SIZE-1]); +-#else +- if (addr_in_prev_frame < rb_gc_stack_start) { +- /* Stack grows downward */ +- if (addr_in_prev_frame > th->stk_pos) stack_extend(th, exit, &space[0]); +- } +- else { +- /* Stack grows upward */ +- if (addr_in_prev_frame < th->stk_pos + th->stk_len) stack_extend(th, exit, &space[STACK_PAD_SIZE-1]); +- } +-#endif +-#ifdef __ia64 +- register_stack_extend(th, exit, space, (VALUE*)rb_ia64_bsp()); +-#else +- rb_thread_restore_context_0(th, exit, space); +-#endif +-} + + static void + rb_thread_restore_context(th, exit) + rb_thread_t th; + int exit; + { ++ VALUE *pos = th->stk_start; ++ ++#if HAVE_ALLOCA /* use alloca to grow stack in O(1) time */ + VALUE v; ++ volatile VALUE *space; ++ + if (!th->stk_ptr) rb_bug("unsaved context"); +- stack_extend(th, exit, &v); ++# if !STACK_GROW_DIRECTION /* unknown at compile time */ ++ if (rb_gc_stack_grow_direction < 0) { ++# endif ++# if STACK_GROW_DIRECTION <= 0 ++ pos -= th->stk_len; ++ if (&v > pos) space=ALLOCA_N(VALUE, &v-pos); ++# endif ++# if !STACK_GROW_DIRECTION ++ }else ++# endif ++#if STACK_GROW_DIRECTION >= 0 /* stack grows upward */ ++ if (&v < pos + th->stk_len) space=ALLOCA_N(VALUE, pos+th->stk_len - &v); ++# endif ++ ++#else /* recursive O(n/1024) if extending stack > 1024 VALUEs */ ++ ++ volatile VALUE v[1023]; ++ ++# if !STACK_GROW_DIRECTION /* unknown at compile time */ ++ if (rb_gc_stack_grow_direction < 0) { ++# endif ++# if STACK_GROW_DIRECTION <= 0 ++ pos -= th->stk_len; ++ if (v > pos) rb_thread_restore_context(th, exit); ++# endif ++# if !STACK_GROW_DIRECTION ++ }else ++# endif ++# if STACK_GROW_DIRECTION >= 0 /* stack grows upward */ ++ if (v < pos + th->stk_len) rb_thread_restore_context(th, exit); ++# endif ++ if (!th->stk_ptr) rb_bug("unsaved context"); ++ ++#endif /* stack now extended */ ++ ++ ++#ifdef __ia64 ++ register_stack_extend(th, exit, (VALUE*)rb_ia64_bsp()); ++#else ++ rb_thread_restore_context_0(th, exit); ++#endif + } + + static void +diff -rux '*.o' ruby-1.8.7-p72/gc.c ruby-1.8.7-mbari/gc.c +--- ruby-1.8.7-p72/gc.c 2008-12-20 22:34:10.000000000 -0800 ++++ ruby-1.8.7-mbari/gc.c 2008-12-17 23:43:46.000000000 -0800 +@@ -3,7 +3,7 @@ + gc.c - + + $Author: brent $ +- $Date: 2008/12/14 07:23:34 $ ++ $Date: 2008/12/18 07:43:46 $ + created at: Tue Oct 5 09:44:46 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +diff -rux '*.o' ruby-1.8.7-p72/version.h ruby-1.8.7-mbari/version.h +--- ruby-1.8.7-p72/version.h 2008-12-17 23:46:07.000000000 -0800 ++++ ruby-1.8.7-mbari/version.h 2008-12-17 22:32:11.000000000 -0800 +@@ -1,7 +1,7 @@ + #define RUBY_VERSION "1.8.7" +-#define RUBY_RELEASE_DATE "2008-12-16" ++#define RUBY_RELEASE_DATE "2008-12-17" + #define RUBY_VERSION_CODE 187 +-#define RUBY_RELEASE_CODE 20081216 ++#define RUBY_RELEASE_CODE 20081217 + #define RUBY_PATCHLEVEL 72 + + #define RUBY_VERSION_MAJOR 1 +@@ -9,7 +9,7 @@ + #define RUBY_VERSION_TEENY 7 + #define RUBY_RELEASE_YEAR 2008 + #define RUBY_RELEASE_MONTH 12 +-#define RUBY_RELEASE_DAY 16 ++#define RUBY_RELEASE_DAY 17 + + #ifdef RUBY_EXTERN + RUBY_EXTERN const char ruby_version[]; +@@ -25,7 +25,7 @@ + #define RUBY_BIRTH_MONTH 2 + #define RUBY_BIRTH_DAY 24 + +-#define RUBY_RELEASE_STR "MBARI 4 on patchlevel" ++#define RUBY_RELEASE_STR "MBARI 5 on patchlevel" + #define RUBY_RELEASE_NUM RUBY_PATCHLEVEL diff --git a/patches/ruby/1.8.7/p72/mbari-6.patch b/patches/ruby/1.8.7/p72/mbari-6.patch new file mode 100644 index 0000000000..fea283f0c1 --- /dev/null +++ b/patches/ruby/1.8.7/p72/mbari-6.patch @@ -0,0 +1,225 @@ +diff -rux '*.o' ruby-1.8.7-p72/ChangeLog ruby-1.8.7-mbari/ChangeLog +--- ruby-1.8.7-p72/ChangeLog 2008-12-19 23:42:15.000000000 -0800 ++++ ruby-1.8.7-mbari/ChangeLog 2008-12-19 23:52:11.000000000 -0800 +@@ -1,7 +1,14 @@ ++Tue Dec 19 20:15:36 2008 Brent Roman ++ ++ * eval.c: added (Method|Proc)#(__line__|__file__) methods ++ call ruby_set_current_source() before adding method nodes ++ ++ + Tue Dec 17 4:15:36 2008 Brent Roman + + * eval.c: streamlined rb_thread_restore_context() to ensure O(1) time + ++ + Tue Dec 15 9:15:36 2008 Brent Roman + + * eval.c: factored rb_eval() into many separate non-inlined +diff -rux '*.o' ruby-1.8.7-p72/eval.c ruby-1.8.7-mbari/eval.c +--- ruby-1.8.7-p72/eval.c 2008-12-19 23:42:15.000000000 -0800 ++++ ruby-1.8.7-mbari/eval.c 2008-12-19 23:47:22.000000000 -0800 +@@ -3,7 +3,7 @@ + eval.c - + + $Author: brent $ +- $Date: 2008/12/18 07:44:48 $ ++ $Date: 2008/12/20 07:47:22 $ + created at: Thu Jun 10 14:22:17 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -726,6 +726,7 @@ + if (!name) { + rb_raise(rb_eArgError, "argument needs to be symbol or string"); + } ++ ruby_set_current_source(); /* for Method#__line__ */ + len = strlen(name)+2; + buf = ALLOCA_N(char,len); + snprintf(buf, len, "@%s", name); +@@ -2248,7 +2249,10 @@ + NODE *node; + NODE *rval; + { +- NODE *copy = NEW_NODE(NODE_SCOPE,0,rval,node->nd_next); ++ NODE *copy; ++ ++ ruby_set_current_source(); /* for Method#__line__ */ ++ copy=NEW_NODE(NODE_SCOPE,0,rval,node->nd_next); + + if (node->nd_tbl) { + copy->nd_tbl = ALLOC_N(ID, node->nd_tbl[0]+1); +@@ -3878,7 +3882,8 @@ + result = Qnil; + if (node) { + ruby_current_node = node; +- ++ SET_CURRENT_SOURCE(); ++ + switch (nd_type(node)) { + case NODE_BLOCK: + while (node->nd_next) { +@@ -10119,6 +10124,7 @@ + else { + rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); + } ++ ruby_set_current_source(); /* for Method#__line__ */ + if (RDATA(body)->dmark == (RUBY_DATA_FUNC)bm_mark) { + node = NEW_DMETHOD(method_unbind(body)); + } +@@ -10150,6 +10156,98 @@ + return body; + } + ++ ++/* ++ * call-seq: ++ * meth.__file__ => String ++ * ++ * returns the filename containing this method's definition ++ * raises ArgumentError if method has no associated ruby source code ++ */ ++ ++static VALUE ++method_source_file_name(VALUE method) ++{ ++ struct METHOD *data; ++ NODE *node; ++ ++ Data_Get_Struct(method, struct METHOD, data); ++ if (node = data->body) { ++ const char *filename = node->nd_file; ++ if (filename) ++ return rb_str_new2(filename); ++ } ++ rb_raise(rb_eArgError, "native Method"); ++} ++ ++/* ++ * call-seq: ++ * meth.__line__ => Fixnum ++ * ++ * returns the starting line number of this method ++ * raises ArgumentError if method has no associated ruby source code ++ */ ++ ++static VALUE ++method_source_line(VALUE method) ++{ ++ struct METHOD *data; ++ NODE *node; ++ ++ Data_Get_Struct(method, struct METHOD, data); ++ if (node = data->body) { ++ int lineno = nd_line(node); ++ if (lineno) ++ return INT2FIX(nd_line(node)); ++ } ++ rb_raise(rb_eArgError, "native Method"); ++} ++ ++ ++ ++/* ++ * call-seq: ++ * prc.__file__ => String ++ * ++ * returns the filename where this proc is defined ++ * raises ArgumentError if proc has no associated ruby source ++ */ ++ ++static VALUE ++proc_source_file_name(VALUE block) ++{ ++ struct BLOCK *data; ++ const char *filename; ++ NODE *node; ++ ++ Data_Get_Struct(block, struct BLOCK, data); ++ if ((node = data->frame.node) || (node = data->body)) ++ return rb_str_new2(node->nd_file); ++ rb_raise(rb_eArgError, "native Proc"); ++} ++ ++ ++/* ++ * call-seq: ++ * prc.__line__ => Fixnum ++ * ++ * returns the starting line number of this proc ++ * raises ArgumentError if proc has no associated ruby source code ++ */ ++ ++static VALUE ++proc_source_line(VALUE block) ++{ ++ struct BLOCK *data; ++ NODE *node; ++ ++ Data_Get_Struct(block, struct BLOCK, data); ++ if ((node = data->frame.node) || (node = data->body)) ++ return INT2FIX( nd_line(node) ); ++ rb_raise(rb_eArgError, "native Proc"); ++} ++ ++ + /* + * Proc objects are blocks of code that have been bound to + * a set of local variables. Once bound, the code may be called in +@@ -10201,6 +10299,8 @@ + rb_define_method(rb_cProc, "to_s", proc_to_s, 0); + rb_define_method(rb_cProc, "to_proc", proc_to_self, 0); + rb_define_method(rb_cProc, "binding", proc_binding, 0); ++ rb_define_method(rb_cProc, "__file__", proc_source_file_name, 0); ++ rb_define_method(rb_cProc, "__line__", proc_source_line, 0); + + rb_define_global_function("proc", proc_lambda, 0); + rb_define_global_function("lambda", proc_lambda, 0); +@@ -10221,6 +10321,8 @@ + rb_define_method(rb_cMethod, "owner", method_owner, 0); + rb_define_method(rb_cMethod, "unbind", method_unbind, 0); + rb_define_method(rb_mKernel, "method", rb_obj_method, 1); ++ rb_define_method(rb_cMethod, "__file__", method_source_file_name, 0); ++ rb_define_method(rb_cMethod, "__line__", method_source_line, 0); + + rb_cUnboundMethod = rb_define_class("UnboundMethod", rb_cObject); + rb_undef_alloc_func(rb_cUnboundMethod); +@@ -10233,6 +10335,8 @@ + rb_define_method(rb_cUnboundMethod, "name", method_name, 0); + rb_define_method(rb_cUnboundMethod, "owner", method_owner, 0); + rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1); ++ rb_define_method(rb_cUnboundMethod, "__file__", method_source_file_name, 0); ++ rb_define_method(rb_cUnboundMethod, "__line__", method_source_line, 0); + rb_define_method(rb_cModule, "instance_method", rb_mod_method, 1); + } + +diff -rux '*.o' ruby-1.8.7-p72/version.h ruby-1.8.7-mbari/version.h +--- ruby-1.8.7-p72/version.h 2008-12-19 23:42:15.000000000 -0800 ++++ ruby-1.8.7-mbari/version.h 2008-12-19 23:39:56.000000000 -0800 +@@ -1,7 +1,7 @@ + #define RUBY_VERSION "1.8.7" +-#define RUBY_RELEASE_DATE "2008-12-17" ++#define RUBY_RELEASE_DATE "2008-12-21" + #define RUBY_VERSION_CODE 187 +-#define RUBY_RELEASE_CODE 20081217 ++#define RUBY_RELEASE_CODE 20081221 + #define RUBY_PATCHLEVEL 72 + + #define RUBY_VERSION_MAJOR 1 +@@ -9,7 +9,7 @@ + #define RUBY_VERSION_TEENY 7 + #define RUBY_RELEASE_YEAR 2008 + #define RUBY_RELEASE_MONTH 12 +-#define RUBY_RELEASE_DAY 17 ++#define RUBY_RELEASE_DAY 21 + + #ifdef RUBY_EXTERN + RUBY_EXTERN const char ruby_version[]; +@@ -25,7 +25,7 @@ + #define RUBY_BIRTH_MONTH 2 + #define RUBY_BIRTH_DAY 24 + +-#define RUBY_RELEASE_STR "MBARI 5 on patchlevel" ++#define RUBY_RELEASE_STR "MBARI 6 on patchlevel" + #define RUBY_RELEASE_NUM RUBY_PATCHLEVEL + + diff --git a/patches/ruby/1.8.7/p72/mbari-8b.patch b/patches/ruby/1.8.7/p72/mbari-8b.patch new file mode 100644 index 0000000000..7e7b4053be --- /dev/null +++ b/patches/ruby/1.8.7/p72/mbari-8b.patch @@ -0,0 +1,2228 @@ +diff --git a/ChangeLog b/ChangeLog +index 4c7e3ac..708f5bc 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,51 @@ ++Wed Mar 1 12:01:19 2009 Brent Roman ++ ++ * eval.c: fixed missed volatile qualifiers ++ ++ * version.h: bumped date, MBARI version 8A --> 8B ++ ++Wed Feb 27 12:01:19 2009 Brent Roman ++ ++ * rubysig.c: added support for __anyPowerPC__ ++ ++ * version.h: bumped date ++ ++Wed Feb 25 12:01:19 2009 Brent Roman ++ ++ * gc.c: default GC.limit=2e6*sizeof(VALUE) ++ ++ * eval.c: added RB_GC_GUARDs to eval_slit() & more volatile tweaks ++ ++ * re.c: removed unneeded volatile qualifier & copy in rb_regcomp() ++ ++ * version.h: bumped date, MBARI version 7A --> 8A ++ ++Tue Feb 24 00:01:19 2009 Brent Roman ++ ++ * cofigure.in: added --enable-mbari-api and --with-wipe-sites ++ ++ * signal.c: removed CHECK_INTS after kill ++ ++ * test/ruby/suicide.rb: add tiny delay to let signal propogate ++ ++ * gc.c: save regs properly on main stack before marking it! ++ ++ * eval.c: numerous corrections in use of volatile variables w/setjmp() ++ ++ * version.h: bumped date, MBARI version 7+ --> 7A ++ ++Fri Feb 13 00:01:19 2009 Brent Roman ++ ++ * signal.c: CHECK_INTS after kill in case of suicide ++ ++ * version.h: bumped date ++ ++Tue Feb 10 00:01:19 2009 Brent Roman ++ ++ * gc.c: don't redundantly mark stack before base of current thread ++ ++ * version.h: bumped date ++ + Mon Feb 09 00:01:19 2009 Brent Roman + + * rubysig.h: default values for STACK_WIPE_SITES if x86_64 +diff --git a/configure.in b/configure.in +index fe63c0c..885bfc0 100644 +--- a/configure.in ++++ b/configure.in +@@ -151,6 +151,24 @@ AC_ARG_ENABLE(frame-address, + if test $frame_address = yes; then + AC_DEFINE(USE_BUILTIN_FRAME_ADDRESS) + fi ++AC_ARG_ENABLE(mbari-api, ++ [ --enable-mbari-api enable API changes from the MBARI patches. ], ++ [mbari_api=$enableval]) ++if test "$mbari_api" = yes; then ++ AC_DEFINE(MBARI_API) ++fi ++AC_ARG_WITH(wipe-sites, ++[ --with-wipe-sites=MASK override default STACK_WIPES_SITES mask in rubysig.h], ++[wipe_sites=$withval]) ++if test "$wipe_sites" != ""; then ++ case $wipe_sites in ++ none|no) wipe_sites=0x0;; ++ yes) wipe_sites=;; ++ esac ++ if test -n "$wipe_sites"; then ++ AC_DEFINE_UNQUOTED(STACK_WIPE_SITES,$wipe_sites) ++ fi ++fi + + AC_ARG_PROGRAM + +@@ -1783,7 +1801,7 @@ AC_DEFINE_UNQUOTED(RUBY_SITE_ARCHLIB, "${RUBY_SITE_LIB_PATH2}/${sitearch}") + AC_DEFINE_UNQUOTED(RUBY_VENDOR_ARCHLIB, "${RUBY_VENDOR_LIB_PATH2}/${sitearch}") + + AC_ARG_WITH(search-path, +- [ --with-search-path=DIR specify the additional search path], ++ [ --with-search-path= DIR specify the additional search path], + [search_path=$withval]) + if test "$search_path" != ""; then + AC_DEFINE_UNQUOTED(RUBY_SEARCH_PATH,"$search_path") +diff --git a/eval.c b/eval.c +index e9ce2b7..a73bd2b 100644 +--- a/eval.c ++++ b/eval.c +@@ -221,7 +221,7 @@ static VALUE proc_invoke _((VALUE,VALUE,VALUE,VALUE)); + static VALUE rb_f_binding _((VALUE)); + NOINLINE(static void rb_f_END _((void))); + static VALUE rb_f_block_given_p _((void)); +-static VALUE block_pass _((VALUE,NODE*)); ++static VALUE block_pass _((volatile VALUE, NODE *volatile)); + + VALUE rb_cMethod; + static VALUE method_call _((int, VALUE*, VALUE)); +@@ -243,6 +243,30 @@ static int scope_vmode; + VALUE (*ruby_sandbox_save)_((rb_thread_t)); + VALUE (*ruby_sandbox_restore)_((rb_thread_t)); + NODE* ruby_current_node; ++ ++#if 0 ++#define SET_CURRENT_SOURCE() (ruby_sourcefile = ruby_current_node->nd_file, \ ++ ruby_sourceline = nd_line(ruby_current_node)) ++#else ++#define SET_CURRENT_SOURCE() ((void)0) ++#endif ++ ++void ++ruby_set_current_source() ++{ ++ if (ruby_current_node) { ++ ruby_sourcefile = ruby_current_node->nd_file; ++ ruby_sourceline = nd_line(ruby_current_node); ++ } ++} ++ ++#ifdef MBARI_API ++#define SET_METHOD_SOURCE() ruby_set_current_source() ++#else ++#define SET_METHOD_SOURCE() (void)0 ++#endif ++ ++ + int ruby_safe_level = 0; + /* safe-level: + 0 - strings from streams/environment/ARGV are tainted (default) +@@ -726,7 +750,7 @@ rb_attr(klass, id, read, write, ex) + if (!name) { + rb_raise(rb_eArgError, "argument needs to be symbol or string"); + } +- ruby_set_current_source(); /* for Method#__line__ */ ++ SET_METHOD_SOURCE(); + len = strlen(name)+2; + buf = ALLOCA_N(char,len); + snprintf(buf, len, "@%s", name); +@@ -965,7 +989,7 @@ rb_svar(cnt) + ID id; + + if (!ruby_scope->local_tbl) return NULL; +- if (cnt >= ruby_scope->local_tbl[0]) return NULL; ++ if ((ID)cnt >= ruby_scope->local_tbl[0]) return NULL; + id = ruby_scope->local_tbl[cnt+1]; + while (vars) { + if (vars->id == id) return &vars->val; +@@ -1123,10 +1147,11 @@ static void scope_dup _((struct SCOPE *)); + } while (0) + + static VALUE rb_eval _((VALUE,NODE*)); +-static VALUE eval _((VALUE,VALUE,VALUE,const char*,int)); ++static VALUE eval _((VALUE,VALUE,volatile VALUE,const char* volatile,int)); + static NODE *compile _((VALUE, const char*, int)); + +-static VALUE rb_yield_0 _((VALUE, VALUE, VALUE, int, int)); ++static VALUE rb_yield_0 ++ _((volatile VALUE, volatile VALUE, VALUE, int, volatile int)); + + #if STACK_WIPE_SITES & 0x20 + #define wipeBeforeYield() rb_gc_wipe_stack() +@@ -1142,7 +1167,7 @@ static VALUE rb_yield_0 _((VALUE, VALUE, VALUE, int, int)); + #define YIELD_FUNC_LAMBDA 3 + + static VALUE rb_call _((VALUE,VALUE,ID,int,const VALUE*,int,VALUE)); +-static VALUE module_setup _((VALUE,NODE*)); ++static VALUE module_setup _((VALUE,NODE *volatile)); + + static VALUE massign _((VALUE,NODE*,VALUE,int)); + static void assign _((VALUE,NODE*,VALUE,int)); +@@ -1174,22 +1199,6 @@ static VALUE trace_func = 0; + static int tracing = 0; + static void call_trace_func _((rb_event_t,NODE*,VALUE,ID,VALUE)); + +-#if 0 +-#define SET_CURRENT_SOURCE() (ruby_sourcefile = ruby_current_node->nd_file, \ +- ruby_sourceline = nd_line(ruby_current_node)) +-#else +-#define SET_CURRENT_SOURCE() ((void)0) +-#endif +- +-void +-ruby_set_current_source() +-{ +- if (ruby_current_node) { +- ruby_sourcefile = ruby_current_node->nd_file; +- ruby_sourceline = nd_line(ruby_current_node); +- } +-} +- + static void + #ifdef HAVE_STDARG_PROTOTYPES + warn_printf(const char *fmt, ...) +@@ -1251,15 +1260,15 @@ set_backtrace(info, bt) + static void + error_print() + { +- VALUE errat = Qnil; /* OK */ ++ VALUE errat; + volatile VALUE eclass, e; +- const char *einfo; ++ const char * einfo; + long elen; + + if (NIL_P(ruby_errinfo)) return; + + PUSH_TAG(PROT_NONE); +- errat = EXEC_TAG() == 0 ? get_backtrace(ruby_errinfo) : Qnil; ++ errat = EXEC_TAG() ? Qnil : get_backtrace(ruby_errinfo); + if (EXEC_TAG()) goto error; + if (NIL_P(errat)){ + ruby_set_current_source(); +@@ -1442,7 +1451,7 @@ ruby_init() + } + + static VALUE +-eval_node(self, node) ++eval_tree(self, node) + VALUE self; + NODE *node; + { +@@ -1591,12 +1600,13 @@ ruby_finalize() + } + + int +-ruby_cleanup(ex) +- int ex; ++ruby_cleanup(exArg) ++ int exArg; + { + int state; + volatile VALUE errs[2]; +- int nerr; ++ unsigned nerr; ++ volatile int ex = exArg; + + errs[1] = ruby_errinfo; + ruby_safe_level = 0; +@@ -1659,7 +1669,7 @@ ruby_exec_internal() + /* default visibility is private at toplevel */ + SCOPE_SET(SCOPE_PRIVATE); + if ((state = EXEC_TAG()) == 0) { +- eval_node(ruby_top_self, ruby_eval_tree); ++ eval_tree(ruby_top_self, ruby_eval_tree); + } + POP_ITER(); + POP_TAG(); +@@ -1867,8 +1877,8 @@ rb_eval_cmd(cmd, arg, level) + int level; + { + int state; +- VALUE val = Qnil; /* OK */ +- struct SCOPE *saved_scope; ++ VALUE val; ++ struct SCOPE * volatile saved_scope; + volatile int safe = ruby_safe_level; + + if (OBJ_TAINTED(cmd)) { +@@ -1899,9 +1909,7 @@ rb_eval_cmd(cmd, arg, level) + ruby_safe_level = level; + + PUSH_TAG(PROT_NONE); +- if ((state = EXEC_TAG()) == 0) { +- val = eval(ruby_top_self, cmd, Qnil, 0, 0); +- } ++ val = (state = EXEC_TAG()) ? Qnil : eval(ruby_top_self, cmd, Qnil, 0, 0); + if (ruby_scope->flags & SCOPE_DONT_RECYCLE) + scope_dup(saved_scope); + ruby_scope = saved_scope; +@@ -1940,8 +1948,12 @@ ev_const_defined(cref, id, self) + return rb_const_defined(cref->nd_clss, id); + } + +-NOINLINE(static VALUE +-ev_const_get(cref, id, self)) ++NOINLINE(static VALUE ev_const_get _((NODE *cref, ID id, VALUE self))); ++NOINLINE(static void eval_cvar_set _((NODE *node, VALUE result, int warn))); ++NOINLINE(static void eval_cdecl _((VALUE self, NODE *node, VALUE value))); ++ ++static VALUE ++ev_const_get(cref, id, self) + NODE *cref; + ID id; + VALUE self; +@@ -2268,8 +2280,8 @@ rb_copy_node_scope(node, rval) + NODE *rval; + { + NODE *copy; +- +- ruby_set_current_source(); /* for Method#__line__ */ ++ ++ SET_METHOD_SOURCE(); + copy=NEW_NODE(NODE_SCOPE,0,rval,node->nd_next); + + if (node->nd_tbl) { +@@ -2377,10 +2389,10 @@ arg_defined(self, node, buf, type) + static const char* + is_defined(self, node, buf) + VALUE self; +- NODE *node; /* OK */ ++ NODE *node; + char *buf; + { +- VALUE val; /* OK */ ++ VALUE val; + int state; + + again: +@@ -2725,14 +2737,15 @@ call_trace_func(event, node, self, id, klass) + NODE *node; + VALUE self; + ID id; +- VALUE klass; /* OK */ ++ VALUE klass; + { +- int state, raised; ++ int state; ++ volatile int raised; + struct FRAME *prev; +- NODE *node_save; ++ NODE * volatile node_save; + VALUE srcfile; + const char *event_name; +- rb_thread_t th = curr_thread; ++ volatile rb_thread_t th = curr_thread; + + if (!trace_func) return; + if (tracing) return; +@@ -2941,11 +2954,11 @@ class_prefix(self, cpath) + NORETURN(static void return_jump _((VALUE))); + NORETURN(static void break_jump _((VALUE))); + NORETURN(static void next_jump _((VALUE))); +-NORETURN(static void unknown_node _((NODE * volatile))); ++NORETURN(static void unknown_node _((NODE *))); + + static void + unknown_node(node) +- NODE *volatile node; ++ NODE *node; + { + ruby_current_node = 0; + if (node->flags == 0) { +@@ -2959,23 +2972,26 @@ unknown_node(node) + } + } + +- + /* +- functions factored out of rb_eval() to reduce its stack frame size +-*/ +-NOINLINE(static VALUE eval_match2(self, node)) +- VALUE self; +- NODE *node; ++ * functions factored out of rb_eval() to reduce its stack frame size ++ */ ++#define eval_node_0(n,retType, self, node) \ ++NOINLINE(static retType TOKEN_PASTE(eval_,n) _((self, node)));\ ++static retType TOKEN_PASTE(eval_,n)(self, node) ++ ++#define eval_node(n,retType) \ ++ eval_node_0(n,retType, VALUE self, NODE *node) ++#define eval_node_volatile(n,retType) \ ++ eval_node_0(n,retType, volatile VALUE self, NODE * volatile node) ++ ++eval_node(match2, VALUE) + { + VALUE l = rb_eval(self,node->nd_recv); + VALUE r = rb_eval(self,node->nd_value); + return rb_reg_match(l, r); + } + +-NOINLINE(static VALUE +-eval_match3(self, node)) +- VALUE self; +- NODE *node; ++eval_node(match3, VALUE) + { + VALUE r = rb_eval(self,node->nd_recv); + VALUE l = rb_eval(self,node->nd_value); +@@ -2983,16 +2999,14 @@ eval_match3(self, node)) + } + + +-NOINLINE(static void +-eval_opt_n(self, node)) +- VALUE self; +- NODE *node; ++eval_node_volatile(opt_n, void) + { + int state; + PUSH_TAG(PROT_LOOP); + switch (state = EXEC_TAG()) { ++ case TAG_NEXT: ++ state = 0; + case 0: +- opt_n_next: + while (!NIL_P(rb_gets())) { + opt_n_redo: + rb_eval(self, node->nd_body); +@@ -3002,9 +3016,7 @@ eval_opt_n(self, node)) + case TAG_REDO: + state = 0; + goto opt_n_redo; +- case TAG_NEXT: +- state = 0; +- goto opt_n_next; ++ + case TAG_BREAK: + state = 0; + default: +@@ -3015,10 +3027,7 @@ eval_opt_n(self, node)) + } + + +-NOINLINE(static NODE * +-eval_when(self, node)) +- VALUE self; +- NODE *node; ++eval_node(when, NODE*) + { + do { + NODE *tag = node->nd_head; +@@ -3045,10 +3054,7 @@ eval_when(self, node)) + } + + +-NOINLINE (static NODE * +-eval_case(self, node)) +- VALUE self; +- NODE *node; ++eval_node(case, NODE*) + { + VALUE val = rb_eval(self, node->nd_head); + node = node->nd_body; +@@ -3083,27 +3089,26 @@ eval_case(self, node)) + } + + +-NOINLINE (static VALUE +-eval_while(self, node)) +- VALUE self; +- NODE *node; ++eval_node_volatile(while, VALUE) + { + int state; +- volatile VALUE result = Qnil; ++ VALUE result; + PUSH_TAG(PROT_LOOP); + switch (state = EXEC_TAG()) { + case 0: +- if (node->nd_state && !RTEST(rb_eval(self, node->nd_cond))) +- goto while_out; +- do { +- while_redo: ++ if (!(node->nd_state) || RTEST(rb_eval(self, node->nd_cond))) { ++ do { ++ while_redo: + #if STACK_WIPE_SITES & 0x10 +- rb_gc_wipe_stack(); ++ rb_gc_wipe_stack(); + #endif +- rb_eval(self, node->nd_body); +- while_next: +- ; +- } while (RTEST(rb_eval(self, node->nd_cond))); ++ rb_eval(self, node->nd_body); ++ while_next: ++ ; ++ } while (RTEST(rb_eval(self, node->nd_cond))); ++ } /* fall thru */ ++ default: ++ result=Qnil; + break; + + case TAG_REDO: +@@ -3117,38 +3122,33 @@ eval_while(self, node)) + state = 0; + result = prot_tag->retval; + } +- /* fall through */ +- default: +- break; + } +-while_out: + POP_TAG(); + if (state) JUMP_TAG(state); + return result; + } + + +-NOINLINE (static VALUE +-eval_until(self, node)) +- VALUE self; +- NODE *node; ++eval_node_volatile(until, VALUE) + { + int state; +- volatile VALUE result = Qnil; ++ VALUE result; + PUSH_TAG(PROT_LOOP); + switch (state = EXEC_TAG()) { + case 0: +- if (node->nd_state && RTEST(rb_eval(self, node->nd_cond))) +- goto until_out; +- do { +- until_redo: +-#if STACK_WIPE_SITES & 0x10 +- rb_gc_wipe_stack(); +-#endif +- rb_eval(self, node->nd_body); +- until_next: +- ; +- } while (!RTEST(rb_eval(self, node->nd_cond))); ++ if (!(node->nd_state) || !RTEST(rb_eval(self, node->nd_cond))) { ++ do { ++ until_redo: ++ #if STACK_WIPE_SITES & 0x10 ++ rb_gc_wipe_stack(); ++ #endif ++ rb_eval(self, node->nd_body); ++ until_next: ++ ; ++ } while (!RTEST(rb_eval(self, node->nd_cond))); ++ } /* fall thru */ ++ default: ++ result=Qnil; + break; + + case TAG_REDO: +@@ -3162,24 +3162,17 @@ eval_until(self, node)) + state = 0; + result = prot_tag->retval; + } +- /* fall through */ +- default: +- break; + } +- until_out: + POP_TAG(); + if (state) JUMP_TAG(state); + return result; + } + + +-NOINLINE (static VALUE +-eval_iter(self, node)) +- VALUE self; +- NODE *node; ++eval_node_volatile(iter, VALUE) + { + int state; +- volatile VALUE result = Qnil; ++ VALUE result; + + PUSH_TAG(PROT_LOOP); + PUSH_BLOCK(node->nd_var, node->nd_body); +@@ -3194,15 +3187,13 @@ eval_iter(self, node)) + result = rb_eval(self, node->nd_iter); + } + else { +- VALUE recv; +- + _block.flags &= ~BLOCK_D_SCOPE; + BEGIN_CALLARGS; +- recv = rb_eval(self, node->nd_iter); ++ result = rb_eval(self, node->nd_iter); + END_CALLARGS; +- ruby_current_node = node; ++ ruby_current_node = (NODE *)node; + SET_CURRENT_SOURCE(); +- result = rb_call(CLASS_OF(recv),recv,each,0,0,0,self); ++ result = rb_call(CLASS_OF(result),result,each,0,0,0,self); + } + POP_ITER(); + break; +@@ -3220,15 +3211,12 @@ eval_iter(self, node)) + } + + +-NOINLINE (static VALUE +-eval_rescue(self, node)) +- VALUE self; +- NODE *node; ++eval_node_volatile(rescue, VALUE) + { + volatile VALUE e_info = ruby_errinfo; + volatile int rescuing = 0; + int state; +- volatile VALUE result = Qnil; ++ VALUE result; + + PUSH_TAG(PROT_NONE); + if ((state = EXEC_TAG()) == 0) { +@@ -3238,6 +3226,7 @@ eval_rescue(self, node)) + else if (rescuing) { + if (rescuing < 0) { + /* in rescue argument, just reraise */ ++ result = Qnil; + } + else if (state == TAG_RETRY) { + rescuing = state = 0; +@@ -3279,13 +3268,10 @@ eval_rescue(self, node)) + } + + +-NOINLINE (static VALUE +-eval_ensure(self, node)) +- VALUE self; +- NODE *node; ++eval_node_volatile(ensure, VALUE) + { + int state; +- volatile VALUE result = Qnil; ++ VALUE result; + + PUSH_TAG(PROT_NONE); + if ((state = EXEC_TAG()) == 0) { +@@ -3305,10 +3291,7 @@ eval_ensure(self, node)) + } + + +-NOINLINE (static VALUE +-eval_dot(self, node)) +- VALUE self; +- NODE *node; ++eval_node(dot, VALUE) + { + VALUE beg = rb_eval(self, node->nd_beg); + VALUE end = rb_eval(self, node->nd_end); +@@ -3316,10 +3299,7 @@ eval_dot(self, node)) + } + + +-NOINLINE (static VALUE +-eval_flip2(self, node)) +- VALUE self; +- NODE *node; ++eval_node(flip2, VALUE) + { + VALUE *flip = rb_svar(node->nd_cnt); + if (!flip) rb_bug("unexpected local variable"); +@@ -3334,10 +3314,7 @@ eval_flip2(self, node)) + } + + +-NOINLINE (static VALUE +-eval_flip3(self, node)) +- VALUE self; +- NODE *node; ++eval_node(flip3, VALUE) + { + VALUE *flip = rb_svar(node->nd_cnt); + if (!flip) rb_bug("unexpected local variable"); +@@ -3349,10 +3326,7 @@ eval_flip3(self, node)) + } + + +-NOINLINE (static VALUE +-eval_attrasgn(self, node)) +- VALUE self; +- NODE *node; ++eval_node(attrasgn, VALUE) + { + VALUE recv; + int argc; VALUE *argv; /* used in SETUP_ARGS */ +@@ -3378,10 +3352,7 @@ eval_attrasgn(self, node)) + } + + +-NOINLINE (static VALUE +-eval_call(self, node)) +- VALUE self; +- NODE *node; ++eval_node(call, VALUE) + { + VALUE recv; + int argc; VALUE *argv; /* used in SETUP_ARGS */ +@@ -3398,10 +3369,7 @@ eval_call(self, node)) + } + + +-NOINLINE (static VALUE +-eval_fcall(self, node)) +- VALUE self; +- NODE *node; ++eval_node(fcall, VALUE) + { + int argc; VALUE *argv; /* used in SETUP_ARGS */ + TMP_PROTECT; +@@ -3415,10 +3383,8 @@ eval_fcall(self, node)) + return rb_call(CLASS_OF(self),self,node->nd_mid,argc,argv,1,self); + } + +-NOINLINE (static VALUE +-eval_super(self, node)) +- VALUE self; +- NODE *node; ++ ++eval_node(super, VALUE) + { + int argc; VALUE *argv; /* used in SETUP_ARGS */ + TMP_PROTECT; +@@ -3463,15 +3429,12 @@ eval_super(self, node)) + } + + +-NOINLINE (static VALUE +-eval_scope(self, node)) +- VALUE self; +- NODE *node; ++eval_node_volatile(scope, VALUE) + { + int state; +- volatile VALUE result = Qnil; ++ VALUE result; + struct FRAME frame; +- NODE *saved_cref = 0; ++ NODE * volatile saved_cref = 0; + + frame = *ruby_frame; + frame.tmp = ruby_frame; +@@ -3506,10 +3469,7 @@ eval_scope(self, node)) + return result; + } + +-NOINLINE (static VALUE +-eval_op_asgn1(self, node)) +- VALUE self; +- NODE *node; ++eval_node(op_asgn1, VALUE) + { + int argc; VALUE *argv; /* used in SETUP_ARGS */ + VALUE recv, val, tmp; +@@ -3539,10 +3499,7 @@ eval_op_asgn1(self, node)) + } + + +-NOINLINE (static VALUE +-eval_op_asgn2(self, node)) +- VALUE self; +- NODE *node; ++eval_node(op_asgn2, VALUE) + { + ID id = node->nd_next->nd_vid; + VALUE recv, val, tmp; +@@ -3568,10 +3525,7 @@ eval_op_asgn2(self, node)) + } + + +-NOINLINE (static VALUE +-eval_hash(self, node)) +- VALUE self; +- NODE *node; ++eval_node(hash, VALUE) + { + NODE *list; + VALUE hash = rb_hash_new(); +@@ -3591,10 +3545,7 @@ eval_hash(self, node)) + } + + +-NOINLINE (static VALUE +-eval_array(self, node)) +- VALUE self; +- NODE *node; ++eval_node(array, VALUE) + { + VALUE ary; + long i; +@@ -3609,10 +3560,7 @@ eval_array(self, node)) + } + + +-NOINLINE (static VALUE +-eval_slit(self, node)) +- VALUE self; +- NODE *node; ++eval_node(slit, VALUE) + { + VALUE str, str2; + NODE *list = node->nd_next; +@@ -3635,12 +3583,15 @@ eval_slit(self, node)) + } + switch (nd_type(node)) { + case NODE_DREGX: +- return rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, ++ str2 = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, + node->nd_cflag); ++ RB_GC_GUARD(str); /* ensure str is not GC'd in rb_reg_new */ ++ return str2; + case NODE_DREGX_ONCE: /* regexp expand once */ + str2 = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, + node->nd_cflag); + nd_set_type(node, NODE_LIT); ++ RB_GC_GUARD(str); /* ensure str is not GC'd in rb_reg_new */ + return node->nd_lit = str2; + case NODE_LIT: + /* other thread may replace NODE_DREGX_ONCE to NODE_LIT */ +@@ -3654,10 +3605,7 @@ eval_slit(self, node)) + } + + +-NOINLINE (static void +-eval_defn(self, node)) +- VALUE self; +- NODE *node; ++eval_node(defn, void) + { + NODE *body, *defn; + VALUE origin = 0; +@@ -3703,10 +3651,7 @@ eval_defn(self, node)) + } + + +-NOINLINE (static void +-eval_defs(self, node)) +- VALUE self; +- NODE *node; ++eval_node(defs, void) + { + VALUE recv = rb_eval(self, node->nd_recv); + VALUE klass; +@@ -3740,10 +3685,7 @@ eval_defs(self, node)) + } + + +-NOINLINE (static VALUE +-eval_class(self, node)) +- VALUE self; +- NODE *node; ++eval_node(class, VALUE) + { + VALUE super, klass, tmp, cbase; + ID cname; +@@ -3799,10 +3741,7 @@ eval_class(self, node)) + } + + +-NOINLINE (static VALUE +-eval_module(self, node)) +- VALUE self; +- NODE *node; ++eval_node(module, VALUE) + { + VALUE module, cbase; + ID cname; +@@ -3836,10 +3775,7 @@ eval_module(self, node)) + } + + +-NOINLINE (static VALUE +-eval_sclass(self, node)) +- VALUE self; +- NODE *node; ++eval_node(sclass, VALUE) + { + VALUE klass, result; + +@@ -3861,10 +3797,7 @@ eval_sclass(self, node)) + } + + +-NOINLINE (static VALUE +-eval_defined(self, node)) +- VALUE self; +- NODE *node; ++eval_node(defined, VALUE) + { + char buf[20]; + const char *desc = is_defined(self, node->nd_head, buf); +@@ -3872,17 +3805,18 @@ eval_defined(self, node)) + } + + +-NOINLINE (static void +-eval_cvar_set(result, node, bool)) +- VALUE result, bool; ++static void ++eval_cvar_set(node, result, warn) + NODE *node; ++ VALUE result; ++ int warn; + { +- rb_cvar_set(cvar_cbase(), node->nd_vid, result, bool); ++ rb_cvar_set(cvar_cbase(), node->nd_vid, result, warn); + } + + +-NOINLINE (static void +-eval_cdecl(self, node, result)) ++static void ++eval_cdecl(self, node, result) + VALUE self, result; + NODE *node; + { +@@ -3897,7 +3831,7 @@ eval_cdecl(self, node, result)) + static VALUE + rb_eval(self, node) + VALUE self; +- NODE *node; ++ NODE * node; + { + VALUE result; + +@@ -3906,8 +3840,6 @@ again: + result = Qnil; + if (node) { + ruby_current_node = node; +- SET_CURRENT_SOURCE(); +- + switch (nd_type(node)) { + case NODE_BLOCK: + while (node->nd_next) { +@@ -4187,12 +4119,12 @@ again: + rb_raise(rb_eTypeError, "no class/module to define class variable"); + } + result = rb_eval(self, node->nd_value); +- eval_cvar_set(result, node, Qtrue); ++ eval_cvar_set(node, result, Qtrue); + break; + + case NODE_CVASGN: + result = rb_eval(self, node->nd_value); +- eval_cvar_set(result, node, Qfalse); ++ eval_cvar_set(node, result, Qfalse); + break; + + case NODE_LVAR: +@@ -4378,12 +4310,12 @@ again: + static VALUE + module_setup(module, n) + VALUE module; +- NODE *n; ++ NODE * volatile n; + { +- NODE * volatile node = n->nd_body; ++ NODE *node = n->nd_body; + int state; + struct FRAME frame; +- VALUE result = Qnil; /* OK */ ++ VALUE result; + TMP_PROTECT; + + frame = *ruby_frame; +@@ -4774,16 +4706,16 @@ rb_iter_break() + break_jump(Qnil); + } + +-NORETURN(static void rb_longjmp _((int, VALUE))); ++NORETURN(static void rb_longjmp _((volatile int, volatile VALUE))); + static VALUE make_backtrace _((void)); + + static void + rb_longjmp(tag, mesg) +- int tag; +- VALUE mesg; ++ volatile int tag; ++ volatile VALUE mesg; + { + VALUE at; +- rb_thread_t th = curr_thread; ++ volatile rb_thread_t th = curr_thread; + + if (rb_thread_set_raised(th)) { + ruby_errinfo = exception_error; +@@ -4914,14 +4846,12 @@ rb_make_exception(argc, argv) + int argc; + VALUE *argv; + { +- VALUE mesg; ++ VALUE mesg = Qnil; + ID exception; + int n; + +- mesg = Qnil; + switch (argc) { + case 0: +- mesg = Qnil; + break; + case 1: + if (NIL_P(argv[0])) break; +@@ -5140,19 +5070,21 @@ rb_need_block() + + static VALUE + rb_yield_0(val, self, klass, flags, avalue) +- VALUE val, self, klass; /* OK */ +- int flags, avalue; ++ volatile VALUE val, self; ++ VALUE klass; ++ int flags; ++ volatile int avalue; + { +- NODE *node, *var; ++ NODE *var, *volatile node; + volatile VALUE result = Qnil; + volatile VALUE old_cref; + volatile VALUE old_wrapper; + struct BLOCK * volatile block; + struct SCOPE * volatile old_scope; +- int old_vmode; ++ volatile int old_vmode; + struct FRAME frame; + NODE *cnode = ruby_current_node; +- int lambda = flags & YIELD_LAMBDA_CALL; ++ volatile int lambda = flags & YIELD_LAMBDA_CALL; + int state; + + rb_need_block(); +@@ -5262,56 +5194,49 @@ rb_yield_0(val, self, klass, flags, avalue) + + PUSH_ITER(block->iter); + PUSH_TAG(lambda ? PROT_NONE : PROT_YIELD); +- if ((state = EXEC_TAG()) == 0) { +- redo: ++ switch (state = EXEC_TAG()) { ++ case TAG_REDO: ++ state = 0; ++ CHECK_INTS; ++ case 0: + if (nd_type(node) == NODE_CFUNC || nd_type(node) == NODE_IFUNC) { +- switch (node->nd_state) { +- case YIELD_FUNC_LAMBDA: +- if (!avalue) { +- val = rb_ary_new3(1, val); +- } +- break; +- case YIELD_FUNC_AVALUE: +- if (!avalue) { +- val = svalue_to_avalue(val); +- } +- break; +- default: +- if (avalue) { +- val = avalue_to_svalue(val); +- } +- if (val == Qundef && node->nd_state != YIELD_FUNC_SVALUE) +- val = Qnil; ++ switch (node->nd_state) { ++ case YIELD_FUNC_LAMBDA: ++ if (!avalue) { ++ val = rb_ary_new3(1, val); ++ } ++ break; ++ case YIELD_FUNC_AVALUE: ++ if (!avalue) { ++ val = svalue_to_avalue(val); ++ } ++ break; ++ default: ++ if (avalue) { ++ val = avalue_to_svalue(val); ++ } ++ if (val == Qundef && node->nd_state != YIELD_FUNC_SVALUE) ++ val = Qnil; + } + result = (*node->nd_cfnc)(val, node->nd_tval, self); +- } +- else { ++ }else + result = rb_eval(self, node); +- } +- } +- else { +- switch (state) { +- case TAG_REDO: +- state = 0; +- CHECK_INTS; +- goto redo; +- case TAG_NEXT: +- if (!lambda) { +- state = 0; +- result = prot_tag->retval; +- } +- break; +- case TAG_BREAK: +- if (TAG_DST()) { +- result = prot_tag->retval; +- } +- else { +- lambda = Qtrue; /* just pass TAG_BREAK */ +- } +- break; +- default: +- break; +- } ++ break; ++ case TAG_NEXT: ++ if (!lambda) { ++ state = 0; ++ result = prot_tag->retval; ++ } ++ break; ++ case TAG_BREAK: ++ if (TAG_DST()) { ++ result = prot_tag->retval; ++ } ++ else { ++ lambda = Qtrue; /* just pass TAG_BREAK */ ++ } ++ default: ++ break; + } + POP_TAG(); + POP_ITER(); +@@ -5597,11 +5522,12 @@ assign(self, lhs, val, pcall) + + VALUE + rb_iterate(it_proc, data1, bl_proc, data2) +- VALUE (*it_proc) _((VALUE)), (*bl_proc)(ANYARGS); +- VALUE data1, data2; ++ VALUE (* volatile it_proc) _((VALUE)), (*bl_proc)(ANYARGS); ++ volatile VALUE data1; ++ VALUE data2; + { + int state; +- volatile VALUE retval = Qnil; ++ VALUE retval; + NODE *node = NEW_IFUNC(bl_proc, data2); + VALUE self = ruby_top_self; + +@@ -5625,12 +5551,7 @@ rb_iterate(it_proc, data1, bl_proc, data2) + POP_BLOCK(); + POP_TAG(); + +- switch (state) { +- case 0: +- break; +- default: +- JUMP_TAG(state); +- } ++ if (state) JUMP_TAG(state); + return retval; + } + +@@ -5662,16 +5583,17 @@ handle_rescue(self, node) + + VALUE + #ifdef HAVE_STDARG_PROTOTYPES +-rb_rescue2(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*r_proc)(ANYARGS), VALUE data2, ...) ++rb_rescue2(VALUE (* volatile b_proc)(ANYARGS), volatile VALUE data1, ++ VALUE (* volatile r_proc)(ANYARGS), volatile VALUE data2, ...) + #else + rb_rescue2(b_proc, data1, r_proc, data2, va_alist) +- VALUE (*b_proc)(ANYARGS), (*r_proc)(ANYARGS); +- VALUE data1, data2; ++ VALUE (* volatile b_proc)(ANYARGS), (* volatile r_proc)(ANYARGS); ++ volatile VALUE data1, data2; + va_dcl + #endif + { + int state; +- volatile VALUE result; ++ VALUE result; + volatile VALUE e_info = ruby_errinfo; + volatile int handle = Qfalse; + VALUE eclass; +@@ -5730,9 +5652,9 @@ VALUE + rb_protect(proc, data, state) + VALUE (*proc) _((VALUE)); + VALUE data; +- int *state; ++ int * volatile state; + { +- VALUE result = Qnil; /* OK */ ++ VALUE result; + int status; + + PUSH_TAG(PROT_NONE); +@@ -5745,22 +5667,18 @@ rb_protect(proc, data, state) + if (state) { + *state = status; + } +- if (status != 0) { +- return Qnil; +- } +- +- return result; ++ return status ? Qnil : result; + } + + VALUE + rb_ensure(b_proc, data1, e_proc, data2) + VALUE (*b_proc)(); + VALUE data1; +- VALUE (*e_proc)(); +- VALUE data2; ++ VALUE (* volatile e_proc)(); ++ volatile VALUE data2; + { + int state; +- volatile VALUE result = Qnil; ++ VALUE result; + VALUE retval; + + PUSH_TAG(PROT_NONE); +@@ -5768,7 +5686,7 @@ rb_ensure(b_proc, data1, e_proc, data2) + result = (*b_proc)(data1); + } + POP_TAG(); +- retval = prot_tag ? prot_tag->retval : Qnil; /* save retval */ ++ if (prot_tag) retval = prot_tag->retval; /* save retval */ + if (!thread_no_ensure()) { + (*e_proc)(data2); + } +@@ -5782,7 +5700,7 @@ rb_with_disable_interrupt(proc, data) + VALUE (*proc)(); + VALUE data; + { +- VALUE result = Qnil; /* OK */ ++ VALUE result; + int status; + + DEFER_INTS; +@@ -6034,16 +5952,16 @@ call_cfunc(func, recv, len, argc, argv) + + static VALUE + rb_call0(klass, recv, id, oid, argc, argv, body, flags) +- VALUE klass, recv; +- ID id; ++ volatile VALUE klass, recv; ++ volatile ID id; + ID oid; +- int argc; /* OK */ +- VALUE *argv; /* OK */ +- NODE * volatile body; ++ int argc; ++ VALUE *argv; ++ NODE *body; + int flags; + { + NODE *b2; /* OK */ +- volatile VALUE result = Qnil; ++ VALUE result; + int itr; + static int tick; + TMP_PROTECT; +@@ -6150,9 +6068,10 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags) + Data_Get_Struct(body->nd_cval, struct BLOCK, data); + EXEC_EVENT_HOOK(RUBY_EVENT_CALL, data->body, recv, id, klass); + } +- result = proc_invoke(body->nd_cval, rb_ary_new4(argc, argv), recv, klass); ++ result = proc_invoke(body->nd_cval, rb_ary_new4(argc,argv), recv,klass); + if (event_hooks) { +- EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, ruby_current_node, recv, id, klass); ++ EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, ++ ruby_current_node, recv, id, klass); + } + break; + +@@ -6160,7 +6079,7 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags) + { + int state; + VALUE *local_vars; /* OK */ +- NODE *saved_cref = 0; ++ NODE * volatile saved_cref = 0; + + PUSH_SCOPE(); + if (body->nd_rval) { +@@ -6206,8 +6125,9 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags) + + i = node->nd_cnt; + if (i > argc) { +- rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", +- argc, i); ++ rb_raise(rb_eArgError, ++ "wrong number of arguments (%d for %d)", ++ argc, i); + } + if (!node->nd_rest) { + NODE *optnode = node->nd_opt; +@@ -6275,7 +6195,8 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags) + } + POP_TAG(); + if (event_hooks) { +- EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, ruby_current_node, recv, id, klass); ++ EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, ruby_current_node, ++ recv, id, klass); + } + POP_VARS(); + POP_CLASS(); +@@ -6303,7 +6224,6 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags) + + default: + unknown_node(body); +- break; + } + POP_FRAME(); + POP_ITER(); +@@ -6471,7 +6391,7 @@ rb_funcall_rescue(recv, mid, n, va_alist) + va_dcl + #endif + { +- VALUE result = Qnil; /* OK */ ++ VALUE result; + int status; + va_list ar; + +@@ -6687,12 +6607,13 @@ compile(src, file, line) + + static VALUE + eval(self, src, scope, file, line) +- VALUE self, src, scope; +- const char *file; ++ VALUE self, src; ++ volatile VALUE scope; ++ const char * volatile file; + int line; + { + struct BLOCK *data = NULL; +- volatile VALUE result = Qnil; ++ VALUE result; + struct SCOPE * volatile old_scope; + struct BLOCK * volatile old_block; + struct RVarmap * volatile old_dyna_vars; +@@ -6700,7 +6621,7 @@ eval(self, src, scope, file, line) + int volatile old_vmode; + volatile VALUE old_wrapper; + struct FRAME frame; +- NODE *nodesave = ruby_current_node; ++ NODE * volatile nodesave = ruby_current_node; + volatile int iter = ruby_frame->iter; + volatile int safe = ruby_safe_level; + int state; +@@ -6765,7 +6686,7 @@ eval(self, src, scope, file, line) + compile_error(0); + } + if (!NIL_P(result)) ruby_errinfo = result; +- result = eval_node(self, node); ++ result = eval_tree(self, node); + } + POP_TAG(); + POP_CLASS(); +@@ -6891,12 +6812,13 @@ rb_f_eval(argc, argv, self) + static VALUE + exec_under(func, under, cbase, args) + VALUE (*func)(); +- VALUE under, cbase; ++ VALUE under; ++ volatile VALUE cbase; + void *args; + { +- VALUE val = Qnil; /* OK */ ++ VALUE val; + int state; +- int mode; ++ volatile int mode; + struct FRAME *f = ruby_frame; + + PUSH_CLASS(under); +@@ -7182,9 +7104,9 @@ rb_load(fname, wrap) + volatile int prohibit_int = rb_prohibit_interrupt; + volatile ID last_func; + volatile VALUE wrapper = ruby_wrapper; +- volatile VALUE self = ruby_top_self; ++ VALUE self = ruby_top_self; + NODE *volatile last_node; +- NODE *saved_cref = ruby_cref; ++ NODE *volatile saved_cref = ruby_cref; + + if (wrap && ruby_safe_level >= 4) { + StringValue(fname); +@@ -7233,7 +7155,7 @@ rb_load(fname, wrap) + ruby_current_node = 0; + if (state == 0) { + NODE *node; +- volatile int critical; ++ int critical; + + DEFER_INTS; + ruby_in_eval++; +@@ -7245,7 +7167,7 @@ rb_load(fname, wrap) + rb_thread_critical = critical; + ALLOW_INTS; + if (ruby_nerrs == 0) { +- eval_node(self, node); ++ eval_tree(self, node); + } + } + ruby_frame->last_func = last_func; +@@ -7278,7 +7200,7 @@ void + rb_load_protect(fname, wrap, state) + VALUE fname; + int wrap; +- int *state; ++ int * volatile state; + { + int status; + +@@ -7567,7 +7489,7 @@ rb_require_safe(fname, safe) + VALUE fname; + int safe; + { +- VALUE result = Qnil; ++ VALUE result; + volatile VALUE errinfo = ruby_errinfo; + int state; + struct { +@@ -7618,7 +7540,8 @@ rb_require_safe(fname, safe) + rb_provide_feature(feature); + result = Qtrue; + } +- } ++ }else ++ result = Qnil; + } + POP_TAG(); + ruby_current_node = saved.node; +@@ -8286,7 +8209,7 @@ rb_f_at_exit() + void + rb_exec_end_proc() + { +- struct end_proc_data *link, *tmp; ++ struct end_proc_data *tmp, *volatile link; + int status; + volatile int safe = ruby_safe_level; + +@@ -9009,8 +8932,9 @@ proc_invoke(proc, args, self, klass) + int state; + volatile int safe = ruby_safe_level; + volatile VALUE old_wrapper = ruby_wrapper; +- volatile int pcall, avalue = Qtrue; +- volatile VALUE tmp = args; ++ volatile int pcall; ++ int avalue = Qtrue; ++ VALUE tmp = args; + VALUE bvar = Qnil; + + if (rb_block_given_p() && ruby_frame->last_func) { +@@ -9316,15 +9240,15 @@ proc_binding(proc) + + static VALUE + block_pass(self, node) +- VALUE self; +- NODE *node; ++ volatile VALUE self; ++ NODE *volatile node; + { +- VALUE proc = rb_eval(self, node->nd_body); /* OK */ ++ volatile VALUE proc = rb_eval(self, node->nd_body); + VALUE b; + struct BLOCK * volatile old_block; + struct BLOCK _block; + struct BLOCK *data; +- volatile VALUE result = Qnil; ++ VALUE result; + int state; + volatile int orphan; + volatile int safe = ruby_safe_level; +@@ -9371,20 +9295,24 @@ block_pass(self, node) + + PUSH_TAG(PROT_LOOP); + state = EXEC_TAG(); +- if (state == 0) { +- retry: ++ switch (state) { ++ case TAG_RETRY: ++ state = 0; ++ case 0: + proc_set_safe_level(proc); + if (safe > ruby_safe_level) + ruby_safe_level = safe; + result = rb_eval(self, node->nd_iter); +- } +- else if (state == TAG_BREAK && TAG_DST()) { +- result = prot_tag->retval; +- state = 0; +- } +- else if (state == TAG_RETRY) { +- state = 0; +- goto retry; ++ break; ++ case TAG_BREAK: ++ result = Qnil; ++ if (TAG_DST()) { ++ result = prot_tag->retval; ++ state = 0; ++ } ++ break; ++ default: ++ result = Qnil; + } + POP_TAG(); + POP_ITER(); +@@ -9401,7 +9329,6 @@ block_pass(self, node) + default: + JUMP_TAG(state); + } +- + return result; + } + +@@ -9735,7 +9662,7 @@ method_call(argc, argv, method) + VALUE *argv; + VALUE method; + { +- VALUE result = Qnil; /* OK */ ++ VALUE result; + struct METHOD *data; + int safe; + +@@ -10030,12 +9957,9 @@ static VALUE + bmcall(args, method) + VALUE args, method; + { +- volatile VALUE a; +- VALUE ret; +- +- a = svalue_to_avalue(args); +- ret = method_call(RARRAY(a)->len, RARRAY(a)->ptr, method); +- a = Qnil; /* prevent tail call */ ++ VALUE a = svalue_to_avalue(args); ++ VALUE ret = method_call(RARRAY(a)->len, RARRAY(a)->ptr, method); ++ RB_GC_GUARD(a); /* ensure a is not GC'd during method_call */ + return ret; + } + +@@ -10151,7 +10075,7 @@ rb_mod_define_method(argc, argv, mod) + else { + rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); + } +- ruby_set_current_source(); /* for Method#__line__ */ ++ SET_METHOD_SOURCE(); + if (RDATA(body)->dmark == (RUBY_DATA_FUNC)bm_mark) { + node = NEW_DMETHOD(method_unbind(body)); + } +@@ -10184,12 +10108,16 @@ rb_mod_define_method(argc, argv, mod) + } + + ++#ifdef MBARI_API + /* + * call-seq: + * meth.__file__ => String + * + * returns the filename containing this method's definition ++ * + * raises ArgumentError if method has no associated ruby source code ++ * ++ * Only available when MBARI_API extentions are enabled at build time + */ + + static VALUE +@@ -10212,7 +10140,10 @@ method_source_file_name(VALUE method) + * meth.__line__ => Fixnum + * + * returns the starting line number of this method ++ * + * raises ArgumentError if method has no associated ruby source code ++ * ++ * Only available when MBARI_API extentions are enabled at build time + */ + + static VALUE +@@ -10231,13 +10162,15 @@ method_source_line(VALUE method) + } + + +- + /* + * call-seq: + * prc.__file__ => String + * + * returns the filename where this proc is defined ++ * + * raises ArgumentError if proc has no associated ruby source ++ * ++ * Only available when MBARI_API extentions are enabled at build time + */ + + static VALUE +@@ -10259,7 +10192,10 @@ proc_source_file_name(VALUE block) + * prc.__line__ => Fixnum + * + * returns the starting line number of this proc ++ * + * raises ArgumentError if proc has no associated ruby source code ++ * ++ * Only available when MBARI_API extentions are enabled at build time + */ + + static VALUE +@@ -10274,6 +10210,8 @@ proc_source_line(VALUE block) + rb_raise(rb_eArgError, "native Proc"); + } + ++#endif /* MBARI_API */ ++ + + /* + * Proc objects are blocks of code that have been bound to +@@ -10326,8 +10264,6 @@ Init_Proc() + rb_define_method(rb_cProc, "to_s", proc_to_s, 0); + rb_define_method(rb_cProc, "to_proc", proc_to_self, 0); + rb_define_method(rb_cProc, "binding", proc_binding, 0); +- rb_define_method(rb_cProc, "__file__", proc_source_file_name, 0); +- rb_define_method(rb_cProc, "__line__", proc_source_line, 0); + + rb_define_global_function("proc", proc_lambda, 0); + rb_define_global_function("lambda", proc_lambda, 0); +@@ -10348,8 +10284,6 @@ Init_Proc() + rb_define_method(rb_cMethod, "owner", method_owner, 0); + rb_define_method(rb_cMethod, "unbind", method_unbind, 0); + rb_define_method(rb_mKernel, "method", rb_obj_method, 1); +- rb_define_method(rb_cMethod, "__file__", method_source_file_name, 0); +- rb_define_method(rb_cMethod, "__line__", method_source_line, 0); + + rb_cUnboundMethod = rb_define_class("UnboundMethod", rb_cObject); + rb_undef_alloc_func(rb_cUnboundMethod); +@@ -10362,9 +10296,16 @@ Init_Proc() + rb_define_method(rb_cUnboundMethod, "name", method_name, 0); + rb_define_method(rb_cUnboundMethod, "owner", method_owner, 0); + rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1); ++ rb_define_method(rb_cModule, "instance_method", rb_mod_method, 1); ++ ++#ifdef MBARI_API + rb_define_method(rb_cUnboundMethod, "__file__", method_source_file_name, 0); + rb_define_method(rb_cUnboundMethod, "__line__", method_source_line, 0); +- rb_define_method(rb_cModule, "instance_method", rb_mod_method, 1); ++ rb_define_method(rb_cProc, "__file__", proc_source_file_name, 0); ++ rb_define_method(rb_cProc, "__line__", proc_source_line, 0); ++ rb_define_method(rb_cMethod, "__file__", method_source_file_name, 0); ++ rb_define_method(rb_cMethod, "__line__", method_source_line, 0); ++#endif + } + + /* +@@ -10910,7 +10851,7 @@ static void + rb_thread_save_context(th) + rb_thread_t th; + { +- int len; ++ size_t len; + static VALUE tval; + + len = ruby_stack_length(th->stk_start,&th->stk_pos); +@@ -11112,7 +11053,6 @@ rb_thread_restore_context(th, exit) + + #if HAVE_ALLOCA /* use alloca to grow stack in O(1) time */ + VALUE v; +- volatile VALUE *space; + + if (!th->stk_ptr) rb_bug("unsaved context"); + # if !STACK_GROW_DIRECTION /* unknown at compile time */ +@@ -11120,13 +11060,15 @@ rb_thread_restore_context(th, exit) + # endif + # if STACK_GROW_DIRECTION <= 0 + pos -= th->stk_len; +- if (&v > pos) space=ALLOCA_N(VALUE, &v-pos); ++ if (&v > pos) ++ (volatile void *)ALLOCA_N(VALUE, &v-pos); + # endif + # if !STACK_GROW_DIRECTION + }else + # endif + #if STACK_GROW_DIRECTION >= 0 /* stack grows upward */ +- if (&v < pos + th->stk_len) space=ALLOCA_N(VALUE, pos+th->stk_len - &v); ++ if (&v < pos + th->stk_len) ++ (volatile void *)ALLOCA_N(VALUE, pos+th->stk_len - &v); + # endif + + #else /* recursive O(n/1024) if extending stack > 1024 VALUEs */ +@@ -11737,8 +11679,6 @@ rb_thread_select(max, read, write, except, timeout) + return curr_thread->select_value; + } + +-static int rb_thread_join _((rb_thread_t, double)); +- + static int + rb_thread_join(th, limit) + rb_thread_t th; +@@ -13450,7 +13390,7 @@ static VALUE + rb_callcc(self) + VALUE self; + { +- rb_thread_t th = prep4callcc(); ++ volatile rb_thread_t th = prep4callcc(); + return THREAD_SAVE_CONTEXT(th) ? + th->result + : +@@ -13505,18 +13445,21 @@ rb_cont_call(argc, argv, cont) + } + + ++#ifdef MBARI_API + /* + * call-seq: + * cont.thread + * + * Returns the thread on which this continuation can be called +- * (or nil if that thread has died) ++ * or nil if that thread has died + * + * t = Thread.new {callcc{|c| $x=c}; sleep 5} + * sleep 1 + * $x.thread #=> t + * sleep 10 + * $x.thread #=> nil ++ * ++ * Only available when MBARI_API extentions are enabled at build time + */ + static VALUE + rb_cont_thread(cont) +@@ -13526,6 +13469,7 @@ rb_cont_thread(cont) + cc_purge(th); + return th->thread; + } ++#endif + + + struct thgroup { +@@ -13784,21 +13728,20 @@ rb_exec_recursive(func, obj, arg) + VALUE obj; + VALUE arg; + { +- VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key); +- VALUE objid = rb_obj_id(obj); ++ volatile VALUE hash = ++ rb_thread_local_aref(rb_thread_current(), recursive_key); ++ volatile VALUE objid = rb_obj_id(obj); + + if (recursive_check(hash, objid)) { + return (*func) (obj, arg, Qtrue); + } + else { +- VALUE result = Qundef; ++ VALUE result; + int state; + + hash = recursive_push(hash, objid); + PUSH_TAG(PROT_NONE); +- if ((state = EXEC_TAG()) == 0) { +- result = (*func) (obj, arg, Qfalse); +- } ++ result = (state = EXEC_TAG()) ? Qundef : (*func) (obj, arg, Qfalse); + POP_TAG(); + recursive_pop(hash, objid); + if (state) +@@ -13881,7 +13824,9 @@ Init_Thread() + rb_undef_method(CLASS_OF(rb_cCont), "new"); + rb_define_method(rb_cCont, "call", rb_cont_call, -1); + rb_define_method(rb_cCont, "[]", rb_cont_call, -1); ++#ifdef MBARI_API + rb_define_method(rb_cCont, "thread", rb_cont_thread, 0); ++#endif + rb_define_global_function("callcc", rb_callcc, 0); + rb_global_variable(&cont_protect); + +@@ -13933,10 +13878,11 @@ Init_Thread() + + static VALUE + rb_f_catch(dmy, tag) +- VALUE dmy, tag; ++ VALUE dmy; ++ volatile VALUE tag; + { + int state; +- VALUE val = Qnil; /* OK */ ++ VALUE val; + + tag = ID2SYM(rb_to_id(tag)); + PUSH_TAG(tag); +diff --git a/gc.c b/gc.c +index 3314171..167dfcd 100644 +--- a/gc.c ++++ b/gc.c +@@ -43,7 +43,7 @@ int _setjmp(), _longjmp(); + #if defined(MSDOS) || defined(__human68k__) + #define GC_MALLOC_LIMIT 200000 + #else +-#define GC_MALLOC_LIMIT 8000000 ++#define GC_MALLOC_LIMIT (2000000*sizeof(VALUE)) + #endif + #endif + +@@ -60,6 +60,7 @@ static VALUE *stack_limit, *gc_stack_limit; + static size_t malloc_increase = 0; + static size_t malloc_limit = GC_MALLOC_LIMIT; + ++#ifdef MBARI_API + /* + * call-seq: + * GC.limit => increase limit in bytes +@@ -67,6 +68,7 @@ static size_t malloc_limit = GC_MALLOC_LIMIT; + * Get the # of bytes that may be allocated before triggering + * a mark and sweep by the garbarge collector to reclaim unused storage. + * ++ * Only available when MBARI_API extentions are enabled at build time + */ + static VALUE gc_getlimit(VALUE mod) + { +@@ -84,12 +86,14 @@ static VALUE gc_getlimit(VALUE mod) + * GC.limit=5000000 #=> 5000000 + * GC.limit #=> 5000000 + * GC.limit=-50 #=> 5000000 +- * GC.limit=0 #=> 0 ++ * GC.limit=0 #=> 0 #functionally equivalent to GC.stress=true + * ++ * Only available when MBARI_API extentions are enabled at build time + */ + static VALUE gc_setlimit(VALUE mod, VALUE newLimit) + { + long limit = NUM2LONG(newLimit); ++ rb_secure(2); + if (limit < 0) return gc_getlimit(mod); + malloc_limit = limit; + return newLimit; +@@ -98,12 +102,13 @@ static VALUE gc_setlimit(VALUE mod, VALUE newLimit) + + /* + * call-seq: +- * GC.increase ++ * GC.growth + * + * Get # of bytes that have been allocated since the last mark & sweep + * ++ * Only available when MBARI_API extentions are enabled at build time + */ +-static VALUE gc_increase(VALUE mod) ++static VALUE gc_growth(VALUE mod) + { + return ULONG2NUM(malloc_increase); + } +@@ -115,6 +120,7 @@ static VALUE gc_increase(VALUE mod) + * + * Purge ghost references from recently freed stack space + * ++ * Only available when MBARI_API extentions are enabled at build time + */ + static VALUE gc_exorcise(VALUE mod) + { +@@ -122,6 +128,55 @@ static VALUE gc_exorcise(VALUE mod) + return Qnil; + } + ++#else /* no api changes */ ++ ++static size_t unstressed_malloc_limit = GC_MALLOC_LIMIT; ++ ++/* ++ * call-seq: ++ * GC.stress => true or false ++ * ++ * returns current status of GC stress mode. ++ * ++ * Only available when MBARI_API extentions are disabled at build time ++ */ ++ ++static VALUE ++gc_stress_get(self) ++ VALUE self; ++{ ++ return malloc_limit ? Qfalse : Qtrue; ++} ++ ++/* ++ * call-seq: ++ * GC.stress = bool => bool ++ * ++ * updates GC stress mode. ++ * ++ * When GC.stress = true, GC is invoked for all GC opportunity: ++ * all memory and object allocation. ++ * ++ * Since it makes Ruby very slow, it is only for debugging. ++ * ++ * Only available when MBARI_API extentions are enabled at build time ++ */ ++ ++static VALUE ++gc_stress_set(self, bool) ++ VALUE self, bool; ++{ ++ rb_secure(2); ++ if (!RTEST(bool)) ++ malloc_limit = unstressed_malloc_limit; ++ else if (malloc_limit > 0) { ++ unstressed_malloc_limit = malloc_limit; ++ malloc_limit = 0; ++ } ++ return bool; ++} ++ ++#endif /* MBARI_API */ + + static void run_final(); + static VALUE nomem_error; +@@ -512,6 +567,7 @@ static unsigned int STACK_LEVEL_MAX = 655300; + + #ifndef nativeAllocA + /* portable way to return an approximate stack pointer */ ++NOINLINE(VALUE *__sp(void)); + VALUE *__sp(void) { + VALUE tos; + return &tos; +@@ -548,7 +604,7 @@ stack_grow_direction(addr) + # define STACK_UPPER(a, b) (rb_gc_stack_grow_direction > 0 ? a : b) + #endif + +-int ++size_t + ruby_stack_length(start, base) + VALUE *start, **base; + { +@@ -733,7 +789,7 @@ mark_locations_array(x, n) + } + } + +-void inline ++inline void + rb_gc_mark_locations(start, end) + VALUE *start, *end; + { +@@ -1103,7 +1159,7 @@ gc_sweep() + RVALUE *p, *pend, *final_list; + int freed = 0; + int i; +- unsigned long free_min = 0; ++ long free_min = 0; + + for (i = 0; i < heaps_used; i++) { + free_min += heaps[i].limit; +@@ -1376,7 +1432,6 @@ garbage_collect_0(VALUE *top_frame) + { + struct gc_list *list; + struct FRAME * frame; +- jmp_buf save_regs_gc_mark; + SET_STACK_END; + + #ifdef HAVE_NATIVETHREAD +@@ -1415,19 +1470,15 @@ garbage_collect_0(VALUE *top_frame) + mark_tbl(finalizer_table); + } + +- FLUSH_REGISTER_WINDOWS; +- /* This assumes that all registers are saved into the jmp_buf (and stack) */ +- rb_setjmp(save_regs_gc_mark); +- mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *)); + #if STACK_GROW_DIRECTION < 0 +- rb_gc_mark_locations(top_frame, rb_gc_stack_start); ++ rb_gc_mark_locations(top_frame, rb_curr_thread->stk_start); + #elif STACK_GROW_DIRECTION > 0 +- rb_gc_mark_locations(rb_gc_stack_start, top_frame + 1); ++ rb_gc_mark_locations(rb_curr_thread->stk_start, top_frame + 1); + #else + if (rb_gc_stack_grow_direction < 0) +- rb_gc_mark_locations(top_frame, rb_gc_stack_start); ++ rb_gc_mark_locations(top_frame, rb_curr_thread->stk_start); + else +- rb_gc_mark_locations(rb_gc_stack_start, top_frame + 1); ++ rb_gc_mark_locations(rb_curr_thread->stk_start, top_frame + 1); + #endif + #ifdef __ia64 + /* mark backing store (flushed register window on the stack) */ +@@ -1436,7 +1487,7 @@ garbage_collect_0(VALUE *top_frame) + #endif + #if defined(__human68k__) || defined(__mc68000__) + rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2), +- (VALUE*)((char*)rb_gc_stack_start + 2)); ++ (VALUE*)((char*)rb_curr_thread->stk_start + 2)); + #endif + rb_gc_mark_threads(); + +@@ -1473,13 +1524,17 @@ garbage_collect_0(VALUE *top_frame) + static void + garbage_collect() + { ++ jmp_buf save_regs_gc_mark; + VALUE *top = __sp(); ++ FLUSH_REGISTER_WINDOWS; ++ /* This assumes that all registers are saved into the jmp_buf (and stack) */ ++ rb_setjmp(save_regs_gc_mark); ++ + #if STACK_WIPE_SITES & 0x400 + # ifdef nativeAllocA + if (__stack_past (top, stack_limit)) { + /* allocate a large frame to ensure app stack cannot grow into GC stack */ +- volatile char *spacer = +- nativeAllocA(__stack_depth((void*)stack_limit,(void*)top)); ++ (volatile void*) nativeAllocA(__stack_depth((void*)stack_limit,(void*)top)); + } + garbage_collect_0(top); + # else /* no native alloca() available */ +@@ -2123,10 +2178,15 @@ Init_GC() + rb_define_singleton_method(rb_mGC, "start", rb_gc_start, 0); + rb_define_singleton_method(rb_mGC, "enable", rb_gc_enable, 0); + rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0); ++#ifdef MBARI_API + rb_define_singleton_method(rb_mGC, "limit", gc_getlimit, 0); + rb_define_singleton_method(rb_mGC, "limit=", gc_setlimit, 1); +- rb_define_singleton_method(rb_mGC, "increase", gc_increase, 0); ++ rb_define_singleton_method(rb_mGC, "growth", gc_growth, 0); + rb_define_singleton_method(rb_mGC, "exorcise", gc_exorcise, 0); ++#else ++ rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0); ++ rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1); ++#endif + rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0); + + rb_mObSpace = rb_define_module("ObjectSpace"); +diff --git a/intern.h b/intern.h +index e434bc5..ee9185e 100644 +--- a/intern.h ++++ b/intern.h +@@ -251,7 +251,7 @@ VALUE rb_file_directory_p _((VALUE,VALUE)); + /* gc.c */ + NORETURN(void rb_memerror __((void))); + int ruby_stack_check _((void)); +-int ruby_stack_length _((VALUE *,VALUE**)); ++size_t ruby_stack_length _((VALUE *,VALUE**)); + int rb_during_gc _((void)); + char *rb_source_filename _((const char*)); + void rb_gc_mark_locations _((VALUE*, VALUE*)); +diff --git a/node.h b/node.h +index e79f526..3295cf7 100644 +--- a/node.h ++++ b/node.h +@@ -409,13 +409,11 @@ struct rb_thread { + + VALUE result; + +- long stk_len, stk_max; ++ size_t stk_len, stk_max; + VALUE *stk_ptr, *stk_pos, *stk_start; + #ifdef __ia64 +- long bstr_len; +- long bstr_max; +- VALUE *bstr_ptr; +- VALUE *bstr_pos; ++ size_t bstr_len, bstr_max; ++ VALUE *bstr_ptr, *bstr_pos; + #endif + + struct FRAME *frame; +diff --git a/re.c b/re.c +index a0ac6a8..85d013c 100644 +--- a/re.c ++++ b/re.c +@@ -1468,18 +1468,18 @@ VALUE + rb_reg_regcomp(str) + VALUE str; + { +- volatile VALUE save_str = str; +- if (reg_cache && RREGEXP(reg_cache)->len == RSTRING(str)->len +- && case_cache == ruby_ignorecase +- && kcode_cache == reg_kcode +- && memcmp(RREGEXP(reg_cache)->str, RSTRING(str)->ptr, RSTRING(str)->len) == 0) +- return reg_cache; +- +- case_cache = ruby_ignorecase; +- kcode_cache = reg_kcode; +- reg_cache = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, ruby_ignorecase); +- RB_GC_GUARD(save_str); ++ if (reg_cache && RREGEXP(reg_cache)->len == RSTRING(str)->len ++ && case_cache == ruby_ignorecase ++ && kcode_cache == reg_kcode ++ && memcmp(RREGEXP(reg_cache)->str, RSTRING(str)->ptr, ++ RSTRING(str)->len) == 0) + return reg_cache; ++ ++ case_cache = ruby_ignorecase; ++ kcode_cache = reg_kcode; ++ reg_cache = rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, ruby_ignorecase); ++ RB_GC_GUARD(str); ++ return reg_cache; + } + + static int +diff --git a/rubysig.h b/rubysig.h +index 8a11cf4..fae0869 100644 +--- a/rubysig.h ++++ b/rubysig.h +@@ -15,6 +15,11 @@ + + #include + ++#if defined __ppc__ || defined __powerpc__ || \ ++ defined __ppc64__ || defined __powerpc64__ ++#define __anyPowerPC__ 1 /* for compatibility with older gcc versions */ ++#endif ++ + /* STACK_WIPE_SITES determines where attempts are made to exorcise + "ghost object refereces" from the stack and how the stack is cleared: + +@@ -65,7 +70,7 @@ + #ifndef STACK_WIPE_SITES + # ifdef __x86_64__ /* deal with "red zone" by not inlining stack clearing */ + # define STACK_WIPE_SITES 0x6770 +-# elif defined __ppc__ || defined __ppc64__ /* On any PowerPC, deal with... */ ++# elif defined __anyPowerPC__ /* On any PowerPC, deal with... */ + # define STACK_WIPE_SITES 0x7764 /* red zone & alloc(0) doesn't return sp */ + # else + # define STACK_WIPE_SITES 0x8770 /*normal case, use 0x4770 if problems arise*/ +@@ -211,11 +216,12 @@ static inline VALUE *__sp(void) \ + VALUE *sp; asm(asmb); \ + return sp; \ + } +-# if defined __ppc__ || defined __ppc64__ ++# ifdef __anyPowerPC__ + __defspfn("addi %0, r1, 0": "=r"(sp)) + # elif defined __i386__ + __defspfn("movl %%esp, %0": "=r"(sp)) + # elif defined __x86_64__ ++#warn ===> x86_64 inline assembler is known to crash -- change STACK_WIPE_SITES + __defspfn("movq %%rsp, %0": "=r"(sp)) + # elif __arm__ + __defspfn("mov %0, sp": "=r"(sp)) +diff --git a/test/ruby/suicide.rb b/test/ruby/suicide.rb +index 2687ed0..c7a0a67 100644 +--- a/test/ruby/suicide.rb ++++ b/test/ruby/suicide.rb +@@ -1,2 +1,4 @@ + STDERR.reopen(STDOUT) +-at_exit{Process.kill(:INT, $$)} ++at_exit{Process.kill(:INT, $$); sleep 0} ++# brent@mbari.org says ++# sleep 0 avoids race between process termination and signal reception +diff --git a/version.h b/version.h +index c608764..b336dd7 100644 +--- a/version.h ++++ b/version.h +@@ -1,15 +1,15 @@ + #define RUBY_VERSION "1.8.7" +-#define RUBY_RELEASE_DATE "2009-2-9" ++#define RUBY_RELEASE_DATE "2009-3-1" + #define RUBY_VERSION_CODE 187 +-#define RUBY_RELEASE_CODE 20090209 ++#define RUBY_RELEASE_CODE 20090301 + #define RUBY_PATCHLEVEL 72 + + #define RUBY_VERSION_MAJOR 1 + #define RUBY_VERSION_MINOR 8 + #define RUBY_VERSION_TEENY 7 + #define RUBY_RELEASE_YEAR 2009 +-#define RUBY_RELEASE_MONTH 2 +-#define RUBY_RELEASE_DAY 9 ++#define RUBY_RELEASE_MONTH 3 ++#define RUBY_RELEASE_DAY 1 + + #ifdef RUBY_EXTERN + RUBY_EXTERN const char ruby_version[]; +@@ -28,7 +28,14 @@ RUBY_EXTERN const char *ruby_copyright; + #include "rubysig.h" + + #define string_arg(s) #s +-#define MBARI_RELEASE(wipe_sites) "MBARI 7/" string_arg(wipe_sites) ++ ++#ifdef MBARI_API ++#define _mbari_rev_ "MBARI" ++#else ++#define _mbari_rev_ "mbari" ++#endif ++ ++#define MBARI_RELEASE(wipe_sites) _mbari_rev_ " 8B/" string_arg(wipe_sites) + + #define RUBY_RELEASE_STR MBARI_RELEASE(STACK_WIPE_SITES) " on patchlevel" + #define RUBY_RELEASE_NUM RUBY_PATCHLEVEL +--- mbari8A/configure 2008-08-10 17:39:51.000000000 -0700 ++++ matzruby/configure 2009-02-25 21:16:28.000000000 -0800 +@@ -1347,6 +1347,7 @@ + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-frame-address use GCC __builtin_frame_address(). ++ --enable-mbari-api enable API changes from the MBARI patches. + --disable-largefile omit support for large files + --enable-pthread use pthread library. + --disable-fastthread do not use the fastthread mutex +@@ -1359,6 +1360,7 @@ + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --without-gcc never use gcc ++ --with-wipe-sites=MASK override default STACK_WIPES_SITES mask in rubysig.h + --with-winsock2 link winsock2 (MinGW only) + --with-libc_r link libc_r if possible (FreeBSD only) + --with-setjmp-type select setjmp type +@@ -1367,7 +1369,7 @@ + --with-static-linked-ext link external modules statically + --with-sitedir=DIR site libraries in DIR [LIBDIR/ruby/site_ruby] + --with-vendordir=DIR vendor libraries in DIR [LIBDIR/ruby/vendor_ruby] +- --with-search-path=DIR specify the additional search path ++ --with-search-path= DIR specify the additional search path + --with-mantype=TYPE specify man page type; TYPE is one of man and doc + + Some influential environment variables: +@@ -2042,6 +2044,35 @@ + _ACEOF + + fi ++# Check whether --enable-mbari-api was given. ++if test "${enable_mbari_api+set}" = set; then ++ enableval=$enable_mbari_api; mbari_api=$enableval ++fi ++ ++if test "$mbari_api" = yes; then ++ cat >>confdefs.h <<\_ACEOF ++#define MBARI_API 1 ++_ACEOF ++ ++fi ++ ++# Check whether --with-wipe-sites was given. ++if test "${with_wipe_sites+set}" = set; then ++ withval=$with_wipe_sites; wipe_sites=$withval ++fi ++ ++if test "$wipe_sites" != ""; then ++ case $wipe_sites in ++ none|no) wipe_sites=0x0;; ++ yes) wipe_sites=;; ++ esac ++ if test -n "$wipe_sites"; then ++ cat >>confdefs.h <<_ACEOF ++#define STACK_WIPE_SITES $wipe_sites ++_ACEOF ++ ++ fi ++fi + + test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" diff --git a/patches/ruby/1.8.7/p72/mbari7.patch b/patches/ruby/1.8.7/p72/mbari7.patch new file mode 100644 index 0000000000..60ad8902ec --- /dev/null +++ b/patches/ruby/1.8.7/p72/mbari7.patch @@ -0,0 +1,1509 @@ +diff -ru ruby-1.8.7-p72/ChangeLog ruby-1.8.7-mbari/ChangeLog +--- ruby-1.8.7-p72/ChangeLog 2009-02-09 21:21:30.000000000 -0800 ++++ ruby-1.8.7-mbari/ChangeLog 2009-02-09 20:24:44.000000000 -0800 +@@ -1,3 +1,126 @@ ++Mon Feb 09 00:01:19 2009 Brent Roman ++ ++ * rubysig.h: default values for STACK_WIPE_SITES if x86_64 ++ cast builtin_alloca result to (VALUE *) ++ ++ * gc.c: don't use builtin-frame-address at all ++ ++ * version.h: bumped date ++ ++Sun Feb 08 00:01:19 2009 Brent Roman ++ ++ * rubysig.h: changed default values for STACK_WIPE_SITES ++ ++ * gc.c: don't trust config's USE_BUILTIN_FRAME_ADDRESS ++ ++ * version.h: bumped date ++ ++ ++Thu Jan 23 00:01:19 2009 Brent Roman ++ ++ * rubysig.h: remapped wipe methods to avoid values > 9 ++ added cases for __ppc64__ and __x86_64__ ++ ++ * missing/alloca.c: made 64-bit clean ++ ++ * version.h: bumped date ++ ++ ++Sun Jan 18 20:15:36 2009 Brent Roman ++ ++ * rubysig.h: added support for STACK_WIPE_METHOD==5 (x86 asm) ++ ++ * gc.c: allow another STACK_WIPE_METHOD ++ ++ * version.h: bumped date ++ ++ ++Sat Jan 17 20:15:36 2009 Brent Roman ++ ++ * gc.c: use separate gc stack so it never need be wiped ++ ++ * version.h: bumped date ++ ++ ++Fri Jan 16 20:15:36 2009 Brent Roman ++ ++ * gc.c: added GC_STACK_PAD, renamed stack_gc_limit->gc_stack_limit ++ optionally wipe the entire GC stack after each gc pass ++ ++ * rubysig.h: default STACK_WIPE_SITES changed to 0x4770 ++ ++ * version.h: bumped date ++ ++ ++Wed Jan 14 20:15:36 2009 Brent Roman ++ ++ * eval.c: declare wipe_after with gnu always_inline attribute ++ ++ * rubysig.h: use alloca(0) to get sp for all CPU except PowerPC ++ (less likely to trash stack when clearing it) ++ ++ * version.h: bumped date ++ ++ ++Sun Jan 13 20:15:36 2009 Brent Roman ++ ++ * rubysig.h: moved #defs to configure alloca here from gc.c ++ added missing # to #else ++ ++ * gc.c: removed #defs to configurure alloca ++ set_stack_size must handle signed rlim_t for Darwin & BSD Unix ++ ++ * version.h: bumped date ++ ++ ++Sun Jan 11 20:15:36 2009 Brent Roman ++ ++ * rubysig.h: added support for multiple STACK_WIPE_METHODs ++ added __stack_depth() ++ added 2nd param to stack_past() ++ __sp() returns stack pointer in an efficent, portable way ++ ++ * gc.c: STACK_END uses __sp() ++ STACK_UPPER now takes only two parameters ++ added rb_gc_wipe_stack() ++ rb_mark_tbl() and mark_hash() implemented as #define macros ++ added STACK_END parameters to __stack_past() invocations ++ exploited missed opportunities for tail recursion in markchilren ++ ++ * version.h: bumped date ++ ++ ++Mon Jan 5 20:15:36 2009 Brent Roman ++ ++ * common.mk: added dependency on rubysig.h to version.h ++ ++ * eval.c: added wipeAfter and STACK_WIPE_SITES cofiguration options ++ ++ * gc.c: added STACK_WIPE_SITES cofiguration options ++ added GC.exorcise method ++ ++ * rubysig.h: added STACK_WIPE_SITES cofiguration options ++ when available, use gcc asm to optimize wipe_stack ++ ++ * version.h: include STACK_WIPE_SITES options in MBARI release string ++ ++ ++Sun Jan 4 20:15:36 2009 Brent Roman ++ ++ * eval.c: eliminated up_stk_extent(), wipe_stack in rb_thread_switch ++ ++ * gc.c: removed lev counter args, check stack pointer instead ++ streamlined SET_STACK_END and STACK_END, stack_length(), etc. ++ added TOP_FRAME to use gcc's builtin frame_address ++ optimized is_heap_pointer() ++ gc_mark_rest() does not need to copy entire mark_stack! ++ added set_stack_size() to properly hande RLIM_INFINITY ++ ++ * rubysig.h: repaired broken pseudo preemptive thread switching ++ removed rb_gc_malloc_increase & limit ++ replaced buggy __stack_grown* with __stack_past* macros ++ ++ + Tue Dec 19 20:15:36 2008 Brent Roman + + * eval.c: added (Method|Proc)#(__line__|__file__) methods +diff -ru ruby-1.8.7-p72/common.mk ruby-1.8.7-mbari/common.mk +--- ruby-1.8.7-p72/common.mk 2008-08-03 22:05:38.000000000 -0700 ++++ ruby-1.8.7-mbari/common.mk 2009-01-05 01:18:37.000000000 -0800 +@@ -462,7 +462,7 @@ + {$(VPATH)}env.h {$(VPATH)}node.h {$(VPATH)}st.h {$(VPATH)}util.h + version.$(OBJEXT): {$(VPATH)}version.c {$(VPATH)}ruby.h config.h \ + {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \ +- {$(VPATH)}version.h ++ {$(VPATH)}rubysig.h {$(VPATH)}version.h + + dist: $(PROGRAM) + $(RUNRUBY) $(srcdir)/distruby.rb +diff -ru ruby-1.8.7-p72/eval.c ruby-1.8.7-mbari/eval.c +--- ruby-1.8.7-p72/eval.c 2009-02-09 21:21:30.000000000 -0800 ++++ ruby-1.8.7-mbari/eval.c 2009-01-22 02:54:08.000000000 -0800 +@@ -3,7 +3,7 @@ + eval.c - + + $Author: brent $ +- $Date: 2008/12/20 07:47:22 $ ++ $Date: 2009/01/15 07:41:46 $ + created at: Thu Jun 10 14:22:17 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -1028,14 +1028,26 @@ + #define PROT_LAMBDA INT2FIX(2) /* 5 */ + #define PROT_YIELD INT2FIX(3) /* 7 */ + +-#define EXEC_TAG() ruby_setjmp(((void)0), prot_tag->buf) +- +-static inline +-int up_stk_extent(int status) ++#if STACK_WIPE_SITES & 0x42 ++#ifdef __GNUC__ ++static inline int wipeAfter(int) __attribute__((always_inline)); ++#endif ++static inline int wipeAfter(int status) + { +- rb_gc_update_stack_extent(); ++ rb_gc_wipe_stack(); + return status; + } ++#else ++#define wipeAfter(status) status ++#endif ++#if STACK_WIPE_SITES & 2 ++#define wipeAfterTag(status) wipeAfter(status) ++#else ++#define wipeAfterTag(status) status ++#endif ++ ++#define EXEC_TAG_0() ruby_setjmp(((void)0), prot_tag->buf) ++#define EXEC_TAG() wipeAfterTag(EXEC_TAG_0()) + + #define JUMP_TAG(st) do { \ + ruby_frame = prot_tag->frame; \ +@@ -1116,6 +1128,12 @@ + + static VALUE rb_yield_0 _((VALUE, VALUE, VALUE, int, int)); + ++#if STACK_WIPE_SITES & 0x20 ++#define wipeBeforeYield() rb_gc_wipe_stack() ++#else ++#define wipeBeforeYield() (void)0 ++#endif ++ + #define YIELD_LAMBDA_CALL 1 + #define YIELD_PROC_CALL 2 + #define YIELD_PUBLIC_DEF 4 +@@ -3079,6 +3097,9 @@ + goto while_out; + do { + while_redo: ++#if STACK_WIPE_SITES & 0x10 ++ rb_gc_wipe_stack(); ++#endif + rb_eval(self, node->nd_body); + while_next: + ; +@@ -3121,6 +3142,9 @@ + goto until_out; + do { + until_redo: ++#if STACK_WIPE_SITES & 0x10 ++ rb_gc_wipe_stack(); ++#endif + rb_eval(self, node->nd_body); + until_next: + ; +@@ -5347,6 +5371,7 @@ + rb_yield(val) + VALUE val; + { ++ wipeBeforeYield(); + return rb_yield_0(val, 0, 0, 0, Qfalse); + } + +@@ -5395,6 +5420,7 @@ + loop_i() + { + for (;;) { ++ wipeBeforeYield(); + rb_yield_0(Qundef, 0, 0, 0, Qfalse); + CHECK_INTS; + } +@@ -10949,6 +10975,9 @@ + rb_thread_switch(n) + int n; + { ++#if STACK_WIPE_SITES & 1 ++ rb_gc_wipe_stack(); ++#endif + rb_trap_immediate = (curr_thread->flags&0x100)?1:0; + switch (n) { + case 0: +@@ -10985,7 +11014,7 @@ + return 1; + } + +-#define THREAD_SAVE_CONTEXT(th) (rb_thread_switch(up_stk_extent( \ ++#define THREAD_SAVE_CONTEXT(th) (rb_thread_switch( wipeAfter(\ + ruby_setjmp(rb_thread_save_context(th), (th)->context)))) + + NORETURN(static void rb_thread_restore_context _((rb_thread_t,int))); +@@ -13911,7 +13940,7 @@ + + tag = ID2SYM(rb_to_id(tag)); + PUSH_TAG(tag); +- if ((state = EXEC_TAG()) == 0) { ++ if ((state = wipeAfter(EXEC_TAG_0())) == 0) { + val = rb_yield_0(tag, 0, 0, 0, Qfalse); + } + else if (state == TAG_THROW && tag == prot_tag->dst) { +@@ -13979,6 +14008,9 @@ + if (!tt) { + rb_name_error(SYM2ID(tag), "uncaught throw `%s'", rb_id2name(SYM2ID(tag))); + } ++#if STACK_WIPE_SITES & 0x800 ++ rb_gc_update_stack_extent(); ++#endif + rb_trap_restore_mask(); + JUMP_TAG(TAG_THROW); + #ifndef __GNUC__ +diff -ru ruby-1.8.7-p72/gc.c ruby-1.8.7-mbari/gc.c +--- ruby-1.8.7-p72/gc.c 2009-02-09 21:21:30.000000000 -0800 ++++ ruby-1.8.7-mbari/gc.c 2009-02-09 20:24:44.000000000 -0800 +@@ -3,7 +3,7 @@ + gc.c - + + $Author: brent $ +- $Date: 2008/12/18 07:43:46 $ ++ $Date: 2009/02/09 20:45:03 $ + created at: Tue Oct 5 09:44:46 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -22,10 +22,6 @@ + #include + #include + +-#ifdef HAVE_SYS_TIME_H +-#include +-#endif +- + #ifdef HAVE_SYS_RESOURCE_H + #include + #endif +@@ -43,25 +39,6 @@ + int _setjmp(), _longjmp(); + #endif + +-/* Make alloca work the best possible way. */ +-#ifdef __GNUC__ +-# ifndef atarist +-# ifndef alloca +-# define alloca __builtin_alloca +-# endif +-# endif /* atarist */ +-#else +-# ifdef HAVE_ALLOCA_H +-# include +-# else +-# ifndef _AIX +-# ifndef alloca /* predefined by HP cc +Olibcalls */ +-void *alloca (); +-# endif +-# endif /* AIX */ +-# endif /* HAVE_ALLOCA_H */ +-#endif /* __GNUC__ */ +- + #ifndef GC_MALLOC_LIMIT + #if defined(MSDOS) || defined(__human68k__) + #define GC_MALLOC_LIMIT 200000 +@@ -70,11 +47,18 @@ + #endif + #endif + ++#ifndef GC_LEVEL_MAX /*maximum # of VALUEs on 'C' stack during GC*/ ++#define GC_LEVEL_MAX 8000 ++#endif ++#ifndef GC_STACK_PAD ++#define GC_STACK_PAD 200 /* extra padding VALUEs for GC stack */ ++#endif ++#define GC_STACK_MAX (GC_LEVEL_MAX+GC_STACK_PAD) + +-size_t rb_gc_malloc_increase = 0; +-#define malloc_increase rb_gc_malloc_increase +-static unsigned long malloc_limit = GC_MALLOC_LIMIT; +-size_t rb_gc_malloc_limit = GC_MALLOC_LIMIT-GC_MALLOC_LIMIT/8; ++static VALUE *stack_limit, *gc_stack_limit; ++ ++static size_t malloc_increase = 0; ++static size_t malloc_limit = GC_MALLOC_LIMIT; + + /* + * call-seq: +@@ -108,7 +92,6 @@ + long limit = NUM2LONG(newLimit); + if (limit < 0) return gc_getlimit(mod); + malloc_limit = limit; +- rb_gc_malloc_limit = malloc_limit - malloc_limit/8; + return newLimit; + } + +@@ -126,6 +109,20 @@ + } + + ++/* ++ * call-seq: ++ * GC.exorcise ++ * ++ * Purge ghost references from recently freed stack space ++ * ++ */ ++static VALUE gc_exorcise(VALUE mod) ++{ ++ rb_gc_wipe_stack(); ++ return Qnil; ++} ++ ++ + static void run_final(); + static VALUE nomem_error; + static void garbage_collect(); +@@ -174,7 +171,9 @@ + rb_memerror(); + } + } ++#if STACK_WIPE_SITES & 0x100 + rb_gc_update_stack_extent(); ++#endif + return mem; + } + +@@ -214,7 +213,9 @@ + rb_memerror(); + } + } ++#if STACK_WIPE_SITES & 0x200 + rb_gc_update_stack_extent(); ++#endif + return mem; + } + +@@ -509,38 +510,32 @@ + # define STACK_LEVEL_MAX 655300 + #endif + +-#ifdef C_ALLOCA +-# define SET_STACK_END VALUE stack_end; alloca(0); ++#ifndef nativeAllocA ++ /* portable way to return an approximate stack pointer */ ++VALUE *__sp(void) { ++ VALUE tos; ++ return &tos; ++} ++# define SET_STACK_END VALUE stack_end + # define STACK_END (&stack_end) + #else +-# if defined(__GNUC__) && defined(USE_BUILTIN_FRAME_ADDRESS) && !defined(__ia64) +-# if ( __GNUC__ == 3 && __GNUC_MINOR__ > 0 ) || __GNUC__ > 3 +-__attribute__ ((noinline)) +-# endif +-static void +-stack_end_address(VALUE **stack_end_p) +-{ +- VALUE stack_end; +- *stack_end_p = &stack_end; +-} +-# define SET_STACK_END VALUE *stack_end; stack_end_address(&stack_end) +-# else +-# define SET_STACK_END VALUE *stack_end = alloca(1) +-# endif +-# define STACK_END (stack_end) ++# define SET_STACK_END ((void)0) ++# define STACK_END __sp() + #endif ++ + #if STACK_GROW_DIRECTION < 0 + # define STACK_LENGTH(start) ((start) - STACK_END) + #elif STACK_GROW_DIRECTION > 0 + # define STACK_LENGTH(start) (STACK_END - (start) + 1) + #else +-# define STACK_LENGTH(start) ((STACK_END < (start)) ? (start) - STACK_END\ +- : STACK_END - (start) + 1) ++# define STACK_LENGTH(start) ((STACK_END < (start)) ? \ ++ (start) - STACK_END : STACK_END - (start) + 1) + #endif ++ + #if STACK_GROW_DIRECTION > 0 +-# define STACK_UPPER(x, a, b) a ++# define STACK_UPPER(a, b) a + #elif STACK_GROW_DIRECTION < 0 +-# define STACK_UPPER(x, a, b) b ++# define STACK_UPPER(a, b) b + #else + int rb_gc_stack_grow_direction; + static int +@@ -550,33 +545,54 @@ + SET_STACK_END; + return rb_gc_stack_grow_direction = STACK_END > addr ? 1 : -1; + } +-# define STACK_UPPER(x, a, b) (rb_gc_stack_grow_direction > 0 ? a : b) ++# define STACK_UPPER(a, b) (rb_gc_stack_grow_direction > 0 ? a : b) + #endif + +-#define GC_WATER_MARK 512 +- +-#define CHECK_STACK(ret) do {\ +- SET_STACK_END;\ +- (ret) = (STACK_LENGTH(rb_gc_stack_start) > STACK_LEVEL_MAX + GC_WATER_MARK);\ +-} while (0) +- + int + ruby_stack_length(start, base) + VALUE *start, **base; + { + SET_STACK_END; +- if (base) *base = STACK_UPPER(STACK_END, start, STACK_END); ++ if (base) *base = STACK_UPPER(start, STACK_END); + return STACK_LENGTH(start); + } + + int + ruby_stack_check() + { +- int ret; ++ SET_STACK_END; ++ return __stack_past(stack_limit, STACK_END); ++} + +- CHECK_STACK(ret); +- return ret; ++/* ++ Zero memory that was (recently) part of the stack, but is no longer. ++ Invoke when stack is deep to mark its extent and when it's shallow to wipe it. ++*/ ++#if STACK_WIPE_METHOD != 4 ++#if STACK_WIPE_METHOD ++void rb_gc_wipe_stack(void) ++{ ++ VALUE *stack_end = rb_gc_stack_end; ++ VALUE *sp = __sp(); ++ rb_gc_stack_end = sp; ++#if STACK_WIPE_METHOD == 1 ++#warning clearing of "ghost references" from the call stack has been disabled ++#elif STACK_WIPE_METHOD == 2 /* alloca ghost stack before clearing it */ ++ if (__stack_past(sp, stack_end)) { ++ size_t bytes = __stack_depth((char *)stack_end, (char *)sp); ++ STACK_UPPER(sp = nativeAllocA(bytes), stack_end = nativeAllocA(bytes)); ++ __stack_zero(stack_end, sp); ++ } ++#elif STACK_WIPE_METHOD == 3 /* clear unallocated area past stack pointer */ ++ __stack_zero(stack_end, sp); /* will crash if compiler pushes a temp. here */ ++#else ++#error unsupported method of clearing ghost references from the stack ++#endif + } ++#else ++#warning clearing of "ghost references" from the call stack completely disabled ++#endif ++#endif + + #define MARK_STACK_MAX 1024 + static VALUE mark_stack[MARK_STACK_MAX]; +@@ -592,6 +608,17 @@ + + #define MARK_STACK_EMPTY (mark_stack_ptr == mark_stack) + ++static inline void ++push_mark_stack(VALUE ptr) ++{ ++ if (!mark_stack_overflow) { ++ if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) ++ *mark_stack_ptr++ = ptr; ++ else ++ mark_stack_overflow = 1; ++ } ++} ++ + static st_table *source_filenames; + + char * +@@ -635,22 +662,22 @@ + } + } + +-static void gc_mark _((VALUE ptr, int lev)); +-static void gc_mark_children _((VALUE ptr, int lev)); ++#define gc_mark(ptr) rb_gc_mark(ptr) ++static void gc_mark_children _((VALUE ptr)); + + static void + gc_mark_all() + { + RVALUE *p, *pend; +- int i; ++ struct heaps_slot *heap = heaps+heaps_used; + + init_mark_stack(); +- for (i = 0; i < heaps_used; i++) { +- p = heaps[i].slot; pend = p + heaps[i].limit; ++ while (--heap >= heaps) { ++ p = heap->slot; pend = p + heap->limit; + while (p < pend) { + if ((p->as.basic.flags & FL_MARK) && + (p->as.basic.flags != FL_MARK)) { +- gc_mark_children((VALUE)p, 0); ++ gc_mark_children((VALUE)p); + } + p++; + } +@@ -660,169 +687,129 @@ + static void + gc_mark_rest() + { ++ size_t stackLen = mark_stack_ptr - mark_stack; ++#ifdef nativeAllocA ++ VALUE *tmp_arry = nativeAllocA(stackLen*sizeof(VALUE)); ++#else + VALUE tmp_arry[MARK_STACK_MAX]; +- VALUE *p; +- +- p = (mark_stack_ptr - mark_stack) + tmp_arry; +- MEMCPY(tmp_arry, mark_stack, VALUE, MARK_STACK_MAX); ++#endif ++ VALUE *p = tmp_arry + stackLen; ++ ++ MEMCPY(tmp_arry, mark_stack, VALUE, stackLen); + + init_mark_stack(); +- while(p != tmp_arry){ +- p--; +- gc_mark_children(*p, 0); +- } ++ while(--p >= tmp_arry) gc_mark_children(*p); + } + + static inline int + is_pointer_to_heap(ptr) + void *ptr; + { +- register RVALUE *p = RANY(ptr); +- register RVALUE *heap_org; +- register long i; ++ RVALUE *p = RANY(ptr); ++ struct heaps_slot *heap; + +- if (p < lomem || p > himem) return Qfalse; +- if ((VALUE)p % sizeof(RVALUE) != 0) return Qfalse; ++ if (p < lomem || p > himem || (VALUE)p % sizeof(RVALUE)) return Qfalse; + + /* check if p looks like a pointer */ +- for (i=0; i < heaps_used; i++) { +- heap_org = heaps[i].slot; +- if (heap_org <= p && p < heap_org + heaps[i].limit) +- return Qtrue; +- } ++ heap = heaps+heaps_used; ++ while (--heap >= heaps) ++ if (p >= heap->slot && p < heap->slot + heap->limit) ++ return Qtrue; + return Qfalse; + } + + static void + mark_locations_array(x, n) +- register VALUE *x; +- register long n; ++ VALUE *x; ++ size_t n; + { + VALUE v; + while (n--) { + v = *x; + if (is_pointer_to_heap((void *)v)) { +- gc_mark(v, 0); ++ gc_mark(v); + } + x++; + } + } + +-void ++void inline + rb_gc_mark_locations(start, end) + VALUE *start, *end; + { +- long n; +- +- n = end - start; +- mark_locations_array(start,n); ++ mark_locations_array(start,end - start); + } + + static int +-mark_entry(key, value, lev) ++mark_entry(key, value) + ID key; + VALUE value; +- int lev; + { +- gc_mark(value, lev); ++ gc_mark(value); + return ST_CONTINUE; + } + +-static void +-mark_tbl(tbl, lev) +- st_table *tbl; +- int lev; +-{ +- if (!tbl) return; +- st_foreach(tbl, mark_entry, lev); +-} +- + void + rb_mark_tbl(tbl) + st_table *tbl; + { +- mark_tbl(tbl, 0); ++ if (!tbl) return; ++ st_foreach(tbl, mark_entry, 0); + } ++#define mark_tbl(tbl) rb_mark_tbl(tbl) + + static int +-mark_keyvalue(key, value, lev) ++mark_keyvalue(key, value) + VALUE key; + VALUE value; +- int lev; + { +- gc_mark(key, lev); +- gc_mark(value, lev); ++ gc_mark(key); ++ gc_mark(value); + return ST_CONTINUE; + } + +-static void +-mark_hash(tbl, lev) +- st_table *tbl; +- int lev; +-{ +- if (!tbl) return; +- st_foreach(tbl, mark_keyvalue, lev); +-} +- + void + rb_mark_hash(tbl) + st_table *tbl; + { +- mark_hash(tbl, 0); ++ if (!tbl) return; ++ st_foreach(tbl, mark_keyvalue, 0); + } ++#define mark_hash(tbl) rb_mark_hash(tbl) + + void + rb_gc_mark_maybe(obj) + VALUE obj; + { + if (is_pointer_to_heap((void *)obj)) { +- gc_mark(obj, 0); ++ gc_mark(obj); + } + } + +-#define GC_LEVEL_MAX 250 +- +-static void +-gc_mark(ptr, lev) ++void ++rb_gc_mark(ptr) + VALUE ptr; +- int lev; + { +- register RVALUE *obj; +- +- obj = RANY(ptr); ++ RVALUE *obj = RANY(ptr); ++ SET_STACK_END; ++ + if (rb_special_const_p(ptr)) return; /* special const not marked */ + if (obj->as.basic.flags == 0) return; /* free cell */ + if (obj->as.basic.flags & FL_MARK) return; /* already marked */ + obj->as.basic.flags |= FL_MARK; + +- if (lev > GC_LEVEL_MAX || (lev == 0 && ruby_stack_check())) { +- if (!mark_stack_overflow) { +- if (mark_stack_ptr - mark_stack < MARK_STACK_MAX) { +- *mark_stack_ptr = ptr; +- mark_stack_ptr++; +- } +- else { +- mark_stack_overflow = 1; +- } +- } +- return; ++ if (__stack_past(gc_stack_limit, STACK_END)) ++ push_mark_stack(ptr); ++ else{ ++ gc_mark_children(ptr); + } +- gc_mark_children(ptr, lev+1); +-} +- +-void +-rb_gc_mark(ptr) +- VALUE ptr; +-{ +- gc_mark(ptr, 0); + } + + static void +-gc_mark_children(ptr, lev) ++gc_mark_children(ptr) + VALUE ptr; +- int lev; + { +- register RVALUE *obj = RANY(ptr); ++ RVALUE *obj = RANY(ptr); + + goto marking; /* skip */ + +@@ -856,7 +843,7 @@ + case NODE_RESCUE: + case NODE_RESBODY: + case NODE_CLASS: +- gc_mark((VALUE)obj->as.node.u2.node, lev); ++ gc_mark((VALUE)obj->as.node.u2.node); + /* fall through */ + case NODE_BLOCK: /* 1,3 */ + case NODE_ARRAY: +@@ -869,7 +856,7 @@ + case NODE_CALL: + case NODE_DEFS: + case NODE_OP_ASGN1: +- gc_mark((VALUE)obj->as.node.u1.node, lev); ++ gc_mark((VALUE)obj->as.node.u1.node); + /* fall through */ + case NODE_SUPER: /* 3 */ + case NODE_FCALL: +@@ -896,7 +883,7 @@ + case NODE_ALIAS: + case NODE_VALIAS: + case NODE_ARGS: +- gc_mark((VALUE)obj->as.node.u1.node, lev); ++ gc_mark((VALUE)obj->as.node.u1.node); + /* fall through */ + case NODE_METHOD: /* 2 */ + case NODE_NOT: +@@ -934,7 +921,7 @@ + case NODE_SCOPE: /* 2,3 */ + case NODE_BLOCK_PASS: + case NODE_CDECL: +- gc_mark((VALUE)obj->as.node.u3.node, lev); ++ gc_mark((VALUE)obj->as.node.u3.node); + ptr = (VALUE)obj->as.node.u2.node; + goto again; + +@@ -967,25 +954,26 @@ + + default: /* unlisted NODE */ + if (is_pointer_to_heap(obj->as.node.u1.node)) { +- gc_mark((VALUE)obj->as.node.u1.node, lev); ++ gc_mark((VALUE)obj->as.node.u1.node); + } + if (is_pointer_to_heap(obj->as.node.u2.node)) { +- gc_mark((VALUE)obj->as.node.u2.node, lev); ++ gc_mark((VALUE)obj->as.node.u2.node); + } + if (is_pointer_to_heap(obj->as.node.u3.node)) { +- gc_mark((VALUE)obj->as.node.u3.node, lev); ++ ptr = (VALUE)obj->as.node.u3.node; ++ goto again; + } + } +- return; /* no need to mark class. */ ++ return; /* no need to mark class. */ + } + +- gc_mark(obj->as.basic.klass, lev); ++ gc_mark(obj->as.basic.klass); + switch (obj->as.basic.flags & T_MASK) { + case T_ICLASS: + case T_CLASS: + case T_MODULE: +- mark_tbl(obj->as.klass.m_tbl, lev); +- mark_tbl(obj->as.klass.iv_tbl, lev); ++ mark_tbl(obj->as.klass.m_tbl); ++ mark_tbl(obj->as.klass.iv_tbl); + ptr = obj->as.klass.super; + goto again; + +@@ -995,17 +983,16 @@ + goto again; + } + else { +- long i, len = obj->as.array.len; + VALUE *ptr = obj->as.array.ptr; +- +- for (i=0; i < len; i++) { +- gc_mark(*ptr++, lev); ++ VALUE *pend = ptr + obj->as.array.len; ++ while (ptr < pend) { ++ gc_mark(*ptr++); + } + } + break; + + case T_HASH: +- mark_hash(obj->as.hash.tbl, lev); ++ mark_hash(obj->as.hash.tbl); + ptr = obj->as.hash.ifnone; + goto again; + +@@ -1022,7 +1009,7 @@ + break; + + case T_OBJECT: +- mark_tbl(obj->as.object.iv_tbl, lev); ++ mark_tbl(obj->as.object.iv_tbl); + break; + + case T_FILE: +@@ -1040,7 +1027,7 @@ + break; + + case T_VARMAP: +- gc_mark(obj->as.varmap.val, lev); ++ gc_mark(obj->as.varmap.val); + ptr = (VALUE)obj->as.varmap.next; + goto again; + +@@ -1050,19 +1037,17 @@ + VALUE *vars = &obj->as.scope.local_vars[-1]; + + while (n--) { +- gc_mark(*vars++, lev); ++ gc_mark(*vars++); + } + } + break; + + case T_STRUCT: + { +- long len = obj->as.rstruct.len; + VALUE *ptr = obj->as.rstruct.ptr; +- +- while (len--) { +- gc_mark(*ptr++, lev); +- } ++ VALUE *pend = ptr + obj->as.rstruct.len; ++ while (ptr < pend) ++ gc_mark(*ptr++); + } + break; + +@@ -1134,7 +1119,7 @@ + p = heaps[i].slot; pend = p + heaps[i].limit; + while (p < pend) { + if (!(p->as.basic.flags&FL_MARK) && BUILTIN_TYPE(p) == T_NODE) +- gc_mark((VALUE)p, 0); ++ gc_mark((VALUE)p); + p++; + } + } +@@ -1346,7 +1331,7 @@ + rb_gc_mark_frame(frame) + struct FRAME *frame; + { +- gc_mark((VALUE)frame->node, 0); ++ gc_mark((VALUE)frame->node); + } + + #ifdef __GNUC__ +@@ -1384,8 +1369,10 @@ + #endif /* __human68k__ or DJGPP */ + #endif /* __GNUC__ */ + ++ ++ + static void +-garbage_collect() ++garbage_collect_0(VALUE *top_frame) + { + struct gc_list *list; + struct FRAME * frame; +@@ -1406,9 +1393,10 @@ + if (during_gc) return; + during_gc++; + ++ gc_stack_limit = __stack_grow(STACK_END, GC_LEVEL_MAX); + init_mark_stack(); + +- gc_mark((VALUE)ruby_current_node, 0); ++ gc_mark((VALUE)ruby_current_node); + + /* mark frame stack */ + for (frame = ruby_frame; frame; frame = frame->prev) { +@@ -1421,10 +1409,10 @@ + } + } + } +- gc_mark((VALUE)ruby_scope, 0); +- gc_mark((VALUE)ruby_dyna_vars, 0); ++ gc_mark((VALUE)ruby_scope); ++ gc_mark((VALUE)ruby_dyna_vars); + if (finalizer_table) { +- mark_tbl(finalizer_table, 0); ++ mark_tbl(finalizer_table); + } + + FLUSH_REGISTER_WINDOWS; +@@ -1432,14 +1420,14 @@ + rb_setjmp(save_regs_gc_mark); + mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *)); + #if STACK_GROW_DIRECTION < 0 +- rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start); ++ rb_gc_mark_locations(top_frame, rb_gc_stack_start); + #elif STACK_GROW_DIRECTION > 0 +- rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1); ++ rb_gc_mark_locations(rb_gc_stack_start, top_frame + 1); + #else + if (rb_gc_stack_grow_direction < 0) +- rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start); ++ rb_gc_mark_locations(top_frame, rb_gc_stack_start); + else +- rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END + 1); ++ rb_gc_mark_locations(rb_gc_stack_start, top_frame + 1); + #endif + #ifdef __ia64 + /* mark backing store (flushed register window on the stack) */ +@@ -1479,10 +1467,35 @@ + } + rb_gc_abort_threads(); + } while (!MARK_STACK_EMPTY); +- + gc_sweep(); + } + ++static void ++garbage_collect() ++{ ++ VALUE *top = __sp(); ++#if STACK_WIPE_SITES & 0x400 ++# ifdef nativeAllocA ++ if (__stack_past (top, stack_limit)) { ++ /* allocate a large frame to ensure app stack cannot grow into GC stack */ ++ volatile char *spacer = ++ nativeAllocA(__stack_depth((void*)stack_limit,(void*)top)); ++ } ++ garbage_collect_0(top); ++# else /* no native alloca() available */ ++ garbage_collect_0(top); ++ { ++ VALUE *paddedLimit = __stack_grow(gc_stack_limit, GC_STACK_PAD); ++ if (__stack_past(rb_gc_stack_end, paddedLimit)) ++ rb_gc_stack_end = paddedLimit; ++ } ++ rb_gc_wipe_stack(); /* wipe the whole stack area reserved for this gc */ ++# endif ++#else ++ garbage_collect_0(top); ++#endif ++} ++ + void + rb_gc() + { +@@ -1507,6 +1520,7 @@ + return Qnil; + } + ++ + void + ruby_set_stack_size(size) + size_t size; +@@ -1514,6 +1528,29 @@ + #ifndef STACK_LEVEL_MAX + STACK_LEVEL_MAX = size / sizeof(VALUE); + #endif ++ stack_limit = __stack_grow(rb_gc_stack_start, STACK_LEVEL_MAX-GC_STACK_MAX); ++} ++ ++static void ++set_stack_size(void) ++{ ++#ifdef HAVE_GETRLIMIT ++ struct rlimit rlim; ++ if (getrlimit(RLIMIT_STACK, &rlim) == 0) { ++ if (rlim.rlim_cur > 0 && rlim.rlim_cur != RLIM_INFINITY) { ++ size_t maxStackBytes = rlim.rlim_cur; ++ if (rlim.rlim_cur != maxStackBytes) ++ maxStackBytes = -1; ++ { ++ size_t space = maxStackBytes/5; ++ if (space > 1024*1024) space = 1024*1024; ++ ruby_set_stack_size(maxStackBytes - space); ++ return; ++ } ++ } ++ } ++#endif ++ ruby_set_stack_size(STACK_LEVEL_MAX*sizeof(VALUE)); + } + + void +@@ -1547,7 +1584,7 @@ + memset(&m, 0, sizeof(m)); + VirtualQuery(&m, &m, sizeof(m)); + rb_gc_stack_start = +- STACK_UPPER((VALUE *)&m, (VALUE *)m.BaseAddress, ++ STACK_UPPER((VALUE *)m.BaseAddress, + (VALUE *)((char *)m.BaseAddress + m.RegionSize) - 1); + #elif defined(STACK_END_ADDRESS) + { +@@ -1556,28 +1593,16 @@ + } + #else + if (!addr) addr = (void *)&addr; +- STACK_UPPER(&addr, addr, ++addr); ++ STACK_UPPER(addr, ++addr); + if (rb_gc_stack_start) { +- if (STACK_UPPER(&addr, +- rb_gc_stack_start > addr, ++ if (STACK_UPPER(rb_gc_stack_start > addr, + rb_gc_stack_start < addr)) + rb_gc_stack_start = addr; + return; + } + rb_gc_stack_start = addr; + #endif +-#ifdef HAVE_GETRLIMIT +- { +- struct rlimit rlim; +- +- if (getrlimit(RLIMIT_STACK, &rlim) == 0) { +- unsigned int space = rlim.rlim_cur/5; +- +- if (space > 1024*1024) space = 1024*1024; +- STACK_LEVEL_MAX = (rlim.rlim_cur - space) / sizeof(VALUE); +- } +- } +-#endif ++ set_stack_size(); + } + + void ruby_init_stack(VALUE *addr +@@ -1587,8 +1612,7 @@ + ) + { + if (!rb_gc_stack_start || +- STACK_UPPER(&addr, +- rb_gc_stack_start > addr, ++ STACK_UPPER(rb_gc_stack_start > addr, + rb_gc_stack_start < addr)) { + rb_gc_stack_start = addr; + } +@@ -1599,16 +1623,7 @@ + } + #endif + #ifdef HAVE_GETRLIMIT +- { +- struct rlimit rlim; +- +- if (getrlimit(RLIMIT_STACK, &rlim) == 0) { +- unsigned int space = rlim.rlim_cur/5; +- +- if (space > 1024*1024) space = 1024*1024; +- STACK_LEVEL_MAX = (rlim.rlim_cur - space) / sizeof(VALUE); +- } +- } ++ set_stack_size(); + #elif defined _WIN32 + { + MEMORY_BASIC_INFORMATION mi; +@@ -1619,7 +1634,7 @@ + size = (char *)mi.BaseAddress - (char *)mi.AllocationBase; + space = size / 5; + if (space > 1024*1024) space = 1024*1024; +- STACK_LEVEL_MAX = (size - space) / sizeof(VALUE); ++ ruby_set_stack_size(size - space); + } + } + #endif +@@ -2111,6 +2126,7 @@ + rb_define_singleton_method(rb_mGC, "limit", gc_getlimit, 0); + rb_define_singleton_method(rb_mGC, "limit=", gc_setlimit, 1); + rb_define_singleton_method(rb_mGC, "increase", gc_increase, 0); ++ rb_define_singleton_method(rb_mGC, "exorcise", gc_exorcise, 0); + rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0); + + rb_mObSpace = rb_define_module("ObjectSpace"); +diff -ru ruby-1.8.7-p72/intern.h ruby-1.8.7-mbari/intern.h +--- ruby-1.8.7-p72/intern.h 2009-02-09 21:21:30.000000000 -0800 ++++ ruby-1.8.7-mbari/intern.h 2008-12-23 21:54:37.000000000 -0800 +@@ -2,8 +2,8 @@ + + intern.h - + +- $Author: shyouhei $ +- $Date: 2008-07-07 12:29:28 +0900 (Mon, 07 Jul 2008) $ ++ $Author: brent $ ++ $Date: 2008/12/24 05:54:37 $ + created at: Thu Jun 10 14:22:17 JST 1993 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +diff -ru ruby-1.8.7-p72/missing/alloca.c ruby-1.8.7-mbari/missing/alloca.c +--- ruby-1.8.7-p72/missing/alloca.c 2007-02-12 15:01:19.000000000 -0800 ++++ ruby-1.8.7-mbari/missing/alloca.c 2009-01-23 00:01:03.000000000 -0800 +@@ -29,6 +29,7 @@ + static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ + #endif + ++#include + #include "config.h" + #ifdef emacs + #ifdef static +@@ -44,11 +45,7 @@ + #endif /* static */ + #endif /* emacs */ + +-#ifdef X3J11 + typedef void *pointer; /* generic pointer type */ +-#else +-typedef char *pointer; /* generic pointer type */ +-#endif /* X3J11 */ + + #define NULL 0 /* null pointer constant */ + +@@ -140,8 +137,7 @@ + static header *last_alloca_header = NULL; /* -> last alloca header */ + + pointer +-alloca (size) /* returns pointer to storage */ +- unsigned size; /* # bytes to allocate */ ++alloca (size_t size) /* returns pointer to storage */ + { + auto char probe; /* probes stack depth: */ + register char *depth = &probe; +diff -ru ruby-1.8.7-p72/rubysig.h ruby-1.8.7-mbari/rubysig.h +--- ruby-1.8.7-p72/rubysig.h 2009-02-09 21:21:30.000000000 -0800 ++++ ruby-1.8.7-mbari/rubysig.h 2009-02-09 20:55:50.000000000 -0800 +@@ -3,7 +3,7 @@ + rubysig.h - + + $Author: brent $ +- $Date: 2008/12/14 07:24:10 $ ++ $Date: 2009/02/09 20:45:48 $ + created at: Wed Aug 16 01:15:38 JST 1995 + + Copyright (C) 1993-2003 Yukihiro Matsumoto +@@ -12,8 +12,75 @@ + + #ifndef SIG_H + #define SIG_H ++ + #include + ++/* STACK_WIPE_SITES determines where attempts are made to exorcise ++ "ghost object refereces" from the stack and how the stack is cleared: ++ ++ 0x*001 --> wipe stack just after every thread_switch ++ 0x*002 --> wipe stack just after every EXEC_TAG() ++ 0x*004 --> wipe stack in CHECK_INTS ++ 0x*010 --> wipe stack in while & until loops ++ 0x*020 --> wipe stack before yield() in iterators and outside eval.c ++ 0x*040 --> wipe stack on catch and thread save context ++ 0x*100 --> update stack extent on each object allocation ++ 0x*200 --> update stack extent on each object reallocation ++ 0x*400 --> update stack extent during GC marking passes ++ 0x*800 --> update stack extent on each throw (use with 0x040) ++ 0x1000 --> use inline assembly code for x86, PowerPC, or ARM CPUs ++ ++ 0x0*** --> do not even call rb_wipe_stack() ++ 0x2*** --> call dummy rb_wipe_stack() (for debugging and profiling) ++ 0x4*** --> safe, portable stack clearing in memory allocated with alloca ++ 0x6*** --> use faster, but less safe stack clearing in unallocated stack ++ 0x8*** --> use faster, but less safe stack clearing (with inline code) ++ ++ for most effective gc use 0x*707 ++ for fastest micro-benchmarking use 0x0000 ++ 0x*770 prevents almost all memory leaks caused by ghost references ++ without adding much overhead for stack clearing. ++ Other good trade offs are 0x*270, 0x*703, 0x*303 or even 0x*03 ++ ++ In general, you may lessen the default -mpreferred-stack-boundary ++ only if using less safe stack clearing (0x6***). Lessening the ++ stack alignment with portable stack clearing (0x4***) may fail to clear ++ all ghost references off the stack. ++ ++ When using 0x6*** or 0x8***, the compiler could insert ++ stack push(s) between reading the stack pointer and clearing ++ the ghost references. The register(s) pushed will be ++ cleared by the rb_gc_stack_wipe(), typically resulting in a segfault ++ or an interpreter hang. ++ ++ STACK_WIPE_SITES of 0x8770 works well compiled with gcc on most machines ++ using the recommended CFLAGS="-O2 -fno-stack-protector". However... ++ If it hangs or crashes for you, try changing STACK_WIPE_SITES to 0x4770 ++ and please report your details. i.e. CFLAGS, compiler, version, CPU ++ ++ Note that it is redundant to wipe_stack in looping constructs if ++ also doing so in CHECK_INTS. It is also redundant to wipe_stack on ++ each thread_switch if wiping after every thread save context. ++*/ ++#ifndef STACK_WIPE_SITES ++# ifdef __x86_64__ /* deal with "red zone" by not inlining stack clearing */ ++# define STACK_WIPE_SITES 0x6770 ++# elif defined __ppc__ || defined __ppc64__ /* On any PowerPC, deal with... */ ++# define STACK_WIPE_SITES 0x7764 /* red zone & alloc(0) doesn't return sp */ ++# else ++# define STACK_WIPE_SITES 0x8770 /*normal case, use 0x4770 if problems arise*/ ++# endif ++#endif ++ ++#if (STACK_WIPE_SITES & 0x14) == 0x14 ++#warning wiping stack in CHECK_INTS makes wiping in loops redundant ++#endif ++#if (STACK_WIPE_SITES & 0x41) == 0x41 ++#warning wiping stack after thread save makes wiping on thread_switch redundant ++#endif ++ ++#define STACK_WIPE_METHOD (STACK_WIPE_SITES>>13) ++ + #ifdef _WIN32 + typedef LONG rb_atomic_t; + +@@ -79,52 +146,151 @@ + + RUBY_EXTERN int rb_thread_critical; + void rb_thread_schedule _((void)); +-#if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE) +-RUBY_EXTERN int rb_thread_pending; + +-EXTERN size_t rb_gc_malloc_increase; +-EXTERN size_t rb_gc_malloc_limit; +-EXTERN VALUE *rb_gc_stack_end; +-EXTERN int *rb_gc_stack_grow_direction; /* -1 for down or 1 for up */ +-#define __stack_zero_up(end,sp) while (end >= ++sp) *sp=0 +-#define __stack_grown_up (rb_gc_stack_end > (VALUE *)alloca(0)) +-#define __stack_zero_down(end,sp) while (end <= --sp) *sp=0 +-#define __stack_grown_down (rb_gc_stack_end < (VALUE *)alloca(0)) ++RUBY_EXTERN VALUE *rb_gc_stack_end; ++RUBY_EXTERN int rb_gc_stack_grow_direction; /* -1 for down or 1 for up */ + + #if STACK_GROW_DIRECTION > 0 ++ ++/* clear stack space between end and sp (not including *sp) */ + #define __stack_zero(end,sp) __stack_zero_up(end,sp) +-#define __stack_grown __stack_grown_up ++ ++/* true if top has grown past limit, i.e. top deeper than limit */ ++#define __stack_past(limit,top) __stack_past_up(limit,top) ++ ++/* depth of mid below stack top */ ++#define __stack_depth(top,mid) __stack_depth_up(top,mid) ++ ++/* stack pointer top adjusted to include depth more items */ ++#define __stack_grow(top,depth) __stack_grow_up(top,depth) ++ ++ + #elif STACK_GROW_DIRECTION < 0 + #define __stack_zero(end,sp) __stack_zero_down(end,sp) +-#define __stack_grown __stack_grown_down ++#define __stack_past(limit,top) __stack_past_down(limit,top) ++#define __stack_depth(top,mid) __stack_depth_down(top,mid) ++#define __stack_grow(top,depth) __stack_grow_down(top,depth) ++ + #else /* limp along if stack direction can't be determined at compile time */ + #define __stack_zero(end,sp) if (rb_gc_stack_grow_direction<0) \ + __stack_zero_down(end,sp); else __stack_zero_up(end,sp); +-#define __stack_grown \ +- (rb_gc_stack_grow_direction<0 ? __stack_grown_down : __stack_grown_up) ++#define __stack_past(limit,top) (rb_gc_stack_grow_direction<0 ? \ ++ __stack_past_down(limit,top) : __stack_past_up(limit,top)) ++#define __stack_depth(top,mid) (rb_gc_stack_grow_direction<0 ? \ ++ __stack_depth_down(top,mid) : __stack_depth_up(top,mid)) ++#define __stack_grow(top,depth) (rb_gc_stack_grow_direction<0 ? \ ++ __stack_grow_down(top,depth) : __stack_grow_up(top,depth)) + #endif + ++#define __stack_zero_up(end,sp) while (end >= ++sp) *sp=0 ++#define __stack_past_up(limit,top) ((limit) < (top)) ++#define __stack_depth_up(top,mid) ((top) - (mid)) ++#define __stack_grow_up(top,depth) ((top)+(depth)) ++ ++#define __stack_zero_down(end,sp) while (end <= --sp) *sp=0 ++#define __stack_past_down(limit,top) ((limit) > (top)) ++#define __stack_depth_down(top,mid) ((mid) - (top)) ++#define __stack_grow_down(top,depth) ((top)-(depth)) ++ ++/* Make alloca work the best possible way. */ ++#ifdef __GNUC__ ++# ifndef atarist ++# ifndef alloca ++# define alloca __builtin_alloca ++# endif ++# endif /* atarist */ ++ ++# define nativeAllocA __builtin_alloca ++ ++/* use assembly to get stack pointer quickly */ ++# if STACK_WIPE_SITES & 0x1000 ++# define __defspfn(asmb) \ ++static inline VALUE *__sp(void) __attribute__((always_inline)); \ ++static inline VALUE *__sp(void) \ ++{ \ ++ VALUE *sp; asm(asmb); \ ++ return sp; \ ++} ++# if defined __ppc__ || defined __ppc64__ ++__defspfn("addi %0, r1, 0": "=r"(sp)) ++# elif defined __i386__ ++__defspfn("movl %%esp, %0": "=r"(sp)) ++# elif defined __x86_64__ ++__defspfn("movq %%rsp, %0": "=r"(sp)) ++# elif __arm__ ++__defspfn("mov %0, sp": "=r"(sp)) ++# else ++# define __sp() ((VALUE *)__builtin_alloca(0)) ++# warning No assembly version of __sp() defined for this CPU. ++# endif ++# else ++# define __sp() ((VALUE *)__builtin_alloca(0)) ++# endif ++ ++#else // not GNUC ++ ++# ifdef HAVE_ALLOCA_H ++# include ++# else ++# ifndef _AIX ++# ifndef alloca /* predefined by HP cc +Olibcalls */ ++void *alloca (); ++# endif ++# endif /* AIX */ ++# endif /* HAVE_ALLOCA_H */ ++ ++# if STACK_WIPE_SITES & 0x1000 ++# warning No assembly versions of __sp() defined for this compiler. ++# endif ++# if HAVE_ALLOCA ++# define __sp() ((VALUE *)alloca(0)) ++# define nativeAllocA alloca ++# else ++RUBY_EXTERN VALUE *__sp(void); ++# if STACK_WIPE_SITES ++# define STACK_WIPE_SITES 0 ++# warning Disabled Stack Wiping because there is no native alloca() ++# endif ++# endif ++#endif /* __GNUC__ */ ++ ++ + /* +- zero the memory that was (recently) part of the stack +- but is no longer. Invoke when stack is deep to mark its extent +- and when it is shallow to wipe it ++ Zero memory that was (recently) part of the stack, but is no longer. ++ Invoke when stack is deep to mark its extent and when it's shallow to wipe it. + */ ++#if STACK_WIPE_METHOD == 0 ++#define rb_gc_wipe_stack() ((void)0) ++#elif STACK_WIPE_METHOD == 4 + #define rb_gc_wipe_stack() { \ +- VALUE *sp = alloca(0); \ + VALUE *end = rb_gc_stack_end; \ ++ VALUE *sp = __sp(); \ + rb_gc_stack_end = sp; \ + __stack_zero(end, sp); \ + } ++#else ++RUBY_EXTERN void rb_gc_wipe_stack(void); ++#endif + + /* + Update our record of maximum stack extent without zeroing unused stack + */ +-#define rb_gc_update_stack_extent() \ +- if __stack_grown rb_gc_stack_end = alloca(0); ++#define rb_gc_update_stack_extent() do { \ ++ VALUE *sp = __sp(); \ ++ if __stack_past(rb_gc_stack_end, sp) rb_gc_stack_end = sp; \ ++} while(0) ++ + ++#if STACK_WIPE_SITES & 4 ++# define CHECK_INTS_wipe_stack() rb_gc_wipe_stack() ++#else ++# define CHECK_INTS_wipe_stack() (void)0 ++#endif + ++#if defined(HAVE_SETITIMER) || defined(_THREAD_SAFE) ++RUBY_EXTERN int rb_thread_pending; + # define CHECK_INTS do {\ +- rb_gc_wipe_stack(); \ ++ CHECK_INTS_wipe_stack(); \ + if (!(rb_prohibit_interrupt || rb_thread_critical)) {\ + if (rb_thread_pending) rb_thread_schedule();\ + if (rb_trap_pending) rb_trap_exec();\ +@@ -135,14 +301,14 @@ + RUBY_EXTERN int rb_thread_tick; + #define THREAD_TICK 500 + #define CHECK_INTS do {\ +- rb_gc_wipe_stack(); \ ++ CHECK_INTS_wipe_stack(); \ + if (!(rb_prohibit_interrupt || rb_thread_critical)) {\ + if (rb_thread_tick-- <= 0) {\ + rb_thread_tick = THREAD_TICK;\ + rb_thread_schedule();\ + }\ ++ if (rb_trap_pending) rb_trap_exec();\ + }\ +- if (rb_trap_pending) rb_trap_exec();\ + } while (0) + #endif + +diff -ru ruby-1.8.7-p72/version.h ruby-1.8.7-mbari/version.h +--- ruby-1.8.7-p72/version.h 2009-02-09 21:21:30.000000000 -0800 ++++ ruby-1.8.7-mbari/version.h 2009-02-09 20:24:44.000000000 -0800 +@@ -1,15 +1,15 @@ + #define RUBY_VERSION "1.8.7" +-#define RUBY_RELEASE_DATE "2008-12-21" ++#define RUBY_RELEASE_DATE "2009-2-9" + #define RUBY_VERSION_CODE 187 +-#define RUBY_RELEASE_CODE 20081221 ++#define RUBY_RELEASE_CODE 20090209 + #define RUBY_PATCHLEVEL 72 + + #define RUBY_VERSION_MAJOR 1 + #define RUBY_VERSION_MINOR 8 + #define RUBY_VERSION_TEENY 7 +-#define RUBY_RELEASE_YEAR 2008 +-#define RUBY_RELEASE_MONTH 12 +-#define RUBY_RELEASE_DAY 21 ++#define RUBY_RELEASE_YEAR 2009 ++#define RUBY_RELEASE_MONTH 2 ++#define RUBY_RELEASE_DAY 9 + + #ifdef RUBY_EXTERN + RUBY_EXTERN const char ruby_version[]; +@@ -25,7 +25,12 @@ + #define RUBY_BIRTH_MONTH 2 + #define RUBY_BIRTH_DAY 24 + +-#define RUBY_RELEASE_STR "MBARI 6 on patchlevel" ++#include "rubysig.h" ++ ++#define string_arg(s) #s ++#define MBARI_RELEASE(wipe_sites) "MBARI 7/" string_arg(wipe_sites) ++ ++#define RUBY_RELEASE_STR MBARI_RELEASE(STACK_WIPE_SITES) " on patchlevel" + #define RUBY_RELEASE_NUM RUBY_PATCHLEVEL + + diff --git a/patches/ruby/1.8.7/railsbench.patch b/patches/ruby/1.8.7/railsbench.patch new file mode 100644 index 0000000000..da1a4590c8 --- /dev/null +++ b/patches/ruby/1.8.7/railsbench.patch @@ -0,0 +1,564 @@ +diff --git a/gc.c b/gc.c +index 52b1c23..f774022 100644 +--- a/gc.c ++++ b/gc.c +@@ -22,8 +22,16 @@ + #include + #include + ++#ifdef _WIN32 ++#include ++#else ++#include ++#endif ++ + #ifdef HAVE_SYS_TIME_H + #include ++#elif defined(_WIN32) ++#include + #endif + + #ifdef HAVE_SYS_RESOURCE_H +@@ -42,7 +50,6 @@ void rb_io_fptr_finalize _((struct rb_io_t*)); + #ifdef __CYGWIN__ + int _setjmp(), _longjmp(); + #endif +- + /* Make alloca work the best possible way. */ + #ifdef __GNUC__ + # ifndef atarist +@@ -205,8 +212,17 @@ ruby_xfree(x) + RUBY_CRITICAL(free(x)); + } + ++#if HAVE_LONG_LONG ++#define GC_TIME_TYPE LONG_LONG ++#else ++#define GC_TIME_TYPE long ++#endif ++ + extern int ruby_in_compile; + static int dont_gc; ++static int gc_statistics = 0; ++static GC_TIME_TYPE gc_time = 0; ++static int gc_collections = 0; + static int during_gc; + static int need_call_final = 0; + static st_table *finalizer_table = 0; +@@ -241,7 +257,7 @@ rb_gc_enable() + * Disables garbage collection, returning true if garbage + * collection was already disabled. + * +- * GC.disable #=> false ++ * GC.disable #=> false or true + * GC.disable #=> true + * + */ +@@ -255,6 +271,104 @@ rb_gc_disable() + return old; + } + ++/* ++ * call-seq: ++ * GC.enable_stats => true or false ++ * ++ * Enables garbage collection statistics, returning true if garbage ++ * collection statistics was already enabled. ++ * ++ * GC.enable_stats #=> false or true ++ * GC.enable_stats #=> true ++ * ++ */ ++ ++VALUE ++rb_gc_enable_stats() ++{ ++ int old = gc_statistics; ++ gc_statistics = Qtrue; ++ return old; ++} ++ ++/* ++ * call-seq: ++ * GC.disable_stats => true or false ++ * ++ * Disables garbage collection statistics, returning true if garbage ++ * collection statistics was already disabled. ++ * ++ * GC.disable_stats #=> false or true ++ * GC.disable_stats #=> true ++ * ++ */ ++ ++VALUE ++rb_gc_disable_stats() ++{ ++ int old = gc_statistics; ++ gc_statistics = Qfalse; ++ return old; ++} ++ ++/* ++ * call-seq: ++ * GC.clear_stats => nil ++ * ++ * Clears garbage collection statistics, returning nil. This resets the number ++ * of collections (GC.collections) and the time used (GC.time) to 0. ++ * ++ * GC.clear_stats #=> nil ++ * ++ */ ++ ++VALUE ++rb_gc_clear_stats() ++{ ++ gc_collections = 0; ++ gc_time = 0; ++ return Qnil; ++} ++ ++/* ++ * call-seq: ++ * GC.collections => Integer ++ * ++ * Returns the number of garbage collections performed while GC statistics collection ++ * was enabled. ++ * ++ * GC.collections #=> 35 ++ * ++ */ ++ ++VALUE ++rb_gc_collections() ++{ ++ return INT2NUM(gc_collections); ++} ++ ++/* ++ * call-seq: ++ * GC.time => Integer ++ * ++ * Returns the time spent during garbage collection while GC statistics collection ++ * was enabled (in micro seconds). ++ * ++ * GC.time #=> 20000 ++ * ++ */ ++ ++VALUE ++rb_gc_time() ++{ ++#if HAVE_LONG_LONG ++ return LL2NUM(gc_time); ++#else ++ return LONG2NUM(gc_time); ++#endif ++} ++ ++ + VALUE rb_mGC; + + static struct gc_list { +@@ -346,7 +460,7 @@ typedef struct RVALUE { + static RVALUE *freelist = 0; + static RVALUE *deferred_final_list = 0; + +-#define HEAPS_INCREMENT 10 ++static int heaps_increment = 10; + static struct heaps_slot { + void *membase; + RVALUE *slot; +@@ -355,13 +469,165 @@ static struct heaps_slot { + static int heaps_length = 0; + static int heaps_used = 0; + +-#define HEAP_MIN_SLOTS 10000 +-static int heap_slots = HEAP_MIN_SLOTS; ++static int heap_min_slots = 10000; ++static int heap_slots = 10000; ++ ++static int heap_free_min = 4096; ++static int heap_slots_increment = 10000; ++static double heap_slots_growth_factor = 1.8; ++ ++static long initial_malloc_limit = GC_MALLOC_LIMIT; + +-#define FREE_MIN 4096 ++static int verbose_gc_stats = Qfalse; ++ ++static FILE* gc_data_file = NULL; + + static RVALUE *himem, *lomem; + ++static void set_gc_parameters() ++{ ++ char *gc_stats_ptr, *min_slots_ptr, *free_min_ptr, *heap_slots_incr_ptr, ++ *heap_incr_ptr, *malloc_limit_ptr, *gc_heap_file_ptr, *heap_slots_growth_factor_ptr; ++ ++ gc_data_file = stderr; ++ ++ gc_stats_ptr = getenv("RUBY_GC_STATS"); ++ if (gc_stats_ptr != NULL) { ++ int gc_stats_i = atoi(gc_stats_ptr); ++ if (gc_stats_i > 0) { ++ verbose_gc_stats = Qtrue; ++ } ++ } ++ ++ gc_heap_file_ptr = getenv("RUBY_GC_DATA_FILE"); ++ if (gc_heap_file_ptr != NULL) { ++ FILE* data_file = fopen(gc_heap_file_ptr, "w"); ++ if (data_file != NULL) { ++ gc_data_file = data_file; ++ } ++ else { ++ fprintf(stderr, ++ "can't open gc log file %s for writing, using default\n", gc_heap_file_ptr); ++ } ++ } ++ ++ min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS"); ++ if (min_slots_ptr != NULL) { ++ int min_slots_i = atoi(min_slots_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_MIN_SLOTS=%s\n", min_slots_ptr); ++ } ++ if (min_slots_i > 0) { ++ heap_slots = min_slots_i; ++ heap_min_slots = min_slots_i; ++ } ++ } ++ ++ free_min_ptr = getenv("RUBY_HEAP_FREE_MIN"); ++ if (free_min_ptr != NULL) { ++ int free_min_i = atoi(free_min_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_FREE_MIN=%s\n", free_min_ptr); ++ } ++ if (free_min_i > 0) { ++ heap_free_min = free_min_i; ++ } ++ } ++ ++ heap_incr_ptr = getenv("RUBY_HEAP_INCREMENT"); ++ if (heap_incr_ptr != NULL) { ++ int heap_incr_i = atoi(heap_incr_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_INCREMENT=%s\n", heap_incr_ptr); ++ } ++ if (heap_incr_i > 0) { ++ heaps_increment = heap_incr_i; ++ } ++ } ++ ++ heap_slots_incr_ptr = getenv("RUBY_HEAP_SLOTS_INCREMENT"); ++ if (heap_slots_incr_ptr != NULL) { ++ int heap_slots_incr_i = atoi(heap_slots_incr_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_SLOTS_INCREMENT=%s\n", heap_slots_incr_ptr); ++ } ++ if (heap_slots_incr_i > 0) { ++ heap_slots_increment = heap_slots_incr_i; ++ } ++ } ++ ++ heap_slots_growth_factor_ptr = getenv("RUBY_HEAP_SLOTS_GROWTH_FACTOR"); ++ if (heap_slots_growth_factor_ptr != NULL) { ++ double heap_slots_growth_factor_d = atoi(heap_slots_growth_factor_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_SLOTS_GROWTH_FACTOR=%s\n", heap_slots_growth_factor_ptr); ++ } ++ if (heap_slots_growth_factor_d > 0) { ++ heap_slots_growth_factor = heap_slots_growth_factor_d; ++ } ++ } ++ ++ malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT"); ++ if (malloc_limit_ptr != NULL) { ++ int malloc_limit_i = atol(malloc_limit_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_GC_MALLOC_LIMIT=%s\n", malloc_limit_ptr); ++ } ++ if (malloc_limit_i > 0) { ++ initial_malloc_limit = malloc_limit_i; ++ } ++ } ++} ++ ++/* ++ * call-seq: ++ * GC.dump => nil ++ * ++ * dumps information about the current GC data structures to the GC log file ++ * ++ * GC.dump #=> nil ++ * ++ */ ++ ++VALUE ++rb_gc_dump() ++{ ++ int i; ++ ++ for (i = 0; i < heaps_used; i++) { ++ int heap_size = heaps[i].limit; ++ fprintf(gc_data_file, "HEAP[%2d]: size=%7d\n", i, heap_size); ++ } ++ ++ return Qnil; ++} ++ ++/* ++ * call-seq: ++ * GC.log String => String ++ * ++ * Logs string to the GC data file and returns it. ++ * ++ * GC.log "manual GC call" #=> "manual GC call" ++ * ++ */ ++ ++VALUE ++rb_gc_log(self, original_str) ++ VALUE self, original_str; ++{ ++ if (original_str == Qnil) { ++ fprintf(gc_data_file, "\n"); ++ } ++ else { ++ VALUE str = StringValue(original_str); ++ char *p = RSTRING(str)->ptr; ++ fprintf(gc_data_file, "%s\n", p); ++ } ++ return original_str; ++} ++ ++ + static void + add_heap() + { +@@ -372,7 +638,7 @@ add_heap() + struct heaps_slot *p; + int length; + +- heaps_length += HEAPS_INCREMENT; ++ heaps_length += heaps_increment; + length = heaps_length*sizeof(struct heaps_slot); + RUBY_CRITICAL( + if (heaps_used > 0) { +@@ -388,10 +654,10 @@ add_heap() + for (;;) { + RUBY_CRITICAL(p = (RVALUE*)malloc(sizeof(RVALUE)*(heap_slots+1))); + if (p == 0) { +- if (heap_slots == HEAP_MIN_SLOTS) { ++ if (heap_slots == heap_min_slots) { + rb_memerror(); + } +- heap_slots = HEAP_MIN_SLOTS; ++ heap_slots = heap_min_slots; + continue; + } + heaps[heaps_used].membase = p; +@@ -407,8 +673,9 @@ add_heap() + if (lomem == 0 || lomem > p) lomem = p; + if (himem < pend) himem = pend; + heaps_used++; +- heap_slots *= 1.8; +- if (heap_slots <= 0) heap_slots = HEAP_MIN_SLOTS; ++ heap_slots += heap_slots_increment; ++ heap_slots_increment *= heap_slots_growth_factor; ++ if (heap_slots <= 0) heap_slots = heap_min_slots; + + while (p < pend) { + p->as.free.flags = 0; +@@ -1102,6 +1369,39 @@ finalize_list(p) + } + } + ++static char* obj_type(int tp) ++{ ++ switch (tp) { ++ case T_NIL : return "NIL"; ++ case T_OBJECT : return "OBJECT"; ++ case T_CLASS : return "CLASS"; ++ case T_ICLASS : return "ICLASS"; ++ case T_MODULE : return "MODULE"; ++ case T_FLOAT : return "FLOAT"; ++ case T_STRING : return "STRING"; ++ case T_REGEXP : return "REGEXP"; ++ case T_ARRAY : return "ARRAY"; ++ case T_FIXNUM : return "FIXNUM"; ++ case T_HASH : return "HASH"; ++ case T_STRUCT : return "STRUCT"; ++ case T_BIGNUM : return "BIGNUM"; ++ case T_FILE : return "FILE"; ++ ++ case T_TRUE : return "TRUE"; ++ case T_FALSE : return "FALSE"; ++ case T_DATA : return "DATA"; ++ case T_MATCH : return "MATCH"; ++ case T_SYMBOL : return "SYMBOL"; ++ ++ case T_BLKTAG : return "BLKTAG"; ++ case T_UNDEF : return "UNDEF"; ++ case T_VARMAP : return "VARMAP"; ++ case T_SCOPE : return "SCOPE"; ++ case T_NODE : return "NODE"; ++ default: return "____"; ++ } ++} ++ + static void + free_unused_heaps() + { +@@ -1134,12 +1434,21 @@ gc_sweep() + unsigned long live = 0; + unsigned long free_min = 0; + ++ unsigned long really_freed = 0; ++ int free_counts[256]; ++ int live_counts[256]; ++ int do_gc_stats = gc_statistics & verbose_gc_stats; ++ + for (i = 0; i < heaps_used; i++) { + free_min += heaps[i].limit; + } + free_min = free_min * 0.2; +- if (free_min < FREE_MIN) +- free_min = FREE_MIN; ++ if (free_min < heap_free_min) ++ free_min = heap_free_min; ++ ++ if (do_gc_stats) { ++ for (i = 0 ; i< 256; i++) { free_counts[i] = live_counts[i] = 0; } ++ } + + if (ruby_in_compile && ruby_parser_stack_on_heap()) { + /* should not reclaim nodes during compilation +@@ -1174,6 +1483,9 @@ gc_sweep() + if (p->as.basic.flags && + ((deferred = obj_free((VALUE)p)) || + ((FL_TEST(p, FL_FINALIZE)) && need_call_final))) { ++ if (do_gc_stats) { ++ really_freed++; ++ } + if (!deferred) { + p->as.free.flags = T_DEFERRED; + RDATA(p)->dfree = 0; +@@ -1183,6 +1495,12 @@ gc_sweep() + final_list = p; + } + else { ++ if (do_gc_stats) { ++ int obt = p->as.basic.flags & T_MASK; ++ if (obt) { ++ free_counts[obt]++; ++ } ++ } + add_freelist(p); + } + n++; +@@ -1194,6 +1512,9 @@ gc_sweep() + else { + RBASIC(p)->flags &= ~FL_MARK; + live++; ++ if (do_gc_stats) { ++ live_counts[RANY((VALUE)p)->as.basic.flags & T_MASK]++; ++ } + } + p++; + } +@@ -1212,7 +1533,7 @@ gc_sweep() + } + if (malloc_increase > malloc_limit) { + malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed); +- if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT; ++ if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit; + } + malloc_increase = 0; + if (freed < free_min) { +@@ -1220,6 +1541,20 @@ gc_sweep() + } + during_gc = 0; + ++ if (do_gc_stats) { ++ fprintf(gc_data_file, "objects processed: %.7d\n", live+freed); ++ fprintf(gc_data_file, "live objects : %.7d\n", live); ++ fprintf(gc_data_file, "freelist objects : %.7d\n", freed - really_freed); ++ fprintf(gc_data_file, "freed objects : %.7d\n", really_freed); ++ for(i=0; i<256; i++) { ++ if (free_counts[i]>0) { ++ fprintf(gc_data_file, ++ "kept %.7d / freed %.7d objects of type %s\n", ++ live_counts[i], free_counts[i], obj_type(i)); ++ } ++ } ++ } ++ + /* clear finalization list */ + if (final_list) { + deferred_final_list = final_list; +@@ -1423,6 +1758,7 @@ garbage_collect() + struct gc_list *list; + struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */ + jmp_buf save_regs_gc_mark; ++ struct timeval gctv1, gctv2; + SET_STACK_END; + + #ifdef HAVE_NATIVETHREAD +@@ -1439,6 +1775,14 @@ garbage_collect() + if (during_gc) return; + during_gc++; + ++ if (gc_statistics) { ++ gc_collections++; ++ gettimeofday(&gctv1, NULL); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "Garbage collection started\n"); ++ } ++ } ++ + init_mark_stack(); + + gc_mark((VALUE)ruby_current_node, 0); +@@ -1514,6 +1858,17 @@ garbage_collect() + } while (!MARK_STACK_EMPTY); + + gc_sweep(); ++ ++ if (gc_statistics) { ++ GC_TIME_TYPE musecs_used; ++ gettimeofday(&gctv2, NULL); ++ musecs_used = ((GC_TIME_TYPE)(gctv2.tv_sec - gctv1.tv_sec) * 1000000) + (gctv2.tv_usec - gctv1.tv_usec); ++ gc_time += musecs_used; ++ ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "GC time: %d msec\n", musecs_used / 1000); ++ } ++ } + } + + void +@@ -1695,6 +2050,7 @@ Init_heap() + if (!rb_gc_stack_start) { + Init_stack(0); + } ++ set_gc_parameters(); + add_heap(); + } + +@@ -2163,6 +2519,14 @@ Init_GC() + rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1); + rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0); + ++ rb_define_singleton_method(rb_mGC, "enable_stats", rb_gc_enable_stats, 0); ++ rb_define_singleton_method(rb_mGC, "disable_stats", rb_gc_disable_stats, 0); ++ rb_define_singleton_method(rb_mGC, "clear_stats", rb_gc_clear_stats, 0); ++ rb_define_singleton_method(rb_mGC, "collections", rb_gc_collections, 0); ++ rb_define_singleton_method(rb_mGC, "time", rb_gc_time, 0); ++ rb_define_singleton_method(rb_mGC, "dump", rb_gc_dump, 0); ++ rb_define_singleton_method(rb_mGC, "log", rb_gc_log, 1); ++ + rb_mObSpace = rb_define_module("ObjectSpace"); + rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1); + rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0); diff --git a/patches/ruby/1.8.7/readline-fix.diff b/patches/ruby/1.8.7/readline-fix.diff new file mode 100644 index 0000000000..41b5346c8d --- /dev/null +++ b/patches/ruby/1.8.7/readline-fix.diff @@ -0,0 +1,31 @@ +diff --git a/ext/readline/extconf.rb b/ext/readline/extconf.rb +index b820c0b..f299cba 100644 +--- a/ext/readline/extconf.rb ++++ b/ext/readline/extconf.rb +@@ -59,6 +59,9 @@ have_func("rl_cleanup_after_signal") + have_func("rl_clear_signals") + have_func("rl_vi_editing_mode") + have_func("rl_emacs_editing_mode") ++# workaround for native windows. ++/mswin|bccwin|mingw/ !~ RUBY_PLATFORM && have_readline_var("rl_catch_sigwinch") ++/mswin|bccwin|mingw/ !~ RUBY_PLATFORM && have_readline_var("rl_catch_signals") + have_func("replace_history_entry") + have_func("remove_history") + create_makefile("readline") +diff --git a/ext/readline/readline.c b/ext/readline/readline.c +index c9acaad..637cb99 100644 +--- a/ext/readline/readline.c ++++ b/ext/readline/readline.c +@@ -833,6 +833,12 @@ Init_readline() + #ifdef HAVE_RL_EVENT_HOOK + rl_event_hook = readline_event; + #endif ++#ifdef HAVE_RL_CATCH_SIGNALS ++ rl_catch_signals = 0; ++#endif ++#ifdef HAVE_RL_CATCH_SIGWINCH ++ rl_catch_sigwinch = 0; ++#endif + #ifdef HAVE_RL_CLEAR_SIGNALS + rl_clear_signals(); + #endif diff --git a/patches/ruby/1.9.1/railsbench.patch b/patches/ruby/1.9.1/railsbench.patch new file mode 100644 index 0000000000..c177b26e86 --- /dev/null +++ b/patches/ruby/1.9.1/railsbench.patch @@ -0,0 +1,685 @@ +diff --git a/a/gc.c b/b/gc.c +index bcdc9af..b380842 100644 +--- a/a/gc.c ++++ b/b/gc.c +@@ -23,8 +23,16 @@ + #include + #include + ++#ifdef _WIN32 ++#include ++#else ++#include ++#endif ++ + #ifdef HAVE_SYS_TIME_H + #include ++#elif defined(_WIN32) ++#include + #endif + + #ifdef HAVE_SYS_RESOURCE_H +@@ -211,11 +219,11 @@ getrusage_time(void) + if (objspace->profile.run) {\ + size_t count = objspace->profile.count;\ + objspace->profile.record[count].heap_use_slots = heaps_used;\ +- objspace->profile.record[count].heap_live_objects = live;\ ++ objspace->profile.record[count].heap_live_objects = live_objects;\ + objspace->profile.record[count].heap_free_objects = freed;\ + objspace->profile.record[count].heap_total_objects = heaps_used * HEAP_OBJ_LIMIT;\ + objspace->profile.record[count].have_finalize = final_list ? Qtrue : Qfalse;\ +- objspace->profile.record[count].heap_use_size = live * sizeof(RVALUE);\ ++ objspace->profile.record[count].heap_use_size = live_objects * sizeof(RVALUE);\ + objspace->profile.record[count].heap_total_size = heaps_used * (HEAP_OBJ_LIMIT * sizeof(RVALUE));\ + }\ + } while(0) +@@ -232,7 +240,7 @@ getrusage_time(void) + if (objspace->profile.run) {\ + size_t count = objspace->profile.count;\ + objspace->profile.record[count].heap_total_objects = heaps_used * HEAP_OBJ_LIMIT;\ +- objspace->profile.record[count].heap_use_size = live * sizeof(RVALUE);\ ++ objspace->profile.record[count].heap_use_size = live_objects * sizeof(RVALUE);\ + objspace->profile.record[count].heap_total_size = heaps_used * HEAP_SIZE;\ + }\ + } while(0) +@@ -372,7 +380,7 @@ rb_objspace_alloc(void) + { + rb_objspace_t *objspace = malloc(sizeof(rb_objspace_t)); + memset(objspace, 0, sizeof(*objspace)); +- malloc_limit = GC_MALLOC_LIMIT; ++ malloc_limit = initial_malloc_limit; + ruby_gc_stress = ruby_initial_gc_stress; + + return objspace; +@@ -405,6 +413,170 @@ int ruby_disable_gc_stress = 0; + static void run_final(rb_objspace_t *objspace, VALUE obj); + static int garbage_collect(rb_objspace_t *objspace); + ++static unsigned long live_objects = 0; ++unsigned long rb_os_live_objects() ++{ return live_objects; } ++ ++#if defined(HAVE_LONG_LONG) ++static unsigned long long allocated_objects = 0; ++unsigned long long rb_os_allocated_objects() ++{ return allocated_objects; } ++#else ++static unsigned long allocated_objects = 0; ++unsigned long rb_os_allocated_objects() ++{ return allocated_objects; } ++#endif ++ ++static int heap_min_slots = HEAP_MIN_SLOTS; ++static int heap_free_min = 4096; ++static double heap_slots_growth_factor = 1.8; ++ ++static long initial_malloc_limit = GC_MALLOC_LIMIT; ++static int verbose_gc_stats = Qfalse; ++static FILE* gc_data_file = NULL; ++ ++static void set_gc_parameters() ++{ ++ char *gc_stats_ptr, *min_slots_ptr, *free_min_ptr, *heap_slots_incr_ptr, ++ *heap_incr_ptr, *malloc_limit_ptr, *gc_heap_file_ptr, *heap_slots_growth_factor_ptr; ++ ++ gc_data_file = stderr; ++ ++ gc_stats_ptr = getenv("RUBY_GC_STATS"); ++ if (gc_stats_ptr != NULL) { ++ int gc_stats_i = atoi(gc_stats_ptr); ++ if (gc_stats_i > 0) { ++ verbose_gc_stats = Qtrue; ++ } ++ } ++ ++ gc_heap_file_ptr = getenv("RUBY_GC_DATA_FILE"); ++ if (gc_heap_file_ptr != NULL) { ++ FILE* data_file = fopen(gc_heap_file_ptr, "w"); ++ if (data_file != NULL) { ++ gc_data_file = data_file; ++ } ++ else { ++ fprintf(stderr, ++ "can't open gc log file %s for writing, using default\n", gc_heap_file_ptr); ++ } ++ } ++ ++ min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS"); ++ if (min_slots_ptr != NULL) { ++ int min_slots_i = atoi(min_slots_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_MIN_SLOTS=%s\n", min_slots_ptr); ++ } ++ if (min_slots_i > 0) { ++ heap_min_slots = min_slots_i; ++ } ++ } ++ ++ free_min_ptr = getenv("RUBY_HEAP_FREE_MIN"); ++ if (free_min_ptr != NULL) { ++ int free_min_i = atoi(free_min_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_FREE_MIN=%s\n", free_min_ptr); ++ } ++ if (free_min_i > 0) { ++ heap_free_min = free_min_i; ++ } ++ } ++ ++ heap_incr_ptr = getenv("RUBY_HEAP_INCREMENT"); ++ if (heap_incr_ptr != NULL) { ++ int heap_incr_i = atoi(heap_incr_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_INCREMENT=%s\n", heap_incr_ptr); ++ } ++ if (heap_incr_i > 0) { ++ (&rb_objspace)->malloc_params.increase = heap_incr_i; ++ } ++ } ++ ++ heap_slots_incr_ptr = getenv("RUBY_HEAP_SLOTS_INCREMENT"); ++ if (heap_slots_incr_ptr != NULL) { ++ int heap_slots_incr_i = atoi(heap_slots_incr_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_SLOTS_INCREMENT=%s\n", heap_slots_incr_ptr); ++ } ++ if (heap_slots_incr_i > 0) { ++ (&rb_objspace)->malloc_params.increase = heap_slots_incr_i; ++ } ++ } ++ ++ heap_slots_growth_factor_ptr = getenv("RUBY_HEAP_SLOTS_GROWTH_FACTOR"); ++ if (heap_slots_growth_factor_ptr != NULL) { ++ double heap_slots_growth_factor_d = atoi(heap_slots_growth_factor_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_HEAP_SLOTS_GROWTH_FACTOR=%s\n", heap_slots_growth_factor_ptr); ++ } ++ if (heap_slots_growth_factor_d > 0) { ++ heap_slots_growth_factor = heap_slots_growth_factor_d; ++ } ++ } ++ ++ malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT"); ++ if (malloc_limit_ptr != NULL) { ++ int malloc_limit_i = atol(malloc_limit_ptr); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "RUBY_GC_MALLOC_LIMIT=%s\n", malloc_limit_ptr); ++ } ++ if (malloc_limit_i > 0) { ++ initial_malloc_limit = malloc_limit_i; ++ } ++ } ++} ++ ++/* ++ * call-seq: ++ * GC.dump => nil ++ * ++ * dumps information about the current GC data structures to the GC log file ++ * ++ * GC.dump #=> nil ++ * ++ */ ++ ++VALUE ++rb_gc_dump() ++{ ++ int i; ++ rb_objspace_t *objspace = &rb_objspace; ++ ++ for (i = 0; i < heaps_used; i++) { ++ int heap_size = heaps[i].limit; ++ fprintf(gc_data_file, "HEAP[%2d]: size=%7d\n", i, heap_size); ++ } ++ ++ return Qnil; ++} ++ ++/* ++ * call-seq: ++ * GC.log String => String ++ * ++ * Logs string to the GC data file and returns it. ++ * ++ * GC.log "manual GC call" #=> "manual GC call" ++ * ++ */ ++ ++VALUE ++rb_gc_log(VALUE self, VALUE original_str) ++{ ++ if (original_str == Qnil) { ++ fprintf(gc_data_file, "\n"); ++ } ++ else { ++ VALUE str = StringValue(original_str); ++ char *p = RSTRING_PTR(str); ++ fprintf(gc_data_file, "%s\n", p); ++ } ++ return original_str; ++} ++ + void + rb_global_variable(VALUE *var) + { +@@ -454,6 +626,10 @@ rb_memerror(void) + rb_exc_raise(nomem_error); + } + ++long gc_allocated_size = 0; ++long gc_num_allocations = 0; ++static int gc_statistics = 0; ++ + /* + * call-seq: + * GC.stress => true or false +@@ -699,6 +875,10 @@ vm_xfree(rb_objspace_t *objspace, void *ptr) + void * + ruby_xmalloc(size_t size) + { ++ if (gc_statistics) { ++ gc_allocated_size += size; ++ gc_num_allocations += 1; ++ } + return vm_xmalloc(&rb_objspace, size); + } + +@@ -744,6 +924,13 @@ ruby_xfree(void *x) + vm_xfree(&rb_objspace, x); + } + ++#if HAVE_LONG_LONG ++#define GC_TIME_TYPE LONG_LONG ++#else ++#define GC_TIME_TYPE long ++#endif ++static GC_TIME_TYPE gc_time = 0; ++static int gc_collections = 0; + + /* + * call-seq: +@@ -775,7 +962,7 @@ rb_gc_enable(void) + * Disables garbage collection, returning true if garbage + * collection was already disabled. + * +- * GC.disable #=> false ++ * GC.disable #=> false or true + * GC.disable #=> true + * + */ +@@ -790,6 +977,139 @@ rb_gc_disable(void) + return old; + } + ++/* ++ * call-seq: ++ * GC.enable_stats => true or false ++ * ++ * Enables garbage collection statistics, returning true if garbage ++ * collection statistics was already enabled. ++ * ++ * GC.enable_stats #=> false or true ++ * GC.enable_stats #=> true ++ * ++ */ ++ ++VALUE ++rb_gc_enable_stats() ++{ ++ int old = gc_statistics; ++ gc_statistics = Qtrue; ++ return old; ++} ++ ++/* ++ * call-seq: ++ * GC.disable_stats => true or false ++ * ++ * Disables garbage collection statistics, returning true if garbage ++ * collection statistics was already disabled. ++ * ++ * GC.disable_stats #=> false or true ++ * GC.disable_stats #=> true ++ * ++ */ ++ ++VALUE ++rb_gc_disable_stats() ++{ ++ int old = gc_statistics; ++ gc_statistics = Qfalse; ++ gc_allocated_size = 0; ++ gc_num_allocations = 0; ++ return old; ++} ++ ++/* ++ * call-seq: ++ * GC.clear_stats => nil ++ * ++ * Clears garbage collection statistics, returning nil. This resets the number ++ * of collections (GC.collections) and the time used (GC.time) to 0. ++ * ++ * GC.clear_stats #=> nil ++ * ++ */ ++ ++VALUE ++rb_gc_clear_stats() ++{ ++ gc_collections = 0; ++ gc_time = 0; ++ gc_allocated_size = 0; ++ gc_num_allocations = 0; ++ return Qnil; ++} ++ ++/* ++ * call-seq: ++ * GC.allocated_size => Integer ++ * ++ * Returns the size of memory (in bytes) allocated since GC statistics collection ++ * was enabled. ++ * ++ * GC.allocated_size #=> 35 ++ * ++ */ ++VALUE ++rb_gc_allocated_size() ++{ ++ return INT2NUM(gc_allocated_size); ++} ++ ++/* ++ * call-seq: ++ * GC.num_allocations => Integer ++ * ++ * Returns the number of memory allocations since GC statistics collection ++ * was enabled. ++ * ++ * GC.num_allocations #=> 150 ++ * ++ */ ++VALUE ++rb_gc_num_allocations() ++{ ++ return INT2NUM(gc_num_allocations); ++} ++ ++/* ++ * call-seq: ++ * GC.collections => Integer ++ * ++ * Returns the number of garbage collections performed while GC statistics collection ++ * was enabled. ++ * ++ * GC.collections #=> 35 ++ * ++ */ ++ ++VALUE ++rb_gc_collections() ++{ ++ return INT2NUM(gc_collections); ++} ++ ++/* ++ * call-seq: ++ * GC.time => Integer ++ * ++ * Returns the time spent during garbage collection while GC statistics collection ++ * was enabled (in micro seconds). ++ * ++ * GC.time #=> 20000 ++ * ++ */ ++ ++VALUE ++rb_gc_time() ++{ ++#if HAVE_LONG_LONG ++ return LL2NUM(gc_time); ++#else ++ return LONG2NUM(gc_time); ++#endif ++} ++ + VALUE rb_mGC; + + void +@@ -921,7 +1241,7 @@ init_heap(rb_objspace_t *objspace) + { + size_t add, i; + +- add = HEAP_MIN_SLOTS / HEAP_OBJ_LIMIT; ++ add = heap_min_slots / HEAP_OBJ_LIMIT; + + if ((heaps_used + add) > heaps_length) { + allocate_heaps(objspace, heaps_used + add); +@@ -934,12 +1254,12 @@ init_heap(rb_objspace_t *objspace) + objspace->profile.invoke_time = getrusage_time(); + } + +- + static void + set_heaps_increment(rb_objspace_t *objspace) + { +- size_t next_heaps_length = heaps_used * 1.8; ++ size_t next_heaps_length = heaps_used * heap_slots_growth_factor; + heaps_inc = next_heaps_length - heaps_used; ++ if (next_heaps_length <= 0) next_heaps_length = heap_min_slots; + + if (next_heaps_length > heaps_length) { + allocate_heaps(objspace, next_heaps_length); +@@ -980,6 +1300,8 @@ rb_newobj_from_heap(rb_objspace_t *objspace) + RANY(obj)->line = rb_sourceline(); + #endif + ++ live_objects++; ++ allocated_objects++; + return obj; + } + +@@ -1671,6 +1993,39 @@ finalize_list(rb_objspace_t *objspace, RVALUE *p) + } + } + ++static char* obj_type(int tp) ++{ ++ switch (tp) { ++ case T_NIL : return "NIL"; ++ case T_OBJECT : return "OBJECT"; ++ case T_CLASS : return "CLASS"; ++ case T_ICLASS : return "ICLASS"; ++ case T_MODULE : return "MODULE"; ++ case T_FLOAT : return "FLOAT"; ++ case T_STRING : return "STRING"; ++ case T_REGEXP : return "REGEXP"; ++ case T_ARRAY : return "ARRAY"; ++ case T_FIXNUM : return "FIXNUM"; ++ case T_HASH : return "HASH"; ++ case T_STRUCT : return "STRUCT"; ++ case T_BIGNUM : return "BIGNUM"; ++ case T_FILE : return "FILE"; ++ ++ case T_TRUE : return "TRUE"; ++ case T_FALSE : return "FALSE"; ++ case T_DATA : return "DATA"; ++ case T_MATCH : return "MATCH"; ++ case T_SYMBOL : return "SYMBOL"; ++ ++ //case T_BLKTAG : return "BLKTAG"; ++ case T_UNDEF : return "UNDEF"; ++ case T_RATIONAL : return "RATIONAL"; ++ case T_COMPLEX : return "COMPLEX"; ++ case T_NODE : return "NODE"; ++ default: return "____"; ++ } ++} ++ + static void + free_unused_heaps(rb_objspace_t *objspace) + { +@@ -1711,14 +2066,24 @@ gc_sweep(rb_objspace_t *objspace) + RVALUE *p, *pend, *final_list; + size_t freed = 0; + size_t i; +- size_t live = 0, free_min = 0, do_heap_free = 0; ++ size_t free_min = 0, do_heap_free = 0; ++ live_objects = 0; ++ ++ unsigned long really_freed = 0; ++ int free_counts[256]; ++ int live_counts[256]; ++ int do_gc_stats = gc_statistics & verbose_gc_stats; + + do_heap_free = (heaps_used * HEAP_OBJ_LIMIT) * 0.65; + free_min = (heaps_used * HEAP_OBJ_LIMIT) * 0.2; + +- if (free_min < FREE_MIN) { ++ if (free_min < heap_free_min) { + do_heap_free = heaps_used * HEAP_OBJ_LIMIT; +- free_min = FREE_MIN; ++ free_min = heap_free_min; ++ } ++ ++ if (do_gc_stats) { ++ for (i = 0 ; i< 256; i++) { free_counts[i] = live_counts[i] = 0; } + } + + freelist = 0; +@@ -1739,6 +2104,9 @@ gc_sweep(rb_objspace_t *objspace) + if (!deferred) { + p->as.free.flags = T_ZOMBIE; + RDATA(p)->dfree = 0; ++ if (do_gc_stats) { ++ really_freed++; ++ } + } + p->as.free.flags |= FL_MARK; + p->as.free.next = final_list; +@@ -1746,6 +2114,12 @@ gc_sweep(rb_objspace_t *objspace) + final_num++; + } + else { ++ if (do_gc_stats) { ++ int obt = p->as.basic.flags & T_MASK; ++ if (obt) { ++ free_counts[obt]++; ++ } ++ } + add_freelist(objspace, p); + free_num++; + } +@@ -1756,7 +2130,10 @@ gc_sweep(rb_objspace_t *objspace) + } + else { + RBASIC(p)->flags &= ~FL_MARK; +- live++; ++ live_objects++; ++ if (do_gc_stats) { ++ live_counts[RANY((VALUE)p)->as.basic.flags & T_MASK]++; ++ } + } + p++; + } +@@ -1777,8 +2154,8 @@ gc_sweep(rb_objspace_t *objspace) + } + GC_PROF_SET_MALLOC_INFO; + if (malloc_increase > malloc_limit) { +- malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed); +- if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT; ++ malloc_limit += (malloc_increase - malloc_limit) * (double)live_objects / (live_objects + freed); ++ if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit; + } + malloc_increase = 0; + if (freed < free_min) { +@@ -1786,6 +2163,20 @@ gc_sweep(rb_objspace_t *objspace) + heaps_increment(objspace); + } + during_gc = 0; ++ ++ if (do_gc_stats) { ++ fprintf(gc_data_file, "objects processed: %.7d\n", live_objects+freed); ++ fprintf(gc_data_file, "live objects : %.7d\n", live_objects); ++ fprintf(gc_data_file, "freelist objects : %.7d\n", freed - really_freed); ++ fprintf(gc_data_file, "freed objects : %.7d\n", really_freed); ++ for(i=0; i<256; i++) { ++ if (free_counts[i]>0) { ++ fprintf(gc_data_file, ++ "kept %.7d / freed %.7d objects of type %s\n", ++ live_counts[i], free_counts[i], obj_type(i)); ++ } ++ } ++ } + + /* clear finalization list */ + if (final_list) { +@@ -1994,6 +2385,7 @@ garbage_collect(rb_objspace_t *objspace) + { + struct gc_list *list; + rb_thread_t *th = GET_THREAD(); ++ struct timeval gctv1, gctv2; + INIT_GC_PROF_PARAMS; + + if (GC_NOTIFY) printf("start garbage_collect()\n"); +@@ -2013,6 +2405,14 @@ garbage_collect(rb_objspace_t *objspace) + } + during_gc++; + objspace->count++; ++ ++ if (gc_statistics) { ++ gc_collections++; ++ gettimeofday(&gctv1, NULL); ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "Garbage collection started\n"); ++ } ++ } + + GC_PROF_TIMER_START; + GC_PROF_MARK_TIMER_START; +@@ -2060,6 +2460,17 @@ garbage_collect(rb_objspace_t *objspace) + GC_PROF_SWEEP_TIMER_START; + gc_sweep(objspace); + GC_PROF_SWEEP_TIMER_STOP; ++ ++ if (gc_statistics) { ++ GC_TIME_TYPE musecs_used; ++ gettimeofday(&gctv2, NULL); ++ musecs_used = ((GC_TIME_TYPE)(gctv2.tv_sec - gctv1.tv_sec) * 1000000) + (gctv2.tv_usec - gctv1.tv_usec); ++ gc_time += musecs_used; ++ ++ if (verbose_gc_stats) { ++ fprintf(gc_data_file, "GC time: %d msec\n", musecs_used / 1000); ++ } ++ } + + GC_PROF_TIMER_STOP; + if (GC_NOTIFY) printf("end garbage_collect()\n"); +@@ -2153,6 +2564,7 @@ Init_stack(VALUE *addr) + void + Init_heap(void) + { ++ set_gc_parameters(); + init_heap(&rb_objspace); + } + +@@ -2868,6 +3280,34 @@ gc_profile_report(int argc, VALUE *argv, VALUE self) + return Qnil; + } + ++/* call-seq: ++ * ObjectSpace.live_objects => number ++ * ++ * Returns the count of objects currently allocated in the system. This goes ++ * down after the garbage collector runs. ++ */ ++static ++VALUE os_live_objects(VALUE self) ++{ return ULONG2NUM(live_objects); } ++ ++/* call-seq: ++ * ObjectSpace.allocated_objects => number ++ * ++ * Returns the count of objects allocated since the Ruby interpreter has ++ * started. This number can only increase. To know how many objects are ++ * currently allocated, use ObjectSpace::live_objects ++ */ ++static ++VALUE os_allocated_objects(VALUE self) ++{ ++#if defined(HAVE_LONG_LONG) ++ return ULL2NUM(allocated_objects); ++#else ++ return ULONG2NUM(allocated_objects); ++#endif ++} ++ ++ + + /* + * The GC module provides an interface to Ruby's mark and +@@ -2897,10 +3337,23 @@ Init_GC(void) + rb_define_singleton_method(rb_mProfiler, "clear", gc_profile_clear, 0); + rb_define_singleton_method(rb_mProfiler, "result", gc_profile_result, 0); + rb_define_singleton_method(rb_mProfiler, "report", gc_profile_report, -1); ++ ++ rb_define_singleton_method(rb_mGC, "enable_stats", rb_gc_enable_stats, 0); ++ rb_define_singleton_method(rb_mGC, "disable_stats", rb_gc_disable_stats, 0); ++ rb_define_singleton_method(rb_mGC, "clear_stats", rb_gc_clear_stats, 0); ++ rb_define_singleton_method(rb_mGC, "allocated_size", rb_gc_allocated_size, 0); ++ rb_define_singleton_method(rb_mGC, "num_allocations", rb_gc_num_allocations, 0); ++ rb_define_singleton_method(rb_mGC, "collections", rb_gc_collections, 0); ++ rb_define_singleton_method(rb_mGC, "time", rb_gc_time, 0); ++ rb_define_singleton_method(rb_mGC, "dump", rb_gc_dump, 0); ++ rb_define_singleton_method(rb_mGC, "log", rb_gc_log, 1); + + rb_mObSpace = rb_define_module("ObjectSpace"); + rb_define_module_function(rb_mObSpace, "each_object", os_each_obj, -1); + rb_define_module_function(rb_mObSpace, "garbage_collect", rb_gc_start, 0); ++ rb_define_module_function(rb_mObSpace, "live_objects", os_live_objects, 0); ++ rb_define_module_function(rb_mObSpace, "allocated_objects", os_allocated_objects, 0); ++ + + rb_define_module_function(rb_mObSpace, "define_finalizer", define_final, -1); + rb_define_module_function(rb_mObSpace, "undefine_finalizer", undefine_final, 1); diff --git a/patches/ruby/1.9.2/gcdata.patch b/patches/ruby/1.9.2/gcdata.patch new file mode 100644 index 0000000000..d0ae1cc389 --- /dev/null +++ b/patches/ruby/1.9.2/gcdata.patch @@ -0,0 +1,119 @@ +diff --git a/gc.c b/gc.c +index e723969..8b5f8e0 100644 +--- a/gc.c ++++ b/gc.c +@@ -290,16 +290,12 @@ struct gc_list { + struct gc_list *next; + }; + +-#define CALC_EXACT_MALLOC_SIZE 0 +- + typedef struct rb_objspace { + struct { + size_t limit; + size_t increase; +-#if CALC_EXACT_MALLOC_SIZE + size_t allocated_size; + size_t allocations; +-#endif + } malloc_params; + struct { + size_t increment; +@@ -646,10 +642,6 @@ vm_xmalloc(rb_objspace_t *objspace, size_t size) + } + if (size == 0) size = 1; + +-#if CALC_EXACT_MALLOC_SIZE +- size += sizeof(size_t); +-#endif +- + if ((ruby_gc_stress && !ruby_disable_gc_stress) || + (malloc_increase+size) > malloc_limit) { + garbage_collect_with_gvl(objspace); +@@ -665,12 +657,8 @@ vm_xmalloc(rb_objspace_t *objspace, size_t size) + } + malloc_increase += size; + +-#if CALC_EXACT_MALLOC_SIZE + objspace->malloc_params.allocated_size += size; + objspace->malloc_params.allocations++; +- ((size_t *)mem)[0] = size; +- mem = (size_t *)mem + 1; +-#endif + + return mem; + } +@@ -691,11 +679,7 @@ vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size) + if (ruby_gc_stress && !ruby_disable_gc_stress) + garbage_collect_with_gvl(objspace); + +-#if CALC_EXACT_MALLOC_SIZE +- size += sizeof(size_t); + objspace->malloc_params.allocated_size -= size; +- ptr = (size_t *)ptr - 1; +-#endif + + mem = realloc(ptr, size); + if (!mem) { +@@ -708,11 +692,7 @@ vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size) + } + malloc_increase += size; + +-#if CALC_EXACT_MALLOC_SIZE + objspace->malloc_params.allocated_size += size; +- ((size_t *)mem)[0] = size; +- mem = (size_t *)mem + 1; +-#endif + + return mem; + } +@@ -720,14 +700,6 @@ vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size) + static void + vm_xfree(rb_objspace_t *objspace, void *ptr) + { +-#if CALC_EXACT_MALLOC_SIZE +- size_t size; +- ptr = ((size_t *)ptr) - 1; +- size = ((size_t*)ptr)[0]; +- objspace->malloc_params.allocated_size -= size; +- objspace->malloc_params.allocations--; +-#endif +- + free(ptr); + } + +@@ -2994,7 +2966,6 @@ gc_count(VALUE self) + return UINT2NUM((&rb_objspace)->count); + } + +-#if CALC_EXACT_MALLOC_SIZE + /* + * call-seq: + * GC.malloc_allocated_size -> Integer +@@ -3024,7 +2995,6 @@ gc_malloc_allocations(VALUE self) + { + return UINT2NUM((&rb_objspace)->malloc_params.allocations); + } +-#endif + + static VALUE + gc_profile_record_get(void) +@@ -3182,6 +3152,8 @@ Init_GC(void) + rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0); + rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1); + rb_define_singleton_method(rb_mGC, "count", gc_count, 0); ++ rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0); ++ rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0); + rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0); + + rb_mProfiler = rb_define_module_under(rb_mGC, "Profiler"); +@@ -3211,9 +3183,4 @@ Init_GC(void) + rb_define_method(rb_mKernel, "object_id", rb_obj_id, 0); + + rb_define_module_function(rb_mObSpace, "count_objects", count_objects, -1); +- +-#if CALC_EXACT_MALLOC_SIZE +- rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0); +- rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0); +-#endif + } diff --git a/patches/ruby/1.9.3/gcdata.patch b/patches/ruby/1.9.3/gcdata.patch new file mode 100644 index 0000000000..3b870354b3 --- /dev/null +++ b/patches/ruby/1.9.3/gcdata.patch @@ -0,0 +1,119 @@ +diff --git a/gc.c b/gc.c +index 8750a27..ae1b5a9 100644 +--- a/gc.c ++++ b/gc.c +@@ -304,16 +304,12 @@ struct gc_list { + struct gc_list *next; + }; + +-#define CALC_EXACT_MALLOC_SIZE 0 +- + typedef struct rb_objspace { + struct { + size_t limit; + size_t increase; +-#if CALC_EXACT_MALLOC_SIZE + size_t allocated_size; + size_t allocations; +-#endif + } malloc_params; + struct { + size_t increment; +@@ -667,10 +663,6 @@ vm_xmalloc(rb_objspace_t *objspace, size_t size) + } + if (size == 0) size = 1; + +-#if CALC_EXACT_MALLOC_SIZE +- size += sizeof(size_t); +-#endif +- + if ((ruby_gc_stress && !ruby_disable_gc_stress) || + (malloc_increase+size) > malloc_limit) { + garbage_collect_with_gvl(objspace); +@@ -686,12 +678,8 @@ vm_xmalloc(rb_objspace_t *objspace, size_t size) + } + malloc_increase += size; + +-#if CALC_EXACT_MALLOC_SIZE + objspace->malloc_params.allocated_size += size; + objspace->malloc_params.allocations++; +- ((size_t *)mem)[0] = size; +- mem = (size_t *)mem + 1; +-#endif + + return mem; + } +@@ -712,11 +700,7 @@ vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size) + if (ruby_gc_stress && !ruby_disable_gc_stress) + garbage_collect_with_gvl(objspace); + +-#if CALC_EXACT_MALLOC_SIZE +- size += sizeof(size_t); + objspace->malloc_params.allocated_size -= size; +- ptr = (size_t *)ptr - 1; +-#endif + + mem = realloc(ptr, size); + if (!mem) { +@@ -729,11 +713,7 @@ vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size) + } + malloc_increase += size; + +-#if CALC_EXACT_MALLOC_SIZE + objspace->malloc_params.allocated_size += size; +- ((size_t *)mem)[0] = size; +- mem = (size_t *)mem + 1; +-#endif + + return mem; + } +@@ -741,14 +721,6 @@ vm_xrealloc(rb_objspace_t *objspace, void *ptr, size_t size) + static void + vm_xfree(rb_objspace_t *objspace, void *ptr) + { +-#if CALC_EXACT_MALLOC_SIZE +- size_t size; +- ptr = ((size_t *)ptr) - 1; +- size = ((size_t*)ptr)[0]; +- objspace->malloc_params.allocated_size -= size; +- objspace->malloc_params.allocations--; +-#endif +- + free(ptr); + } + +@@ -3168,7 +3140,6 @@ gc_count(VALUE self) + return UINT2NUM((&rb_objspace)->count); + } + +-#if CALC_EXACT_MALLOC_SIZE + /* + * call-seq: + * GC.malloc_allocated_size -> Integer +@@ -3198,7 +3169,6 @@ gc_malloc_allocations(VALUE self) + { + return UINT2NUM((&rb_objspace)->malloc_params.allocations); + } +-#endif + + static VALUE + gc_profile_record_get(void) +@@ -3366,6 +3336,8 @@ Init_GC(void) + rb_define_singleton_method(rb_mGC, "stress", gc_stress_get, 0); + rb_define_singleton_method(rb_mGC, "stress=", gc_stress_set, 1); + rb_define_singleton_method(rb_mGC, "count", gc_count, 0); ++ rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0); ++ rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0); + rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0); + + rb_mProfiler = rb_define_module_under(rb_mGC, "Profiler"); +@@ -3395,9 +3367,4 @@ Init_GC(void) + rb_define_method(rb_mKernel, "object_id", rb_obj_id, 0); + + rb_define_module_function(rb_mObSpace, "count_objects", count_objects, -1); +- +-#if CALC_EXACT_MALLOC_SIZE +- rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0); +- rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0); +-#endif + } diff --git a/pkg/gentoo/rvm-0.1.23.ebuild b/pkg/gentoo/rvm-0.1.23.ebuild new file mode 100644 index 0000000000..cf5ffc4355 --- /dev/null +++ b/pkg/gentoo/rvm-0.1.23.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="2cb2b6605ee88d6b85ed75c0734926d9e31434b9" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.24.ebuild b/pkg/gentoo/rvm-0.1.24.ebuild new file mode 100644 index 0000000000..0436082366 --- /dev/null +++ b/pkg/gentoo/rvm-0.1.24.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="be041901c8122590cf3079f9e7ecc96a54caffe3" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.25.ebuild b/pkg/gentoo/rvm-0.1.25.ebuild new file mode 100644 index 0000000000..85927fb80f --- /dev/null +++ b/pkg/gentoo/rvm-0.1.25.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="484ea8e4f5b412f8cff0b053c12df16577ff53ae" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.26.ebuild b/pkg/gentoo/rvm-0.1.26.ebuild new file mode 100644 index 0000000000..3891da8520 --- /dev/null +++ b/pkg/gentoo/rvm-0.1.26.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="adc0c098d10b2c33c436da4f7306dc01b1f5cd57" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.27.ebuild b/pkg/gentoo/rvm-0.1.27.ebuild new file mode 100644 index 0000000000..96b6e34c7e --- /dev/null +++ b/pkg/gentoo/rvm-0.1.27.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="07256c81002888525ff0d7127fa2c4672c2f5ceb" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.28.ebuild b/pkg/gentoo/rvm-0.1.28.ebuild new file mode 100644 index 0000000000..327facdf9a --- /dev/null +++ b/pkg/gentoo/rvm-0.1.28.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="5ac57bdd26572c164165bd67bbe514a2630a4164" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.29.ebuild b/pkg/gentoo/rvm-0.1.29.ebuild new file mode 100644 index 0000000000..a44d559aff --- /dev/null +++ b/pkg/gentoo/rvm-0.1.29.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="d8c93d42c5659c3d5309939b5118a952e160dc8b" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.30.ebuild b/pkg/gentoo/rvm-0.1.30.ebuild new file mode 100644 index 0000000000..ac3fe89ab9 --- /dev/null +++ b/pkg/gentoo/rvm-0.1.30.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="0a7a2e0c7001c191d17132569eb7499c619fd7f6" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.31.ebuild b/pkg/gentoo/rvm-0.1.31.ebuild new file mode 100644 index 0000000000..af055d1fae --- /dev/null +++ b/pkg/gentoo/rvm-0.1.31.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="db504de5d15e26b993d615838e680b2a06dc76cf" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.32.ebuild b/pkg/gentoo/rvm-0.1.32.ebuild new file mode 100644 index 0000000000..b0d51962aa --- /dev/null +++ b/pkg/gentoo/rvm-0.1.32.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="8327cd23e957e8fa2737962e6cf5dc88fddb9f03" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.33.ebuild b/pkg/gentoo/rvm-0.1.33.ebuild new file mode 100644 index 0000000000..4389a7f309 --- /dev/null +++ b/pkg/gentoo/rvm-0.1.33.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="facb9a779091ff71a46980c62d6cab5f54a749a1" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.34.ebuild b/pkg/gentoo/rvm-0.1.34.ebuild new file mode 100644 index 0000000000..afd0574e39 --- /dev/null +++ b/pkg/gentoo/rvm-0.1.34.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="799e1dbfd276fa56cf1884ec90a411576823bbf5" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.35.ebuild b/pkg/gentoo/rvm-0.1.35.ebuild new file mode 100644 index 0000000000..e7c5f3979d --- /dev/null +++ b/pkg/gentoo/rvm-0.1.35.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="9141e63b3f56fd2dc3d1b1d5cd08cacbf037924d" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.36.ebuild b/pkg/gentoo/rvm-0.1.36.ebuild new file mode 100644 index 0000000000..047e59d20d --- /dev/null +++ b/pkg/gentoo/rvm-0.1.36.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="06f6bff29e236f85742fa579c79aa3d3064b4146" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.37.ebuild b/pkg/gentoo/rvm-0.1.37.ebuild new file mode 100644 index 0000000000..7f7addba86 --- /dev/null +++ b/pkg/gentoo/rvm-0.1.37.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="30a91475cba8ebcfb753d62345bb9bfd065c4c03" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.38.ebuild b/pkg/gentoo/rvm-0.1.38.ebuild new file mode 100644 index 0000000000..ebc3ec63cd --- /dev/null +++ b/pkg/gentoo/rvm-0.1.38.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="ca4b2cb5384db7e235c6bb4dfcdc1c11039e3008" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.39.ebuild b/pkg/gentoo/rvm-0.1.39.ebuild new file mode 100644 index 0000000000..e093b3807e --- /dev/null +++ b/pkg/gentoo/rvm-0.1.39.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="761bcfa7d439339a259e9f2935649b225a7c3955" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.40.ebuild b/pkg/gentoo/rvm-0.1.40.ebuild new file mode 100644 index 0000000000..f89d23d3e3 --- /dev/null +++ b/pkg/gentoo/rvm-0.1.40.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="dc6667796a18b3888b7e8b3971edac86e45aa727" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.41.ebuild b/pkg/gentoo/rvm-0.1.41.ebuild new file mode 100644 index 0000000000..f8a97f0ef7 --- /dev/null +++ b/pkg/gentoo/rvm-0.1.41.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="5e7da83fa837b06eea926244209ae724a3fdc9c8" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-0.1.42.ebuild b/pkg/gentoo/rvm-0.1.42.ebuild new file mode 100644 index 0000000000..25a5b88332 --- /dev/null +++ b/pkg/gentoo/rvm-0.1.42.ebuild @@ -0,0 +1,62 @@ +# Copyright 1999-2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Header: $ + +EAPI=2 + +inherit eutils + +DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" +HOMEPAGE="http://rvm.beginrescueend.com/" + +# This should be the first 7 characters of the tagged version's commit. +VERSION_SHORT_SHA1="d9c6a839d0c988620cff832afe23da7968d2de1e" + +SRC_URI="http://github.com/wayneeseguin/rvm/tarball/${PV} -> ${P}.tar.gz" +LICENSE="MIT" +SLOT="0" +KEYWORDS="~x86" +IUSE="mono java" + +RDEPEND="net-misc/curl + sys-devel/patch + java? ( + dev-java/sun-jdk + dev-java/sun-jre-bin + ) + mono? ( dev-lang/mono )" + +S="${WORKDIR}/wayneeseguin-rvm-${VERSION_SHORT_SHA1}" +RVM_DIR="/opt/rvm" + +src_install() { + for v in `env | egrep '^rvm_' | cut -d '=' -f 1`; do + unset $v + done + export rvm_prefix="${D}" + export rvm_path="${D}${RVM_DIR}" + export rvm_symlink_path="${D}/usr/bin" + ./install || die "Installation failed." + + echo "rvm_path=${RVM_DIR}" > "${T}"/rvmrc + insinto /etc + doins "${T}"/rvmrc || die "Failed to install /etc/rvmrc." + elog "A default /etc/rvmrc has been installed. Feel free to modify it." + elog + + echo 'unset RUBY_VERSION' > "${T}"/system + echo 'unset GEM_HOME' >> "${T}"/system + echo 'unset GEM_PATH' >> "${T}"/system + echo 'unset MY_RUBY_HOME' >> "${T}"/system + insinto ${RVM_DIR}/config + doins "${T}"/system || die "Failed to install ${RVM_DIR}/config/system." + elog "You may also wish to review ${RVM_DIR}/config/system ." + elog + + elog "Before any user (including root) can use rvm, the following line must be appended" + elog "to the end of the user's shell's loading files (.bashrc and then .bash_profile" + elog "for bash; or .zshrc for zsh), after all path/variable settings:" + elog + elog " if [[ -s $RVM_DIR/scripts/rvm ]] ; then source $RVM_DIR/scripts/rvm ; fi" + +} diff --git a/pkg/gentoo/rvm-99999.ebuild b/pkg/gentoo/rvm-99999.ebuild index b587d7c2ed..815fad4a73 100644 --- a/pkg/gentoo/rvm-99999.ebuild +++ b/pkg/gentoo/rvm-99999.ebuild @@ -2,10 +2,10 @@ # Distributed under the terms of the GNU General Public License v2 # $Header: $ -inherit git - EGIT_REPO_URI="git://github.com/wayneeseguin/rvm.git" +inherit git + DESCRIPTION="RVM facilitates easy installation and management of multiple Ruby environments and sets of gems" HOMEPAGE="http://rvm.beginrescueend.com/" diff --git a/scripts/alias b/scripts/alias new file mode 100755 index 0000000000..a248943470 --- /dev/null +++ b/scripts/alias @@ -0,0 +1,122 @@ +#!/usr/bin/env bash + +unset rvm_default_flag rvm_wrapper_name + +source $rvm_scripts_path/base + +alias_conflicts_with_ruby() { + # If default exists, we should return true. + [[ "$1" == "default" && ! -L "$rvm_rubies_path/default" ]] && return 1 + # Open for suggestions to a better way of doing this... + alias_check_result="$( + . $rvm_scripts_path/initialize + . $rvm_scripts_path/selector + export rvm_ruby_string="$1" + __rvm_ruby_string > /dev/null 2>&1 + echo "$?" + )" + if [[ "0" == "$alias_check_result" ]]; then + $rvm_scripts_path/log "error" "You are attempted to create an alias called '$1', which is recognized as a rvm ruby." + return 0 + fi + return 1 + unset alias_check_result +} + +show_alias() { + if [[ -z "$alias_name" ]]; then + $rvm_scripts_path/log "error" "usage: 'rvm alias show [alias_name]'" + result=1 + return + fi + expanded_alias_name="$($rvm_scripts_path/db "$rvm_config_path/alias" "$alias_name")" + if [[ -z "$expanded_alias_name" ]]; then + $rvm_scripts_path/log "error" "Unknown alias name: '$alias_name'" + result=1 + else + result=0 + echo "$expanded_alias_name" + fi + unset expanded_alias_name +} + +delete_alias() { + echo "Deleting alias: $alias_name" + for link in "$rvm_rubies_path/$alias_name" ; do + if [[ -L "$link" ]] ; then rm -f $link ; fi + done + $rvm_scripts_path/db "$rvm_config_path/alias" "$alias_name" "delete" +} + +create_alias() { + if alias_conflicts_with_ruby "$alias_name"; then + # Force it to an empty alias name to trigger the usage. + alias_name="" + fi + if [[ -z "$rvm_environment_identifier" ]] || [[ -z "$alias_name" ]] ; then + $rvm_scripts_path/log "error" "usage: 'rvm alias [alias_name] [ruby_string]'" + result=1 + else + if [[ -z "$rvm_alias" ]] ; then + rvm_ruby_string="$rvm_environment_identifier" + rvm_expanding_aliases=1 + __rvm_become + unset rvm_expanding_aliases + if [[ -z "$rvm_ruby_string" ]]; then + $rvm_scripts_path/log "error" "unknown ruby string specified" + result=1 + return + fi + final_environment_identifier="$(__rvm_environment_identifier)" + $rvm_scripts_path/log "info" "Creating alias $alias_name for $final_environment_identifier." + ln -nfs "$rvm_rubies_path/$rvm_ruby_string" "$rvm_rubies_path/$alias_name" + $rvm_scripts_path/log "info" "Recording alias $alias_name for $final_environment_identifier." + $rvm_scripts_path/db "$rvm_config_path/alias" "$alias_name" "$final_environment_identifier" + else + if [[ -d "$rvm_rubies_path/$alias_name" ]] ; then + $rvm_scripts_path/log "error" "$rvm_rubies_path/$alias_name is taken and is *not* able to be an alias name." + result=1 + else + $rvm_scripts_path/log "error" "$rvm_rubies_path/$alias_name is already aliased." + result=1 + fi + fi + fi +} + +alias_list() { + for item in $rvm_rubies_path/* ; do + if [[ -L "$item" ]] ; then + echo "$(basename $item) => $($rvm_scripts_path/db "$rvm_config_path/alias" "$(basename "$item")")" + fi + done; unset item +} + +action="$1" +alias_name="$2" +rvm_environment_identifier="$3" +if [[ ! -f "$rvm_config_path/alias" ]] ; then touch "$rvm_config_path/alias" ; fi +if [[ ! -z "$alias_name" ]] ; then + rvm_alias="$($rvm_scripts_path/db "$rvm_config_path/alias" "$alias_name")" +fi + +# CLI API: +# rvm alias create [alias_name] [ruby] +# rvm alias delete [alias_name] +# rvm alias show [alias_name] +# rvm alias list +if [[ "$action" = "delete" ]] ; then + delete_alias +elif [[ "$action" = "create" ]] ; then + create_alias +elif [[ "$action" = "list" ]] ; then + alias_list +elif [[ "$action" = "show" ]]; then + show_alias +else + $rvm_scripts_path/log "error" "usage: 'rvm alias [action] [arguments]" +fi + +unset action alias_name rvm_ruby_string rvm_environment_identifier final_environment_identifier + +exit $result diff --git a/scripts/base b/scripts/base new file mode 100644 index 0000000000..fdd3a85438 --- /dev/null +++ b/scripts/base @@ -0,0 +1,14 @@ +# Base is a collection general files + commonely included +# setup functions. + +# Load the general scripts. +# Use rvm_base_except="" to override the except. +for script_name in initialize utility selector; do + if echo "$rvm_base_except" | grep -vq "$script_name" ; then + source $rvm_scripts_path/$script_name + fi +done; unset script_name rvm_base_except + +# Setup hooks etc. +__rvm_inherit_trace_flag +__rvm_cleanup_temp_on_exit diff --git a/scripts/cd b/scripts/cd index 2490e1b1b5..cd69290624 100644 --- a/scripts/cd +++ b/scripts/cd @@ -2,24 +2,22 @@ # Source a .rvmrc file in a directory after changing to it, if it exists. # To disable this fature, set rvm_project_rvmrc=0 in $HOME/.rvmrc -if [[ "$rvm_project_rvmrc" != 0 ]] ; then - cd() { - builtin cd "$@" - local cwd ; cwd=$(pwd) - while : ; do - if [[ -z "$cwd" ]] || [[ "$HOME" = "$cwd" ]] || [[ "/" = "$cwd" ]] ; then - if [[ "$rvm_project_rvmrc_default" = 1 ]] ; then - rvm default 1>/dev/null 2>&1 - fi - break - else - if [[ -f "$cwd/.rvmrc" ]] ; then - source "$cwd/.rvmrc" - break - else - cwd=$(dirname "$cwd") - fi - fi - done - } +if [[ "$rvm_project_rvmrc" -ne 0 ]] ; then + if [[ -n "$ZSH_VERSION" ]]; then + autoload is-at-least + if is-at-least 4.3.4 >/dev/null 2>&1; then + # On zsh, use chpwd_functions + chpwd_functions=( "${chpwd_functions[@]}" __rvm_project_rvmrc ) + else + cd() { + builtin cd "$@" + __rvm_project_rvmrc + } + fi + else + cd() { + builtin cd "$@" + __rvm_project_rvmrc + } + fi fi diff --git a/scripts/cleanup b/scripts/cleanup new file mode 100755 index 0000000000..dde91042bc --- /dev/null +++ b/scripts/cleanup @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +rvm_base_except="selector" +source "$rvm_scripts_path/base" + +usage() { + printf "Usage: 'rvm cleanup {all,archives,repos,sources,logs}'\n" + printf " Cleans up the directory tree for the specified item.\n" + exit 1 +} + +cleanup() { + for cleanup_type in $1; do + eval "current_path=\"\$rvm_${cleanup_type}_path\"" + if [[ -n "$current_path" && -d "$current_path" && "$current_path" != "/" ]]; then + $rvm_scripts_path/log "info" "Cleaning up rvm directory '$current_path'" + rm -rf "$current_path"/* >/dev/null 2>&1 + fi + done; unset cleanup_type current_path +} + +# Exit when there is no argument. +[[ -z "$1" ]] && usage + +case "$1" in + all) cleanup "archives repo src log" ;; + archives) cleanup "archives" ;; + repos) cleanup "repo" ;; + sources) cleanup "src" ;; + logs) cleanup "log" ;; + *) usage ;; +esac diff --git a/scripts/cli b/scripts/cli index b6e34d9971..961ddeb7ee 100644 --- a/scripts/cli +++ b/scripts/cli @@ -1,35 +1,46 @@ #!/usr/bin/env bash __rvm_usage() { cat "${rvm_path:-$HOME/.rvm}/README" | ${PAGER:-less} ; } +# alternate usage impl: uses man page +#__rvm_usage() { + #if [[ `which man` ]]; then + #man 1 rvm ; } + #else + #cat "${rvm_path:-$HOME/.rvm}/README" | ${PAGER:-less} + #fi +#} __rvm_parse_args() { - if echo "$*" | grep -q 'trace' ; then echo "$*" ; __rvm_version ; fi + + # TODO: + # Make this more robust '__rvm_history' so that it stores *unique* rvm commands. + # Otherwise this file gets big rather fast. + #echo "$@" >> $HOME/.rvm_history + + if echo "$@" | grep -q 'trace' ; then echo "$@" ; __rvm_version ; fi while [[ $# -gt 0 ]] ; do rvm_token="$1" ; shift case "$rvm_token" in - fetch|version|srcdir|reset|debug|reload|implode|seppuku|update|monitor|notes) + fetch|version|srcdir|reset|debug|reload|update|monitor|notes|implode|seppuku|question|answer|env) rvm_action=$rvm_token ;; package) rvm_action="$rvm_token" + if [[ "$1" = "--only-path" ]]; then + shift; rvm_only_path_flag=1 + fi rvm_ruby_args="$@" rvm_parse_break=1 ;; use) rvm_action=$rvm_token - export rvm_verbose_flag=1 + rvm_verbose_flag=1 if [[ "ruby" = "$1" ]] ; then shift ; fi ;; - inspect) - rvm_action=$rvm_token - rvm_ruby_args="$@" - rvm_parse_break=1 - ;; - install|uninstall) export ${rvm_token}_flag=1 rvm_action=$rvm_token @@ -37,13 +48,15 @@ __rvm_parse_args() { rm|remove) rvm_action="remove" - export rvm_remove_flag=1 + rvm_remove_flag=1 ;; # Can likely remove this due to the *) case jruby|ree|macruby|rbx|rubinius|mput|shyouhei|ironruby|default|maglev|all) - export rvm_ruby_interpreter="$rvm_token" - export rvm_ruby_string="$rvm_token" + if [[ "rubinius" = "$rvm_token" ]] ; then rvm_token="rbx"; fi + rvm_ruby_interpreter="$rvm_token" + rvm_ruby_string="$rvm_token" + rvm_ruby_strings="$rvm_token" rvm_action="${rvm_action:-use}" if $rvm_scripts_path/match "$1" "^[0-9]\.[0-9]" ; then rvm_ruby_version=$1 ; shift ; fi ;; @@ -51,113 +64,123 @@ __rvm_parse_args() { gemset) rvm_action=$rvm_token - export rvm_ruby_gem_home="$GEM_HOME" + rvm_ruby_gem_home="$GEM_HOME" if [[ "clear" = "$1" ]] ; then - unset rvm_gemset_name ; shift + __rvm_gemset_clear rvm_ruby_args="clear" elif [[ "use" = "$1" ]] ; then rvm_use_flag=1 rvm_ruby_args="$@" ; shift - export rvm_use_flag rvm_ruby_args - rvm_gemset_name="$1"; shift - if [[ ! -z "$(echo $rvm_gemset_name | grep '%')" ]] ; then - rvm_ruby_string=$(echo $rvm_gemset_name | sed 's/\(.*\)%.*/\1/') - rvm_gemset_name=$(echo $rvm_gemset_name | sed 's/.*%\(.*\)/\1/') + rvm_gemset_name="$1" ; shift + if [[ ! -z "$(echo $rvm_gemset_name | grep $rvm_gemset_separator)" ]] ; then + rvm_ruby_string=$(echo $rvm_gemset_name | sed 's/\(.*\)'${rvm_gemset_separator}'.*/\1/') + rvm_gemset_name=$(echo $rvm_gemset_name | sed 's/.*'${rvm_gemset_separator}'\(.*\)/\1/') if [[ "$rvm_ruby_string" != "$rvm_gemset_name" ]] ; then - export rvm_ruby_string="$rvm_ruby_string%$rvm_gemset_name" - else - unset rvm_ruby_string + rvm_ruby_string="$rvm_ruby_string${rvm_gemset_separator}$rvm_gemset_name" fi - export rvm_ruby_gem_home="$rvm_ruby_gem_home%$rvm_gemset_name" + rvm_ruby_gem_home="$rvm_ruby_gem_home${rvm_gemset_separator}$rvm_gemset_name" fi - if [[ ! -z "$rvm_gemset_name" ]] ; then export rvm_gemset_name ; fi elif [[ "delete" = "$1" ]] ; then rvm_delete_flag=1 rvm_ruby_args="$@" ; shift rvm_gemset_name="$1"; shift - export rvm_delete_flag rvm_ruby_args rvm_gemset_name - if [[ ! -z "$(echo $rvm_gemset_name | grep '%')" ]] ; then - rvm_ruby_string=$(echo $rvm_gemset_name | sed 's/\(.*\)%.*/\1/') - rvm_gemset_name=$(echo $rvm_gemset_name | sed 's/.*%\(.*\)/\1/') + if [[ ! -z "$(echo $rvm_gemset_name | grep $rvm_gemset_separator)" ]] ; then + rvm_ruby_string=$(echo $rvm_gemset_name | sed 's/\(.*\)'${rvm_gemset_separator}'.*/\1/') + rvm_gemset_name=$(echo $rvm_gemset_name | sed 's/.*'${rvm_gemset_separator}'\(.*\)/\1/') if [[ "$rvm_ruby_string" != "$rvm_gemset_name" ]] ; then - export rvm_ruby_string="$rvm_ruby_string%$rvm_gemset_name" - else - unset rvm_ruby_string + rvm_ruby_string="$rvm_ruby_string${rvm_gemset_separator}$rvm_gemset_name" fi - export rvm_ruby_gem_home="$rvm_ruby_gem_home%$rvm_gemset_name" + rvm_ruby_gem_home="$rvm_ruby_gem_home${rvm_gemset_separator}$rvm_gemset_name" fi - if [[ ! -z "$rvm_gemset_name" ]] ; then export rvm_gemset_name ; fi else - if [[ -z "$1" ]] ; then - rvm_action="error" - rvm_error_message="'gemset' must be followed by a gemset action, see http://rvm.beginrescueend.com/gemsets/ for details." - else - if [[ "$rvm_ruby_string" != "$rvm_gemset_name" ]] ; then export rvm_ruby_string ; else unset rvm_ruby_string ; fi - rvm_ruby_args="$@" ; export rvm_ruby_args - fi + if [[ "$rvm_ruby_string" != "$rvm_gemset_name" ]] ; then __rvm_ruby_string ; fi + rvm_ruby_args="$@" fi rvm_parse_break=1 ;; - gemdir) + gemdir|gempath|gemhome) rvm_action=$rvm_token rvm_gemdir_flag=1 - if [[ "system" = "$1" ]] ; then export rvm_system_flag=1 ; shift ; fi - if [[ "user" = "$1" ]] ; then export rvm_user_flag=1 ; shift ; fi + if [[ "system" = "$1" ]] ; then rvm_system_flag=1 ; shift ; fi + if [[ "user" = "$1" ]] ; then rvm_user_flag=1 ; shift ; fi ;; - list|info|strings) + rubygems|inspect|list|info|alias|docs) rvm_action="$rvm_token" - export rvm_ruby_args="$@" + rvm_ruby_args="$@" rvm_parse_break=1 ;; -S) rvm_action="ruby" - export rvm_ruby_args="$rvm_token $@" + rvm_ruby_args="$rvm_token $(__rvm_quote_args "$@")" rvm_parse_break=1 ;; -e) rvm_action="ruby" - export rvm_ruby_args="$rvm_token \"$@\"" + rvm_ruby_args="$rvm_token $(__rvm_quote_args "$@")" + rvm_parse_break=1 + ;; + + exec|cleanup|tools|disk-usage) + rvm_action="$rvm_token" + rvm_ruby_args="$(__rvm_quote_args "$@")" + rvm_parse_break=1 + ;; + + load-rvmrc) + rvm_action="$rvm_token" + rvm_ruby_args="$1" rvm_parse_break=1 ;; + do|ruby|rake|gem|rubydo|rakedo|gemdo) if [[ "do" = "$rvm_action" ]] ; then rvm_action="ruby" ; fi - export rvm_action=$(echo $rvm_token | sed 's#do##g') + rvm_action=$(echo $rvm_token | sed 's#do##g') if [[ "rake" = "$rvm_action" ]] || [[ "gem" = "$rvm_action" ]] || [[ "ruby" = "$rvm_action" ]] ; then if [[ -z "$1" ]] ; then - if [[ "gem" = "$rvm_action" ]] || [[ "ruby" = "$rvm_action" ]] ; then + if [[ "gem" = "$rvm_action" ]] ; then rvm_action="error" - rvm_error_message="the '$rvm_action' actions must be followed by arguments." + rvm_error_message="'rvm $rvm_action' must be followed by arguments." + elif [[ "ruby" = "$rvm_action" ]] ; then + if [[ -z "$(echo "$rvm_ruby_strings" | awk '/,/')" ]] ; then + rvm_action="ruby" + rvm_ruby_args="" + else + rvm_action="error" + rvm_error_message="rvm X,Y,Z '$rvm_action' must be followed by arguments." + fi fi elif [[ "-S" = "$1" ]] ; then - export rvm_action="ruby" - export rvm_ruby_args="$flag $@" + rvm_action="ruby" + rvm_ruby_args="$flag $(__rvm_quote_args "$@")" rvm_parse_break=1 elif [[ "-e" = "$1" ]] ; then - export rvm_action="ruby" - export rvm_ruby_args="$flag '$@'" + rvm_action="ruby" + rvm_ruby_args="$flag $(__rvm_quote_args "$@")" rvm_parse_break=1 else - export rvm_ruby_args="$*" + rvm_ruby_args="$(__rvm_quote_args "$@")" rvm_parse_break=1 fi else if $rvm_scripts_path/match "$1" "^-" ; then - unset rvm_ruby_version + unset rvm_ruby_strings else if $rvm_scripts_path/match "$1" "^[0-9]" ; then - rvm_ruby_version=$(echo "$1" | tr ',' ' ') ; shift + rvm_ruby_strings=$(echo "$1" | tr ',' ' ') ; shift unset rvm_ruby_interpreter else if $rvm_scripts_path/match "ruby rbx jruby macruby ree rubinius maglev mput shyouhei ironruby" "$1" ; then - rvm_ruby_interpreter=$1 ; shift + rvm_ruby_strings=$1 + rvm_ruby_interpreter=$1 + shift else - unset rvm_ruby_interpreter rvm_ruby_version + unset rvm_ruby_interpreter rvm_ruby_strings fi fi fi @@ -188,78 +211,28 @@ __rvm_parse_args() { --ree-options) if [[ ! -z "$1" ]] ; then - rvm_ree_options="$(echo $1 | tr ',' ' ')" ; shift + export rvm_ree_options="$(echo $1 | tr ',' ' ')" ; shift else rvm_action="error" rvm_error_message="--ree-options *must* be followed by... well... options." fi ;; - -t|--tag) - rvm_ruby_tag="$1"; - rvm_action="${rvm_action:-use}" - shift - ;; - - # For use with --patch - --patch-name) export rvm_ruby_patch_name="$1" ; shift ;; - - -h|--patch) - if [[ -z "$rvm_ruby_patch" ]] ; then - export rvm_ruby_patch="$1" - else - export rvm_ruby_patch="$rvm_ruby_patch,$1"; - fi ; shift - rvm_action="${rvm_action:-use}" - ;; - - --head) - if [[ -z "$rvm_ruby_string" ]] ; then export rvm_ruby_string="head"; else export rvm_ruby_string="${rvm_ruby_string}-head" ; fi - rvm_ruby_revision="head" - export rvm_head_flag=1 - rvm_action="${rvm_action:-use}" + --patches|--patch) + rvm_patch_names="$1 $rvm_patch_names"; shift + rvm_patch_original_pwd="$PWD" ;; - --rev|--revision) - rvm_ruby_revision="$1"; - rvm_action="${rvm_action:-use}" - shift - ;; - - -b|--branch) - rvm_ruby_branch="$1"; - rvm_action="${rvm_action:-use}" - shift - ;; + --head) rvm_head_flag=1 ;; --bin) if [[ "update" = "$rvm_action" ]] ; then - export rvm_bin_flag=1 + rvm_bin_flag=1 else rvm_bin_path="$1" ; shift fi ;; - -j) - if [[ ! -z "$1" ]] ; then - rvm_make_flags="$rvm_make_flags -j$1" - shift - else - rvm_action="error" - rvm_error_message="-j *must* be followed by an integer (normally the # of CPU's in your machine)." - fi - ;; - - -C|--configure) - if [[ ! -z "$1" ]] ; then - export rvm_ruby_configure_flags="$(echo $1 | tr ',' ' ')" - shift - else - rvm_action="error" - rvm_error_message="--configure *must* be followed by configure flags." - fi - ;; - -r|--require) if [[ -z "$1" ]] ; then rvm_action="error" @@ -270,14 +243,9 @@ __rvm_parse_args() { fi ;; - -I|--include) - if [[ -z "$1" ]] ; then - rvm_action="error" - rvm_error_message="-I|--include *must* be followed by a path." - else - rvm_ruby_load_path="$rvm_ruby_load_path:$1" - shift - fi + --rdoc|--yard) + rvm_docs_type="$rvm_token" + rvm_docs_type ;; -f|--file) @@ -288,13 +256,45 @@ __rvm_parse_args() { system|default) rvm_action=${rvm_action:-use} - export rvm_ruby_interpreter="$rvm_token" - export rvm_ruby_string="$rvm_token" + rvm_ruby_interpreter="$rvm_token" + rvm_ruby_string="$rvm_token" + rvm_ruby_strings="$rvm_token" ;; + help) + rvm_action="$rvm_token" + rvm_ruby_args="$@" + rvm_parse_break=1 + ;; - -h|--help|usage|help) rvm_action=help ;; - -G|--gems) rvm_gems_path="$1" ; shift ;; + --passenger|--editor) + rvm_wrapper_name="${rvm_token/--/}" + ;; + + --alias) + if [[ -n "$1" ]]; then + export rvm_ruby_aliases="$(echo "$1" | tr ',' ' ')" + shift + fi + ;; + + --symlink) + $rvm_scripts_path/log "warn" "--symlink has been removed, please see 'rvm wrapper'." + shift + ;; + + wrapper) + rvm_action="$rvm_token" + rvm_ruby_string="$1" ; + [[ -n "$1" ]] && shift + rvm_wrapper_name="$1" + [[ -n "$1" ]] && shift + rvm_ruby_args="$@" # list of binaries, or none + rvm_parse_break=1 + ;; + + -h|--help|usage) rvm_action=help ;; + -G) rvm_gems_path="$1" ; shift ;; --source) rvm_src_path="$1" ; shift ;; --archives) rvm_archives_path="$1" ; shift ;; --make) rvm_ruby_make="$1" ; shift ;; @@ -304,60 +304,121 @@ __rvm_parse_args() { # TODO: handle this below better (if $1 is null) --sdk) rvm_sdk="$1" ; shift ;; --archflags) rvm_archflags="$1" ; shift ;; - --symlink) rvm_symlink_name="$1" ; shift ;; - --install) export rvm_install_on_use_flag=1 ;; - --trace) export rvm_trace_flag=1 ; set -x ;; - --proxy) export rvm_proxy="$1" ; shift ;; - --disable-llvm|--disable-jit) export rvm_llvm_flag=0 ;; - --enable-llvm|--enable-jit) export rvm_llvm_flag=1 ;; - - --self|--gem|--rubygems|--reconfigure|--default|--debug|--force|--all|--export|--summary|--latest|--yaml|--json|--archive|--shebang|--env|--path|--tail|--delete|--verbose|--import|--rvmrc|--passenger|--editor|--sticky) + --install) rvm_install_on_use_flag=1 ;; + --trace) rvm_trace_flag=1 ; set -x ;; + --proxy) rvm_proxy="$1" ; shift ;; + --disable-llvm|--disable-jit) rvm_llvm_flag=0 ;; + --enable-llvm|--enable-jit) rvm_llvm_flag=1 ;; + + --name) + rvm_ruby_name="$1" + shift + ;; + + reboot|damnit|wtf|argh|BOOM|boom|wth) $rvm_action="reboot" ;; + + --self|--gem|--rubygems|--reconfigure|--default|--debug|--force|--export|--summary|--latest|--yaml|--json|--archive|--shebang|--env|--path|--tail|--delete|--verbose|--import|--rvmrc|--sticky|--create|--rvmrc|--gems|--docs) export rvm_$(echo $rvm_token | sed 's#-##g')_flag=1 - if [[ "--debug" = "$rvm_token" ]] ; then export rvm_debug_flag ; fi ;; - reboot|flush|asdf|damnit|wtf|argh|work|workdamnit|BOOM|boom|wth) - $rvm_action="reboot" + --clang) + export rvm_clang_flag=1 + export rvm_prior_cc="$CC" + export CC="clang" ;; - --) - rvm_ruby_args="$*" - rvm_parse_break=1 + -j) + if [[ ! -z "$1" ]] ; then + rvm_make_flags="$rvm_make_flags -j$1" + shift + else + rvm_action="error" + rvm_error_message="-j *must* be followed by an integer (normally the # of CPU's in your machine)." + fi + ;; + + -C|--configure) + if [[ ! -z "$1" ]] ; then + rvm_ruby_configure_flags="$(echo $1 | sed -e 's#,--# --#g')" + shift + else + rvm_action="error" + rvm_error_message="--configure *must* be followed by configure flags." + fi + ;; + + --with-*) + rvm_ruby_configure_flags="$rvm_ruby_configure_flags $rvm_token" + ;; + --without-*) + rvm_ruby_configure_flags="$rvm_ruby_configure_flags $rvm_token" + ;; + --enable-*) + rvm_ruby_configure_flags="$rvm_ruby_configure_flags $rvm_token" + ;; + --disable-*) + rvm_ruby_configure_flags="$rvm_ruby_configure_flags $rvm_token" + ;; + + + -I|--include) + if [[ -z "$1" ]] ; then + rvm_action="error" + rvm_error_message="-I|--include *must* be followed by a path." + else + rvm_ruby_load_path="$rvm_ruby_load_path:$1" + shift + fi ;; + --) rvm_ruby_args="$*" ; rvm_parse_break=1 ;; + *) if [[ ! -z "$rvm_token" ]] ; then if [[ "gemset" = "$rvm_action" ]] ; then - if $rvm_scripts_path/match "$rvm_token" "^.+%.+$" ; then - export rvm_gemset_name="$(echo "$rvm_token" | awk -F'%' '{print $2}')" - export rvm_ruby_string="$(echo "$rvm_token" | awk -F'%' '{print $1}')" + if $rvm_scripts_path/match "$rvm_token" "^.+${rvm_gemset_separator}.+$" ; then + rvm_gemset_name="$(echo "$rvm_token" | awk -F${rvm_gemset_separator} '{print $2}')" + rvm_ruby_string="$(echo "$rvm_token" | awk -F${rvm_gemset_separator} '{print $1}')" elif [[ ! -z "$(echo "$rvm_token" | awk '/\.gems$/')" ]] ; then - export rvm_file_name="$(echo "$rvm_token" | sed 's#\.gems##g').gems" + rvm_file_name="$(echo "$rvm_token" | sed 's#\.gems##g').gems" # elif [[ ! -z "$(echo "$rvm_token" | awk '/\.gems$/')" ]] ; then else - export rvm_gemset_name="$(echo "$rvm_token" | sed 's#\.gems##g')" - export rvm_file_name="$rvm_gemset_name.gems" + rvm_gemset_name="$(echo "$rvm_token" | sed 's#\.gems##g')" + rvm_file_name="$rvm_gemset_name.gems" fi elif [[ ! -z "$(echo "$rvm_token" | awk '/,/')" ]] ; then - export rvm_ruby_version="$rvm_token" + rvm_ruby_strings="$rvm_token" if [[ -z "$rvm_action" ]] ; then rvm_action="ruby" # Not sure if we really want to do this but we'll try it out. fi - elif $rvm_scripts_path/match "$rvm_token" "^.+%.+$" ; then - export rvm_gemset_name="$(echo "$rvm_token" | awk -F'%' '{print $2}')" - export rvm_ruby_string="$(echo "$rvm_token" | awk -F'%' '{print $1}')" + elif $rvm_scripts_path/match "$rvm_token" "^${rvm_gemset_separator}" ; then + rvm_action="use" + rvm_gemset_name="$(echo "$rvm_token" | awk -F${rvm_gemset_separator} '{print $2}')" + rvm_ruby_string="$(__rvm_environment_identifier | awk -F${rvm_gemset_separator} '{print $1}')" + rvm_ruby_strings="${rvm_ruby_string}${rvm_gemset_separator}${rvm_gemset_name}" + elif $rvm_scripts_path/match "$rvm_token" "^.+${rvm_gemset_separator}.+$" ; then + rvm_gemset_name="$(echo "$rvm_token" | awk -F${rvm_gemset_separator} '{print $2}')" + rvm_ruby_string="$(echo "$rvm_token" | awk -F${rvm_gemset_separator} '{print $1}')" + rvm_ruby_strings="$rvm_token" elif $rvm_scripts_path/match "$rvm_token" "-" ; then - export rvm_ruby_string="$rvm_token" + rvm_ruby_string="$rvm_token" + rvm_ruby_strings="$rvm_token" elif $rvm_scripts_path/match "$rvm_token" "^[0-9].[0-9]" ; then - export rvm_ruby_string="$rvm_token" - export rvm_action="${rvm_action:-use}" + rvm_ruby_string="$rvm_token" + rvm_ruby_strings="$rvm_token" + rvm_action="${rvm_action:-use}" elif $rvm_scripts_path/match "$rvm_token" "^ree-" ; then - export rvm_ruby_string="$rvm_token" - export rvm_action="${rvm_action:-use}" + rvm_ruby_string="$rvm_token" + rvm_ruby_strings="$rvm_token" + rvm_action="${rvm_action:-use}" + elif [[ -L "$rvm_rubies_path/$rvm_token" ]] ; then # Alias + rvm_ruby_string=$rvm_token + rvm_ruby_strings="$rvm_token" + rvm_action="${rvm_action:-use}" else if $rvm_scripts_path/match "$rvm_token" "\.rb$" ; then # we have a specified ruby script - export rvm_ruby_args=$rvm_token - export rvm_ruby_file=$rvm_token + rvm_ruby_args=$rvm_token + rvm_ruby_file=$rvm_token if [[ -z "$rvm_action" ]] ; then rvm_action="ruby" fi @@ -385,7 +446,9 @@ __rvm_parse_args() { } rvm() { - if [[ ! -z "$PS1" ]] ; then export rvm_interactive=1 ; else unset rvm_interactive ; fi + __rvm_setup + + if [[ -n "$PS1" ]] ; then export rvm_interactive=1 ; else unset rvm_interactive ; fi if [[ -z "$ZSH_VERSION" ]] ; then trap 'rm -rf "$rvm_tmp_path/$$" >/dev/null 2>&1' 0 1 2 3 15 @@ -394,42 +457,100 @@ rvm() { # Check that this is the current version. disk_version=$(cat "${rvm_path:-$HOME/.rvm}/lib/VERSION.yml" | tail -n 3 | sed 's/^.*: //g' | tr "\n" '.' | sed 's/\.$//') if [[ "${rvm_version}" != "${disk_version}" ]] && [[ "reload" != "$1" ]]; then - echo -e "A newer version of rvm has been installed ($disk_version) than is loaded ($rvm_version), please do one of the following:\n * 'rvm reload'\n * open a new shell\n * source your shell init scripts" + printf "\nA RVM version ${disk_version} is installed yet ${rvm_version} is loaded.\n Please do one of the following:\n * 'rvm reload'\n * open a new shell\n * source your shell init scripts" return 1 fi __rvm_cleanup_variables __rvm_load_rvmrc __rvm_initialize - __rvm_load_defaults - __rvm_parse_args $@ + __rvm_parse_args "$@" + + export BUNDLE_PATH GEM_HOME GEM_PATH rvm_ruby_string rvm_action rvm_bin_flag rvm_debug_flag rvm_delete_flag rvm_docs_type rvm_file_name rvm_gemset_name rvm_head_flag rvm_install_on_use_flag rvm_interactive rvm_llvm_flag rvm_make_flags rvm_proxy rvm_remove_flag rvm_ruby_args rvm_ruby_configure_flags rvm_ruby_file rvm_ruby_gem_home rvm_ruby_interpreter rvm_ruby_name rvm_ruby_version rvm_system_flag rvm_trace_flag rvm_use_flag rvm_user_flag rvm_verbose_flag rvm_patch_names rvm_patch_original_pwd rvm_clang_flag + export rvm_path rvm_rubies_path rvm_scripts_path rvm_archives_path rvm_src_path rvm_patches_path rvm_patches_path rvm_patchsets_path rvm_log_path rvm_bin_path rvm_gems_path rvm_config_path rvm_tmp_path rvm_hooks_path rvm_gems_cache_path rvm_gemset_separator result=0 case "$rvm_action" in - use) __rvm_use ; result=$? ;; - srcdir) __rvm_source_dir ; result=$? ;; - list) __rvm_list ; result=$? ;; - strings) __rvm_strings ; result=$? ;; - info) __rvm_info ; result=$? ;; - debug) __rvm_debug ; result=$? ;; - version) __rvm_version ; result=$? ;; - reset) __rvm_reset ; result=$? ;; - update) __rvm_update ; result=$? ;; - reboot) __rvm_reboot ; result=$? ;; - usage|help) __rvm_usage ; result=$? ;; - benchmark) __rvm_benchmark ; result=$? ;; - inspect) __rvm_inspect ; result=$? ;; - implode|seppuku) __rvm_implode ; result=$? ;; - - gemdir) - $rvm_scripts_path/gemsets gemdir + use) __rvm_use ; result=$? ;; + srcdir) __rvm_source_dir ; result=$? ;; + strings) __rvm_strings ; result=$? ;; + version) __rvm_version ; result=$? ;; + reset) __rvm_reset ; result=$? ;; + update) __rvm_update ; result=$? ;; + reboot) __rvm_reboot ; result=$? ;; + usage) __rvm_usage ; result=$? ;; + benchmark) __rvm_benchmark ; result=$? ;; + inspect) __rvm_inspect ; result=$? ;; + implode|seppuku) __rvm_implode ; result=$? ;; + + list) $rvm_scripts_path/list $rvm_ruby_args ; result=$? ;; + # TODO: Make debug run in the current environment. + debug) $rvm_scripts_path/info '' debug ; result=$? ;; + info) + if [[ "$1" == "info" ]]; then shift; fi + if [[ -z "$rvm_ruby_args" ]] ; then + $rvm_scripts_path/info + else + $rvm_scripts_path/info $rvm_ruby_args + fi + result=$? + ;; + docs) $rvm_scripts_path/docs $rvm_ruby_args ; result=$? ;; + alias) $rvm_scripts_path/alias $rvm_ruby_args ; result=$? ;; + help) $rvm_scripts_path/help $rvm_ruby_args ; result=$? ;; + rubygems) $rvm_scripts_path/rubygems $rvm_ruby_args ; result=$? ;; + + answer) __rvm_Answer_to_the_Ultimate_Question_of_Life_the_Universe_and_Everything ; result=42 ;; + question) __rvm_ultimate_question ; result=42 ;; + + env) + $rvm_scripts_path/env "$rvm_ruby_string" + result=$? + ;; + + wrapper) + $rvm_scripts_path/wrapper "$rvm_ruby_string" "$rvm_wrapper_name" $rvm_ruby_args result=$? + unset rvm_wrapper_name ;; - ruby|gem|rake) + gemdir|gemhome|gempath) + $rvm_scripts_path/gemsets $rvm_action + result=$? + ;; + + ruby|gem|rake|exec) + old_rvm_ruby_string=$rvm_ruby_string + unset rvm_ruby_string + export rvm_ruby_strings $rvm_scripts_path/set $rvm_action $rvm_ruby_args result=$? + # Restore the state pre-sets. + [[ -n "$old_rvm_ruby_string" ]] && rvm_ruby_string=$old_rvm_ruby_string + 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" + result=$? + ;; + + + load-rvmrc) + __rvm_project_rvmrc "$rvm_ruby_args" + result=$? + ;; + gemset) #if $rvm_scripts_path/match $rvm_ruby_args use ; then if [[ "$rvm_use_flag" -eq 1 ]] ; then @@ -438,16 +559,18 @@ rvm() { __rvm_gemset_use fi else + export rvm_ruby_strings $rvm_scripts_path/gemsets $rvm_ruby_args + unset rvm_ruby_strings # Clear the gemset. if [[ "$rvm_delete_flag" -eq 1 ]] ; then - gem_prefix="$(echo $GEM_HOME | sed 's/%.*$//')" - if [[ "$GEM_HOME" = "$gem_prefix%$rvm_gemset_name" ]] ; then + gem_prefix="$(echo $GEM_HOME | sed 's/'${rvm_gemset_separator}'.*$//')" + if [[ "$GEM_HOME" = "${gem_prefix}${rvm_gemset_separator}${rvm_gemset_name}" ]] ; then rvm_ruby_gem_home="$gem_prefix" GEM_HOME="$rvm_ruby_gem_home" BUNDLE_PATH="$rvm_ruby_gem_home" - GEM_PATH="$rvm_ruby_gem_home/bin:$rvm_ruby_gem_home%global/bin" + GEM_PATH="$rvm_ruby_gem_home/bin:$rvm_ruby_gem_home${rvm_gemset_separator}global/bin" export rvm_ruby_gem_home GEM_HOME BUNDLE_PATH GEM_PATH fi ; unset gem_prefix fi @@ -456,17 +579,17 @@ rvm() { ;; monitor) - export rvm_ruby_version rvm_ruby_string + export rvm_ruby_strings rvm_ruby_string $rvm_scripts_path/monitor ; result=$? ;; notes) $rvm_scripts_path/notes ; result=$? ;; - reload) unset rvm_loaded_flag ; rvm_reload_flag=1 ;; + reload) unset rvm_loaded_flag ; rvm_reload_flag=1 ;; fetch|install|uninstall|remove) - if [[ ! -z "$rvm_ruby_string" ]] ; then + if [[ -n "$rvm_ruby_strings" ]] && $rvm_scripts_path/match "$rvm_ruby_strings" "," ; then + $rvm_scripts_path/manage "$rvm_action" "$rvm_ruby_strings" + elif [[ -n "$rvm_ruby_string" ]]; then $rvm_scripts_path/manage "$rvm_action" "$rvm_ruby_string" - elif $rvm_scripts_path/match "$rvm_ruby_version" "," ; then - $rvm_scripts_path/manage "$rvm_action" "$rvm_ruby_version" else $rvm_scripts_path/manage "$rvm_action" fi @@ -494,10 +617,16 @@ rvm() { result=1 esac - if [[ ! -z "$rvm_reload_flag" ]] ; then source "$rvm_scripts_path/rvm" ; fi + 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 . + fi if [[ ! -z "$rvm_trace_flag" ]] ; then set +x ; unset rvm_trace_flag ; fi + __rvm_teardown + return $result } diff --git a/scripts/completion b/scripts/completion new file mode 100644 index 0000000000..a0debc3706 --- /dev/null +++ b/scripts/completion @@ -0,0 +1,115 @@ +# bash completion for Ruby Version Manager (RVM) + +__rvm_comp() +{ + local cur="${COMP_WORDS[COMP_CWORD]}" + COMPREPLY=($(compgen -W "$1" -- "$cur")) + return 0 +} + +__rvm_subcommand() +{ + local word subcommand c=1 + + while [ $c -lt $COMP_CWORD ]; do + word="${COMP_WORDS[c]}" + for subcommand in $1; do + if [ "$subcommand" = "$word" ]; then + echo "$subcommand" + return + fi + done + c=$((++c)) + done +} + +__rvm_rubies () +{ + echo "$(rvm list strings) default system" +} + +__rvm_gemsets () +{ + echo "$(rvm gemset list | grep -v gemset 2>/dev/null)" +} + +_rvm_commands () +{ + local cur=${COMP_WORDS[COMP_CWORD]} + + COMMANDS='\ + version use reload implode update reset info debug\ + install uninstall remove\ + ruby gem rake tests specs monitor gemset\ + gemdir srcdir fetch list package notes' + + RVM_OPTS='\ + -v --version\ + -h --help\ + -l --level\ + --tag\ + --rev\ + --prefix\ + --bin\ + --source\ + --archives\ + -S --script\ + -G --gems\ + -C --configure\ + --reconfigure\ + --make\ + --make-install\ + --nice\ + -m --gem-set\ + --rm-gem-set' + + case "${cur}" in + -*) _rvm_opts ;; + *) __rvm_comp "$COMMANDS $(__rvm_rubies)" ;; + esac +} + +_rvm_opts () +{ + local rvm_opts='\ + -v --version\ + -h --help' + + __rvm_comp "$rvm_opts" +} + +_rvm_use () +{ + local command="${COMP_WORDS[COMP_CWORD-2]}" + + case "${command}" in + gemset) __rvm_comp "$(__rvm_gemsets)" ;; + *) __rvm_comp "$(__rvm_rubies)" ;; + esac +} + +_rvm_gemset () +{ + local subcommands="use create" + local subcommand="$(__rvm_subcommand "$subcommands")" + + if [ -z "$subcommand" ]; then + __rvm_comp "$subcommands" + return + fi +} + +_rvm () +{ + local prev=${COMP_WORDS[COMP_CWORD-1]} + + case "${prev}" in + use) _rvm_use ;; + gemset) _rvm_gemset ;; + *) _rvm_commands ;; + esac + + return 0 +} + +complete -o default -o nospace -F _rvm rvm diff --git a/scripts/db b/scripts/db index fef0e5c7b1..247d95e924 100755 --- a/scripts/db +++ b/scripts/db @@ -1,5 +1,12 @@ #!/usr/bin/env bash +usage() { + printf "\nUsage:\n" >&2 + printf "\n $rvm_scripts_path/db database_file {{key}} {{value}} # set" >&2 + printf "\n $rvm_scripts_path/db database_file {{key}} # get" >&2 + printf "\n $rvm_scripts_path/db database_file {{key}} unset # unset\n\n" >&2 +} + if [[ -f "$1" ]] ; then database_file="$1" ; shift if [[ ! -f "$database_file" ]] ; then @@ -7,21 +14,21 @@ if [[ -f "$1" ]] ; then touch $database_file fi else - echo "usage: $0 database key [value]" + printf "\n\nDatabase file $1 does not exist.\n\n" >&2 exit 1 fi key="$1" ; shift if [[ -z "$key" ]] ; then - echo "usage: $0 database key [value]" + usage exit 1 else value="$*" if [[ "unset" = "$value" ]] || [[ "delete" = "$value" ]] ; then - sed -i.tmp "s#^$key=.*\$##" $database_file + sed -i.tmp -e "s#^$key=.*\$##" -e '/^$/d' $database_file else if [[ -z "$value" ]] ; then # get - awk -F= '/^'"$key"'=/{print $2}' $database_file + awk -F= '/^'"$key"'=/' $database_file | sed -e "s#^$key=##" -e '/^$/d' else # set if [[ -z "$(awk -F= "/^'"$key"'=/{print $2}" $database_file)" ]] ; then # append echo "$key=$value" >> $database_file diff --git a/scripts/disk-usage b/scripts/disk-usage new file mode 100755 index 0000000000..94c8289298 --- /dev/null +++ b/scripts/disk-usage @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +#!/usr/bin/env bash +rvm_base_except="selector" +source "$rvm_scripts_path/base" + +usage() { + printf "Usage: 'rvm disk-usage {all,archives,repos,sources,logs,packages}'\n" + printf " Lists the space rvm uses for a given item.\n" + exit 1 +} + +disk_usage_for_directory() { + du -hs "$1" | awk '{print $1}' +} + +disk_usage() { + eval "local current_path=\"\$rvm_${2}_path\"" + if [[ -n "$current_path" && -d "$current_path" && "$current_path" != "/" ]]; then + echo "$1 Usage: $(disk_usage_for_directory "$current_path")" + fi + unset current_path +} + +all_disk_usage() { + archives_disk_usage + repos_disk_usage + sources_disk_usage + logs_disk_usage + packages_disk_usage + total_disk_usage +} + +total_disk_usage() { + echo "Total Disk Usage: $(disk_usage_for_directory "$rvm_path")" +} + +archives_disk_usage() { disk_usage "Downloaded Archives" "archives"; } +repos_disk_usage() { disk_usage "Repositories" "repo"; } +sources_disk_usage() { disk_usage "Extracted Source Code" "src"; } +logs_disk_usage() { disk_usage "Log Files" "log"; } +packages_disk_usage() { disk_usage "Packages" "usr"; } + + +# Exit when there is no argument. +[[ -z "$1" ]] && usage + +case "$1" in + all|archives|repos|sources|logs|total|packages) eval "$1_disk_usage" ;; + *) usage ;; +esac + diff --git a/scripts/docs b/scripts/docs new file mode 100755 index 0000000000..3f6a131b31 --- /dev/null +++ b/scripts/docs @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +rvm_base_except="selector" +source "$rvm_scripts_path/base" + +rvm_docs_ruby_string="$(__rvm_environment_identifier | awk -F"$rvm_gemset_separator" '{print $1}')" +if [[ "$rvm_docs_ruby_string" = "system" || -z "$rvm_docs_ruby_string" ]]; then + $rvm_scripts_path/log "error" "Currently 'rvm docs ...' does not work with non-rvm rubies." + exit 1 +fi + +rvm_docs_type="${rvm_docs_type:-rdoc}" + +# Ensure we have the doc directories. +if [[ ! -d "$rvm_docs_path" ]] ; then + mkdir -p "$rvm_docs_path/rdoc" "$rvm_docs_path/yard" +fi + +usage() { + printf "Usage: 'rvm docs {open,generate,generate-ri,generate-rdoc}'\n" + exit 1 +} + +open_docs() { + if [[ -s "$rvm_docs_path/$rvm_docs_ruby_string/$rvm_docs_type/index.html" ]] ; then + if command -v open >/dev/null ; then + open $rvm_docs_path/$rvm_docs_ruby_string/$rvm_docs_type/index.html + elif command -v xdg-open >/dev/null ; then + xdg-open $rvm_docs_path/$rvm_docs_ruby_string/$rvm_docs_type/index.html + else + $rvm_scripts_path/log "error" "Neither open nor xdg-open were found, in order to open the docs one of these two are required. \n(OR you can let me know how else to open the html in your browser from comand line on your OS :) )" + fi + else + $rvm_scripts_path/log "error" "$rvm_docs_type docs are missing, perhaps run 'rvm docs generate' first?" + fi +} + +generate_ri() { + # Generate ri docs + __rvm_pushpop "$rvm_src_path/$rvm_docs_ruby_string/" + $rvm_scripts_path/log "info" "Generating ri documentation, be aware that this could take a *long* time, and depends heavily on your system resources..." + $rvm_scripts_path/log "info" "( Errors will be logged to $rvm_log_path/$rvm_docs_ruby_string/docs.error.log )" + rdoc -a --ri --ri-site > /dev/null 2>> $rvm_log_path/$rvm_docs_ruby_string/docs.error.log + __rvm_pushpop +} + +generate_rdoc() { + __rvm_pushpop "$rvm_src_path/$rvm_docs_ruby_string/" + rm -rf "$rvm_docs_path/$rvm_docs_ruby_string/$rvm_docs_type/" + $rvm_scripts_path/log "info" "Generating rdoc documentation, be aware that this could take a *long* time, and depends heavily on your system resources..." + $rvm_scripts_path/log "info" "( Errors will be logged to $rvm_log_path/$rvm_docs_ruby_string/docs.error.log )" + if gem list | grep -q ^hanna ; then + hanna -o $rvm_docs_path/$rvm_docs_ruby_string/$rvm_docs_type --inline-source --line-numbers --fmt=html > /dev/null 2>> $rvm_log_path/$rvm_docs_ruby_string/docs.error.log + else + rdoc -a -o $rvm_docs_path/$rvm_docs_ruby_string/$rvm_docs_type > /dev/null 2>> $rvm_log_path/$rvm_docs_ruby_string/docs.error.log + fi + __rvm_pushpop +} + +case "$1" in + open) open_docs ;; + generate) generate_ri; generate_rdoc ;; + generate-ri) generate_ri ;; + generate-rdoc) generate_rdoc ;; + *) usage ;; +esac + +exit $result diff --git a/scripts/env b/scripts/env new file mode 100755 index 0000000000..f1f642a937 --- /dev/null +++ b/scripts/env @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +# Recursive loops, oh my! +unset rvm_default_flag + +source "$rvm_scripts_path/base" + +usage() { + printf "Usage: rvm env [ruby_string] [--path]\n" +} + +environment_name="$1" + +if [[ -z "$environment_name" ]]; then + usage ; exit 1 +fi + +# Exit when we encounter an unknown environment name. +__rvm_become "$environment_name" + +if [[ "$?" = 0 ]]; then + __rvm_use + environment_file_path="$rvm_environments_path/$(__rvm_environment_identifier)" + # Echo the path or environment file. + if [[ -n "$rvm_path_flag" ]]; then + echo "$environment_file_path" + else + cat "$environment_file_path" + fi + unset environment_file_path + result=0 +else + result=1 +fi + +unset rvm_ruby_string environment_name +__rvm_unset_ruby_variables + +exit $result + diff --git a/scripts/fetch b/scripts/fetch index 2e336262d1..e0331277cd 100755 --- a/scripts/fetch +++ b/scripts/fetch @@ -1,14 +1,20 @@ #!/usr/bin/env bash -if [[ ! -z "$rvm_trace_flag" ]] ; then set -x ; export rvm_trace_flag ; fi +rvm_base_except="selector" +source "$rvm_scripts_path/base" -trap "if [[ -d $rvm_tmp_path/ ]] && [[ -f $rvm_tmp_path/$$ ]] ; then rm -f $rvm_tmp_path/$$ > /dev/null 2>&1 ; fi ; exit" 0 1 2 3 15 +# Set it to cleanup the download on interruption. +trap 'cleanup_download' 1 2 3 15 + +cleanup_download() { + [[ -f "$archive" ]] && rm -rf "$archive" +} record_md5() { if [[ "Darwin" = "$(uname)" ]] || [[ "FreeBSD" = "$(uname)" ]]; then - archive_md5="$(/sbin/md5 $archive | awk '{print $NF}')" + archive_md5="$(/sbin/md5 -q "${archive}")" else - archive_md5="$(md5sum $archive | awk '{print $1}')" + archive_md5="$(md5sum "${archive}" | awk '{print $1}')" fi $rvm_scripts_path/db "$rvm_config_path/md5" "$archive" "$archive_md5" } @@ -19,8 +25,8 @@ if [[ -z "$1" ]] ; then $rvm_scripts_path/log "fail" "BUG: $0 called without an url="$1"; download=1 ; package_name="$2" -if ! which curl &> /dev/null; then - $rvm_scripts_path/log "fail" "rvm requires curl, which does not seem to exist in your path :(" +if ! command -v curl > /dev/null ; then + $rvm_scripts_path/log "fail" "rvm requires curl. curl was not found in your active path." exit 1 elif [[ ! -z ${rvm_proxy} ]] ; then fetch_command="curl -x${rvm_proxy} -L --create-dirs -C - " # -s for silent @@ -39,10 +45,10 @@ fi if [[ ! -z "$rvm_debug_flag" ]] ; then $rvm_scripts_path/log "debug" "Fetching $archive" ; fi # Check first if we have the correct archive -archive_md5="$($rvm_scripts_path/db "$rvm_config_path/md5" "$archive")" +archive_md5="$($rvm_scripts_path/db "$rvm_config_path/md5" "$archive" | head -n1)" if [[ -e "$archive" ]] && [[ ! -z "$archive_md5" ]] ; then if [[ ! -z "$rvm_debug_flag" ]] ; then $rvm_scripts_path/log "debug" "Found archive and its md5, testing correctness" ; fi - if [[ $($rvm_scripts_path/md5 $archive $archive_md5) -gt 0 ]] ; then + if ! $rvm_scripts_path/md5 "${rvm_archives_path}/${archive}" "$archive_md5" ; then if [[ ! -z "$rvm_debug_flag" ]] ; then $rvm_scripts_path/log "debug" "Archive is bad, downloading" ; fi download=1 else @@ -88,5 +94,4 @@ if [[ $download -gt 0 ]] ; then record_md5 fi fi - exit $result diff --git a/scripts/gemsets b/scripts/gemsets index c346b53355..a043f2929a 100755 --- a/scripts/gemsets +++ b/scripts/gemsets @@ -1,47 +1,106 @@ #!/usr/bin/env bash -source $rvm_scripts_path/utility -source $rvm_scripts_path/selector +source "$rvm_scripts_path/base" -color_green=$($rvm_scripts_path/color "green") -color_red=$($rvm_scripts_path/color "red") -color_yellow=$($rvm_scripts_path/color "yellow") -color_none=$($rvm_scripts_path/color "none") - -if [[ ! -z "$rvm_trace_flag" ]] ; then set -x ; export rvm_trace_flag ; fi rvm_ruby_gem_home="${rvm_ruby_gem_home:-$GEM_HOME}" -if [[ ! -d "$rvm_ruby_gem_home" ]] && which gem &> /dev/null ; then rvm_ruby_gem_home="$(gem env home)" ; fi +if [[ ! -d "$rvm_ruby_gem_home" ]] && command -v gem > /dev/null 2>&1; then rvm_ruby_gem_home="$(gem env home)" ; fi -trap "if [[ -d $rvm_tmp_path/ ]] && [[ -s $rvm_tmp_path/$$ ]] ; then rm -f $rvm_tmp_path/$$ > /dev/null 2>&1 ; fi ; exit" 0 1 2 3 15 +usage() { + printf "Usage: 'rvm gemset action'\n" + printf " where action is one of: {import,export,create,copy,empty,delete,name,dir,list,gemdir,install,pristine,clear,use,update,globalcache}\n" + printf "\n" + printf " Tools for working with and manipulating gemsets within rvm.\n" + exit 1 +} -__rvm_gemset_name() { - echo "$(gem env gemdir)" | awk -F'%' '{print $2}' +gemset_update() { + if [[ -z "$rvm_ruby_strings" ]]; then + $rvm_scripts_path/log "info" "Running gem update for all rubies and gemsets." + rvm_ruby_strings="$(\ls "$rvm_gems_path" | grep -v '^\(doc\|cache\|@\|system\)' | tr '\n' ',')" + else + $rvm_scripts_path/log "info" "Running gem update for the specified rubies." + fi + export rvm_ruby_strings + $rvm_scripts_path/set "gem" "update" + return $? } -__rvm_gemset_dir() { +gemset_globalcache() { + if [[ "$1" == "enabled" ]]; then + __rvm_using_gemset_globalcache + local globalcache_enabled="$?" + local gc_status="Unknown" + if [[ "$globalcache_enabled" == "0" ]]; then + gc_status="Enabled" + else + gc_status="Disabled" + fi + $rvm_scripts_path/log "info" "Gemset global cache is currently: $gc_status" + return "$globalcache_enabled" + elif [[ "$1" == "disable" ]]; then + $rvm_scripts_path/log "info" "Removing the global cache (note: this will empty the caches)" + for directory_name in $(\ls "$rvm_gems_path"); do + current_cache_path="$rvm_gems_path/$directory_name/cache" + if [[ -L "$current_cache_path" && "$(readlink "$current_cache_path")" == "$rvm_gems_cache_path" ]]; then + $rvm_scripts_path/log "info" "Reverting the gem cache for $directory_name to an empty directory." + rm -f "$current_cache_path" 2>/dev/null + mkdir -p "$current_cache_path" 2>/dev/null + fi + done; unset full_directory_path directory_name + $rvm_scripts_path/db "$rvm_config_path/user" "use_gemset_globalcache" "delete" + elif [[ "$1" == "enable" ]]; then + $rvm_scripts_path/log "info" "Enabling global cache for gems." + mkdir -p "$rvm_gems_cache_path" + for directory_name in $(\ls "$rvm_gems_path"); do + current_cache_path="$rvm_gems_path/$directory_name/cache" + if [[ -d "$current_cache_path" && ! -L "$current_cache_path" ]]; then + $rvm_scripts_path/log "info" "Moving the gem cache for $directory_name to the global cache." + mv "$current_cache_path/"*.gem "$rvm_gems_cache_path/" 2>/dev/null + rm -rf "$current_cache_path" + ln -nfs "$rvm_gems_cache_path" "$current_cache_path" + fi + done; unset full_directory_path directory_name + $rvm_scripts_path/db "$rvm_config_path/user" "use_gemset_globalcache" "true" + else + printf "Usage: 'rvm gemset globalcache {enable,disable}\n" + printf " Enable / Disable the use of a global gem cachedir.\n" + return 1 + fi +} + +gemset_name() { + gemset_dir | awk -F${rvm_gemset_separator} '{print $2}' +} + +gemset_dir() { echo "$rvm_ruby_gem_home" } -__rvm_gemset_create() { - rvm_ruby_gem_prefix=$(echo $rvm_ruby_gem_home | sed 's/%.*$//') +gemset_create() { + rvm_ruby_gem_prefix=$(echo $rvm_ruby_gem_home | sed 's/'${rvm_gemset_separator}'.*$//') for gemset in $(echo $gems_args) ; do - gem_home="$rvm_ruby_gem_prefix%${gems_args/ /}" - mkdir -p $gem_home - ln -nfs "$HOME/.gem/cache" "$gem_home/cache" + gem_home="${rvm_ruby_gem_prefix}${rvm_gemset_separator}${gemset}" + mkdir -p "$gem_home" + # When the globalcache is enabled, we need to ensure we setup the cache directory correctly. + if __rvm_using_gemset_globalcache; then + if [[ -d "$gem_home/cache" && ! -L "$gem_home/cache" ]]; then + mv "$gem_home/cache"/*.gem "$rvm_gems_cache_path/" 2>/dev/null + rm -rf "$gem_home/cache" + fi + ln -nfs "$rvm_gems_cache_path" "$gem_home/cache" + fi $rvm_scripts_path/log "info" "Gemset '$gemset' created." done ; unset gem_home } -__rvm_gemset_list() { +gemset_list() { if [[ -z "$rvm_ruby_selected_flag" ]] ; then __rvm_select ; fi $rvm_scripts_path/log "info" "gemsets : for $rvm_ruby_string (found in $rvm_gems_path/)" if [[ ! -z "$rvm_gems_path" ]] ; then if [[ ! -z $rvm_ruby_string ]] ; then - for gemdir in $rvm_gems_path/${rvm_ruby_string}%* ; do - echo "$gemdir" | awk -F'%' '{print $2}' - done + \ls ${rvm_gems_path}/ | awk -F"${rvm_gemset_separator}" "/${rvm_ruby_string}${rvm_gemset_separator}/{print \$2}" 2>/dev/null else $rvm_scripts_path/log "error" "\$rvm_ruby_string is not set!" fi @@ -50,10 +109,10 @@ __rvm_gemset_list() { fi } -__rvm_gemset_delete() { +gemset_delete() { if [[ -z "$rvm_ruby_selected_flag" ]] ; then __rvm_select ; fi if [[ ! -z "$rvm_gemset_name" ]] ; then - gemdir="$rvm_gems_path/$rvm_ruby_string%$rvm_gemset_name" + gemdir="$rvm_gems_path/$rvm_ruby_string${rvm_gemset_separator}$rvm_gemset_name" if [[ -d "$gemdir" ]] && [[ "$gemdir" != '/' ]] && [[ ! -z "$rvm_force_flag" ]] ; then rm -rf "$gemdir" elif [[ -d "$gemdir" ]] ; then @@ -61,7 +120,8 @@ __rvm_gemset_delete() { echo -n "(anything other than 'yes' will cancel) > " read response if [[ "yes" = "$response" ]] ; then - rm -f $gemdir/cache && rm -rf $gemdir + rm -f $gemdir/cache 2>/dev/null + rm -rf $gemdir else $rvm_scripts_path/log "info" "Not doing anything, phew... close call that one eh?" fi @@ -73,17 +133,17 @@ __rvm_gemset_delete() { fi } -__rvm_gemset_empty() { - if [[ -z "$rvm_ruby_selected_flag" ]] ; then __rvm_select ; fi +gemset_empty() { + if [[ -z "$rvm_ruby_gem_home" ]] ; then __rvm_select ; fi gemdir="$rvm_ruby_gem_home" if [[ -d "$gemdir" ]] && [[ "$gemdir" != '/' ]] && [[ ! -z "$rvm_force_flag" ]] ; then - cd $gemdir && rm -rf ./bin/* ./doc/* ./gems/* ./specifications/* + builtin cd $gemdir && rm -rf ./bin/* ./doc/* ./gems/* ./specifications/* elif [[ -d "$gemdir" ]] ; then - $rvm_scripts_path/log "warn" "Are you SURE you wish to remove the installed gemset for gemset '%$rvm_gemset_name' ($gemdir)?" + $rvm_scripts_path/log "warn" "Are you SURE you wish to remove the installed gemset for gemset '$(basename $gemdir)' ($gemdir)?" echo -n "(anything other than 'yes' will cancel) > " read response if [[ "yes" = "$response" ]] ; then - cd $gemdir && rm -rf ./bin/* ./doc/* ./gems/* ./specifications/* + builtin cd $gemdir && rm -rf ./bin/* ./doc/* ./gems/* ./specifications/* else $rvm_scripts_path/log "info" "Not doing anything, phew... close call that one eh?" fi @@ -93,7 +153,7 @@ __rvm_gemset_empty() { } # Migrate gemsets from ruby X to ruby Y -__rvm_gemset_copy() { +gemset_copy() { source_ruby="$(echo $gems_args | awk '{print $1}')" destination_ruby="$(echo $gems_args | awk '{print $2}')" if [[ -z "$source_ruby" ]] ; then @@ -102,15 +162,17 @@ __rvm_gemset_copy() { if [[ -z "$destination_ruby" ]] ; then $rvm_scripts_path/log "error" "Source and destination must be specified: 'rvm gemset copy X Y'" fi - source_path="$($rvm_bin_path/rvm $source_ruby gem env gemdir | tail -n 1)" - destination_path="$($rvm_bin_path/rvm $destination_ruby gem env gemdir | tail -n 1)" - + source_path="$(rvm $source_ruby gem env gemdir | tail -n 1)" + destination_path="$(rvm $destination_ruby gem env gemdir | tail -n 1)" if [[ -d "$source_path" ]] ; then if [[ ! -d "$destination_path" ]] ; then mkdir -p $destination_path ; fi - $rvm_scripts_path/log "info" "Copying gemset from $source_ruby to $destination_ruby" ; + $rvm_scripts_path/log "info" "Copying gemset from $source_ruby to $destination_ruby" for dir in bin doc gems specifications ; do - cp -Rf $source_path/$dir $destination_path/ + mkdir -p "$destination_path/$dir" + cp -Rf "$source_path/$dir" "$destination_path/" done + $rvm_scripts_path/log "info" "Making gemset for $destination_ruby pristine." + (rvm "$destination_ruby" ; gemset_pristine) else $rvm_scripts_path/log "error" "Gems directory does not exist for $source_path ($source_path)" return 1 @@ -119,12 +181,12 @@ __rvm_gemset_copy() { unset source_ruby destination_ruby source_path destination_path } -__rvm_gemset_export() { +gemset_export() { rvm_file_name="${rvm_file_name:-$gems_args}" if [[ ! -z "$rvm_ruby_gem_home" ]] ; then export GEM_HOME="$rvm_ruby_gem_home" - export GEM_PATH="$rvm_ruby_gem_home/bin:$rvm_gems_path/$rvm_ruby_string%global/bin" + export GEM_PATH="$rvm_ruby_gem_home/bin:$rvm_gems_path/$rvm_ruby_string${rvm_gemset_separator}global/bin" export BUNDLE_PATH="$rvm_ruby_gem_home" fi @@ -153,11 +215,11 @@ __rvm_gemset_export() { done ; unset file_name } -__rvm_gemset_import() { +gemset_import() { if [[ ! -z "$rvm_ruby_gem_home" ]] ; then export GEM_HOME="$rvm_ruby_gem_home" - export GEM_PATH="$rvm_ruby_gem_home/bin:$rvm_gems_path/$rvm_ruby_string%global/bin" + export GEM_PATH="$rvm_ruby_gem_home/bin:$rvm_gems_path/$rvm_ruby_string${rvm_gemset_separator}global/bin" export BUNDLE_PATH="$rvm_ruby_gem_home" fi @@ -180,7 +242,7 @@ __rvm_gemset_import() { return 1 fi - mkdir -p "$rvm_gems_path/cache" # Ensure the base cache dir is initialized. + mkdir -p "$rvm_gems_cache_path" # Ensure the base cache dir is initialized. if [[ -s "$rvm_file_name" ]] ; then echo "Importing $rvm_file_name file..." @@ -189,7 +251,7 @@ __rvm_gemset_import() { while read -r line do # Keep this on 2nd line :( if [[ ! -z "$(echo $line | sed 's/\s//g')" ]] ; then - gems_args="$line" ; __rvm_gem_install + gems_args="$line" ; gem_install fi done < <(awk '/^[^#]+/{print}' "${rvm_file_name}") else @@ -229,21 +291,22 @@ __rvm_parse_gems_args() { } # Install a gem -__rvm_gem_install() { +gem_install() { # First we parse the gem args to pick apart the pieces. + __rvm_parse_gems_args # Now we determine if a .gem cache file is already installed if [[ -z "$rvm_force_flag" ]] && [[ -f "${rvm_ruby_gem_home}/specifications/$(basename $gem_file_name)spec" ]] ; then unset gem - $rvm_scripts_path/log "info" "$color_green$gem_name $gem_version$yellow exists, skipping (--force to re-install)" + $rvm_scripts_path/log "info" "$gem_name $gem_version exists, skipping (--force to re-install)" else if [[ -s "$gem" ]] ; then cache_file="$gem" - elif [[ -s "$rvm_gems_path/cache/${gem_file_name}" ]] ; then - cache_file="$rvm_gems_path/cache/${gem_file_name}" + elif [[ -s "$(__rvm_current_gemcache_dir)/${gem_file_name}" ]] ; then + cache_file="$(__rvm_current_gemcache_dir)/${gem_file_name}" else - cache_file="${cache_file:-$(\ls ${rvm_gems_path}/cache/${gem_file_name} 2> /dev/null | sort | head -n1)}" + cache_file="${cache_file:-$(\ls "$(__rvm_current_gemcache_dir)/${gem_file_name}" 2> /dev/null | sort | head -n1)}" fi if [[ ! -s "$cache_file" ]] ; then @@ -260,11 +323,11 @@ __rvm_gem_install() { if [[ -z "$rvm_force_flag" ]] && [[ -s "${rvm_ruby_gem_home}/specifications/$(basename $gem_file_name)spec" ]] ; then unset gem # already installed, not forcing reinstall. - $rvm_scripts_path/log "info" "$color_green$gem_name $gem_version$yellow exists, skipping (--force to re-install)" + $rvm_scripts_path/log "info" "$gem_name $gem_version exists, skipping (--force to re-install)" else - if [[ -s "$rvm_gems_path/cache/$(basename $gem_file_name)" ]] ; then + if [[ -s "$(__rvm_current_gemcache_dir)/$(basename $gem_file_name)" ]] ; then mkdir -p "$rvm_tmp_path/$$/" - mv "$rvm_gems_path/cache/$gem_file_name" "$rvm_tmp_path/$$/$gem_file_name" + mv "$(__rvm_current_gemcache_dir)/$gem_file_name" "$rvm_tmp_path/$$/$gem_file_name" gem="$rvm_tmp_path/$$/$gem_file_name -f -l" else gem="$cache_file" @@ -279,16 +342,17 @@ __rvm_gem_install() { if [[ "rvm_make_flags_flag" -eq 1 ]] ; then __rvm_make_flags ; fi if [[ ! -z "$rvm_ruby_gem_home" ]] && [[ "$rvm_ruby_gem_home" != "$rvm_gems_path" ]] ; then - command="GEM_HOME='$rvm_ruby_gem_home' GEM_PATH='$rvm_ruby_gem_home/bin:$rvm_gems_path/$rvm_ruby_string%global/bin' BUNDLE_PATH='$rvm_ruby_gem_home' $gem_prefix gem install $gems_args $rvm_gem_options $gem_postfix $vars" + command="GEM_HOME='$rvm_ruby_gem_home' GEM_PATH='$rvm_ruby_gem_home/bin:$rvm_gems_path/${rvm_ruby_string}${rvm_gemset_separator}global/bin' BUNDLE_PATH='${rvm_ruby_gem_home}' ${gem_prefix} gem install $gems_args $rvm_gem_options $gem_postfix $vars" else - command="$gem_prefix gem install $gems_args $rvm_gem_options -q $gem $gem_postfix $vars" + #--ignore-dependencies + command="$gem_prefix gem install --ignore-dependencies $gems_args $rvm_gem_options -q $gem $gem_postfix $vars" fi - __rvm_run "gem.install" "$command" "$gem_name $gem_version is not installed, installing..." + __rvm_run "gem.install" "$command" "installing ${gem_name} ${gem_version}..." result=$? if [[ $result -eq 0 ]] ; then - $rvm_scripts_path/log "info" "$gem_name $gem_version installed." + $rvm_scripts_path/log "info" "$gem_name $gem_version installed, output logged to:\n$rvm_path/log/$rvm_ruby_string/gem.install.log" else - $rvm_scripts_path/log "error" "$gem_name $gem_version failed to install, output has been logged to:\n$rvm_path/log/$rvm_ruby_string/gem.install.error.log" + $rvm_scripts_path/log "error" "$gem_name $gem_version failed to install, output logged to:\n$rvm_path/log/$rvm_ruby_string/gem.install.error.log" fi fi ; unset gem gem_prefix gem_name gem_version gem_file_name gem_postfix cache_file gem_file_name gem_string gem_action @@ -296,58 +360,125 @@ __rvm_gem_install() { } # Output the user's current gem directory. -__rvm_gemset_gemdir() { +gemset_info() { if [[ "$rvm_user_flag" -eq 1 ]] ; then echo $(rvm system ; gem env | grep "\- $HOME" | awk '{print $NF}') elif [[ "$rvm_system_flag" -eq 1 ]] ; then - echo $(rvm system ; gem env gemdir system) + echo $(rvm system ; gem env $action system) elif [[ ! -z "$rvm_ruby_string" ]] ; then - echo $(rvm "$rvm_ruby_string" ; gem env gemdir) + echo $(rvm "$rvm_ruby_string" ; gem env $action) elif [[ ! -z "$GEM_HOME" ]] ; then echo "$GEM_HOME" else - gem env gemdir + gem env $action fi } +gemset_prune() { + temporary_cache_path="$GEM_HOME/temporary-cache" + live_cache_path="$GEM_HOME/cache" + mkdir -p "$temporary_cache_path" + $rvm_scripts_path/log "info" "Moving active gems into temporary cache..." + while read -r used_gem; do + gem_name="$(echo "$used_gem" | sed -e 's/ .*//')" + versions="$(echo "$used_gem" | sed -e 's/.* (//' -e 's/)//' | tr ', ' ' ')" + for version in $versions; do + cached_gem_name="${gem_name}-${version}.gem" + cached_file_path="${live_cache_path}/${cached_gem_name}" + if [[ -f "$cached_file_path" ]]; then + mv "$cached_file_path" "${temporary_cache_path}/${cached_gem_name}" + fi + done + done < <(gem list --versions) + $rvm_scripts_path/log "info" "Removing live cache and restoring temporary cache..." + # Switch the cache back. + rm -rf "$live_cache_path" + mv "$temporary_cache_path" "$live_cache_path" +} + +gemset_pristine() { + gem pristine --all +} + +# Loads the default gemsets for the current interpreter and gemset. +gemset_initial() { + $rvm_scripts_path/log "info" "Importing initial gemsets for $(__rvm_environment_identifier)." + mkdir -p "$rvm_gemsets_path/$(echo "$rvm_ruby_string" | tr '-' '/')" 2>/dev/null + for gemsets_path in $(__rvm_ruby_string_paths_under "$rvm_gemsets_path") ; do + if [[ -n "$rvm_gemset_name" ]] ; then + if [[ -s "${gemsets_path}/${rvm_gemset_name}.gems" ]] ; then + (source "$rvm_scripts_path/rvm"; rvm gemset import "${gemsets_path}/${rvm_gemset_name}.gems") > /dev/null + fi + else + if [[ -d "$gemsets_path" ]] && [[ -s "${gemsets_path}/default.gems" ]] ; then + (source "$rvm_scripts_path/rvm"; rvm gemset import "$gemsets_path/default.gems") > /dev/null + fi + if [[ -d "$gemsets_path" ]] && [[ -s "${gemsets_path}/global.gems" ]] ; then + (source "$rvm_scripts_path/rvm"; rvm use "$rvm_ruby_string@global" --create ; rvm gemset import "${gemsets_path}/global.gems") > /dev/null + fi + fi + done + $rvm_scripts_path/log "info" "Installation of gems for $(__rvm_environment_identifier) is complete." +} + unset GEM_PATH -if [[ -z "$(which gem 2>/dev/null)" ]] ; then +if ! command -v gem > /dev/null ; then $rvm_scripts_path/log "error" "'gem' was not found, cannot perform gem actions (Do you have an RVM ruby selected?)" exit 1 fi action="$(echo $* | awk '{print $1}')" -gems_args=$(echo "$*" | awk '{$1="" ; print}' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') +gems_args="$(echo "$*" | awk '{$1="" ; print}' | __rvm_strip)" export rvm_gemset_name if [[ "import" = "$action" ]] || [[ "load" = "$action" ]] ; then - __rvm_gemset_import + if [[ -z "$rvm_ruby_strings" ]]; then + gemset_import + else + original_env="$(__rvm_environment_identifier)" + for rvm_ruby_string in $(echo "$rvm_ruby_strings" | tr "," " "); do + __rvm_become + gemset_import + done + __rvm_become "$original_env" + unset original_env + fi elif [[ "export" = "$action" ]] || [[ "dump" = "$action" ]] ; then - __rvm_gemset_export + gemset_export elif [[ "create" = "$action" ]] ; then - __rvm_gemset_create + gemset_create elif [[ "copy" = "$action" ]] ; then - __rvm_gemset_copy + gemset_copy elif [[ "empty" = "$action" ]] ; then - __rvm_gemset_empty + gemset_empty elif [[ "delete" = "$action" ]] ; then - __rvm_gemset_delete -elif [[ "name" = "$action" ]] ; then - __rvm_gemset_name + gemset_delete +elif [[ "name" = "$action" ]] || [[ "string" = "$action" ]]; then + gemset_name elif [[ "dir" = "$action" ]] ; then - __rvm_gemset_dir + gemset_dir elif [[ "list" = "$action" ]] ; then - __rvm_gemset_list -elif [[ "gemdir" = "$action" ]] ; then - __rvm_gemset_gemdir + gemset_list +elif [[ "gemdir" = "$action" ]] || [[ "gempath" = "$action" ]] || [[ "gemhome" = "$action" ]] || [[ "home" = "$action" ]] || [[ "path" = "$action" ]] || [[ "version" = "$action" ]] ; then + gemset_info elif [[ "install" = "$action" ]] ; then - __rvm_gem_install $* + gem_install $* +elif [[ "pristine" = "$action" ]] ; then + gemset_pristine $* +elif [[ "initial" = "$action" ]] ; then + gemset_initial +elif [[ "prune" = "$action" ]] ; then + gemset_prune +elif [[ "update" = "$action" ]]; then + gemset_update +elif [[ "globalcache" = "$action" ]]; then + gemset_globalcache "$2" elif [[ "clear" = "$action" ]] ; then $rvm_scripts_path/log "info" "gemset cleared." exit 0 else - $rvm_scripts_path/log "error" "Unrecognized gemset action '$action'.\n\nValid gems actions are: {create,use,import,export,copy,delete,empty,name,list,gemdir,install}" + usage fi exit $? diff --git a/scripts/help b/scripts/help new file mode 100755 index 0000000000..4ab776a45a --- /dev/null +++ b/scripts/help @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +rvm_base_except="selector" +source "$rvm_scripts_path/base" + +rvm_help_path="${rvm_help_path:-"$rvm_path/help"}" + +command="$(echo $* | awk '{print $1}')" +action="$(echo $* | awk '{print $2}')" +# Reserved for future use: +args=$(echo "$*" | awk '{$1=""; $2="" ; print}' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') + +if [[ ! -z "$command" ]] && [[ -s "${rvm_help_path}/${command}" ]] ; then + if [[ ! -z "$action" ]] && [[ -s "${rvm_help_path}/${command}/${action}" ]] ; then + cat "${rvm_help_path}/${command}/${action}" | ${PAGER:-less} + else + cat "${rvm_help_path}/${command}" | ${PAGER:-less} + fi +else + cat "${rvm_path:-$HOME/.rvm}/README" | ${PAGER:-less} + $rvm_scripts_path/log "info" "\nCommands available with 'rvm help':\n\n $(builtin cd "${rvm_help_path}" ; \ls | tr "\n" ' ')" +fi + +$rvm_scripts_path/log "info" "\nFor additional information please visit RVM's documentation website:\n\n http://rvm.beginrescueend.com/" +$rvm_scripts_path/log "info" "\nIf you still cannot find what an answer to your question, find me 'wayneeseguin' in #rvm on irc.freenode.net:\n\n http://webchat.freenode.net/?channels=rvm\n" + +exit $? diff --git a/scripts/hook b/scripts/hook index b0994be98c..0188bae5b1 100755 --- a/scripts/hook +++ b/scripts/hook @@ -1,12 +1,8 @@ #!/usr/bin/env bash -if [[ ! -z "$rvm_trace_flag" ]] ; then set -x ; export rvm_trace_flag ; fi - -trap "if [[ -d $rvm_tmp_path/ ]] && [[ -f $rvm_tmp_path/$$ ]] ; then rm -f $rvm_tmp_path/$$ > /dev/null 2>&1 ; fi ; exit" 0 1 2 3 15 - -if [[ ! -z "$1" ]] ; then - if [[ -s "$rvm_hooks_path/$1" ]] ; then - if [[ "$rvm_verbose_flag" -eq 1 ]] || [[ "$rvm_debug_flag" -eq 1 ]] ; then $rvm_scripts_path/log "info" "running hook $1" ; fi - source "$rvm_hooks_path/$1" +if [[ ! -z "$rvm_hook" ]] ; then + if [[ -s "$rvm_hooks_path/$rvm_hook" ]] ; then + if [[ "$rvm_verbose_flag" -eq 1 ]] || [[ "$rvm_debug_flag" -eq 1 ]] ; then $rvm_scripts_path/log "info" "running hook $rvm_hook" ; fi + source "$rvm_hooks_path/$rvm_hook" fi -fi +fi ; unset rvm_hook diff --git a/scripts/info b/scripts/info new file mode 100755 index 0000000000..c6d50b0461 --- /dev/null +++ b/scripts/info @@ -0,0 +1,140 @@ +#!/usr/bin/env bash + +source "$rvm_scripts_path/base" +source "$rvm_scripts_path/version" + +rvm_ruby_gem_home="${rvm_ruby_gem_home:-$GEM_HOME}" + +if [[ ! -d "$rvm_ruby_gem_home" ]] && command -v gem > /dev/null 2>&1; then rvm_ruby_gem_home="$(gem env home)" ; fi + +info_system() { + rvm_info="$rvm_info\n system:\n uname: \"$(uname -a)\"" + + if [[ ! -z "$ZSH_VERSION" ]] ; then + rvm_info="$rvm_info\n shell: \"zsh\"\n version: \"$ZSH_VERSION\"" + fi + + if [[ ! -z "$BASH_VERSION" ]] ; then + rvm_info="$rvm_info\n shell: \"bash\"\n version: \"$BASH_VERSION\"" + fi + rvm_info="$rvm_info\n" +} + +info_rvm() { + rvm_info="$rvm_info\n rvm:" + rvm_info="$rvm_info\n version: \"$(__rvm_version | tr "\n" ' ' | __rvm_strip)\"" + rvm_info="$rvm_info\n" +} + +info_ruby() { + [[ "$(__rvm_environment_identifier)" == "system" ]] && return + ruby=$(command -v ruby) + if [[ $? -eq 0 ]] && [[ -x "$ruby" ]] ; then full_version="$($ruby -v)" ; fi + rvm_info="$rvm_info\n ruby:" + rvm_info="$rvm_info\n interpreter: \"$(printf "${full_version}" | awk '{print $1}')\"" + rvm_info="$rvm_info\n version: \"$(printf "${full_version}" | awk '{print $2}')\"" + rvm_info="$rvm_info\n date: \"$(printf "${full_version}" | sed 's/^.*(\([0-9]\{4\}\(-[0-9][0-9]\)\{2\}\).*$/\1/')\"" + rvm_info="$rvm_info\n platform: \"$(printf "${full_version}" | sed 's/^.*\[//' | sed 's/\].*$//')\"" + rvm_info="$rvm_info\n patchlevel: \"$(printf "${full_version}" | sed 's/^.*(//' | sed 's/).*$//')\"" + rvm_info="$rvm_info\n full_version: \"${full_version}\"" + rvm_info="$rvm_info\n" +} + +info_homes() { + rvm_info="$rvm_info\n homes:" + rvm_info="$rvm_info\n gem: \"${GEM_HOME:-"not set"}\"" + rvm_info="$rvm_info\n ruby: \"${MY_RUBY_HOME:-"not set"}\"" + rvm_info="$rvm_info\n" +} + +info_binaries() { + rvm_info="$rvm_info\n binaries:" + rvm_info="$rvm_info\n ruby: \"$(command -v ruby)\"" + rvm_info="$rvm_info\n irb: \"$(command -v irb)\"" + rvm_info="$rvm_info\n gem: \"$(command -v gem)\"" + rvm_info="$rvm_info\n rake: \"$(command -v rake)\"" + rvm_info="$rvm_info\n" +} + +info_environment() { + rvm_info="$rvm_info\n environment:" + rvm_info="$rvm_info\n PATH: \"$PATH\"" + rvm_info="$rvm_info\n GEM_HOME: \"$GEM_HOME\"" + rvm_info="$rvm_info\n GEM_PATH: \"$GEM_PATH\"" + rvm_info="$rvm_info\n BUNDLE_PATH: \"$BUNDLE_PATH\"" + rvm_info="$rvm_info\n MY_RUBY_HOME: \"$MY_RUBY_HOME\"" + rvm_info="$rvm_info\n IRBRC: \"$IRBRC\"" + rvm_info="$rvm_info\n RUBYOPT: \"$RUBYOPT\"" + rvm_info="$rvm_info\n gemset: \"$(printf "$GEM_HOME" | awk -F${rvm_gemset_separator:-'@'} '{print $2}')\"\n" + if [[ ! -z "$MAGLEV_HOME" ]] ; then + rvm_info="$rvm_info\n MAGLEV_HOME: \"$MAGLEV_HOME\"" + fi + rvm_info="$rvm_info\n" +} + +info_debug() { + rvm_info=$(__rvm_version) + rvm_info="$rvm_info\n$($rvm_scripts_path/info "$rvm_ruby_string" "" )" + rvm_info="$rvm_info\nPATH:\n$(printf $PATH | awk -F":" '{print $1":"$2":"$3":"$4":"$5}' )" + rvm_info="$rvm_info\nuname -a: $(uname -a)" + rvm_info="$rvm_info\npermissions: $(\ls -la $rvm_path{,/rubies})" + + if [[ "Darwin" = "$(uname)" ]] ; then + rvm_info="$rvm_info\nuname -r: $(uname -r)" + rvm_info="$rvm_info\nuname -m: $(uname -m)" + rvm_info="$rvm_info\nsw_vers: $(sw_vers | tr "\n" ',')" + rvm_info="$rvm_info\nARCHFLAGS: $ARCHFLAGS" + rvm_info="$rvm_info\nLDFLAGS: $LDFLAGS" + rvm_info="$rvm_info\nCFLAGS: $CFLAGS" + rvm_info="$rvm_info\n/Developer/SDKs/*:$(/usr/bin/basename -a /Developer/SDKs/* | tr "\n" ',')" + fi + + for file_name in $(echo $rc_files) ; do + if [[ -s "$file_name" ]] ; then + rvm_info="$rvm_info\n$( "$file_name:\n$(grep 'rvm' $file_name 2>/dev/null)" )" + fi + done + + if [[ "root" = "$(whoami)" ]] ; then + debug_files="$rvm_config_path/alias $rvm_config_path/system $rvm_config_path/db /etc/rvmrc /etc/gemrc" + else + debug_files="$rvm_config_path/alias $rvm_config_path/system $rvm_config_path/db $HOME/.rvmrc $HOME/.gemrc" + fi + + for file_name in $(echo $debug_files); do + if [[ -f "$file_name" ]] && [[ -s "$file_name" ]] ; then + rvm_info="$rvm_info\n$file_name \(filtered\):\n$(cat $file_name | awk '!/assword|_key/')\n" + fi + done + + rvm_info="$rvm_info\ngem sources:\n$(gem sources | awk '/gems/')" +} + +info_sections() { + for section in $(echo $sections | tr ',' ' ') ; do + unset rvm_info ; "info_${section}" ; printf "$rvm_info" + done +} + +args="$*" +ruby_strings="$(echo "$args" | awk '{print $1}')" +sections=$(echo "$args" | awk '{$1="" ; print}' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') +all_sections="system rvm ruby homes binaries environment" + +if $rvm_scripts_path/match "$all_sections debug" "${ruby_strings/,*/}" ; then + sections="$ruby_strings" + ruby_strings="" +fi + +if [[ -z "$sections" ]] ; then sections="$all_sections" ; fi + +if [[ -z "$ruby_strings" ]] ; then + printf "$(__rvm_environment_identifier):\n" + info_sections +else + for ruby_string in $(printf $ruby_strings | tr ',' ' ') ; do + __rvm_become "$ruby_string" + printf "$(__rvm_environment_identifier):\n" + info_sections + done +fi diff --git a/scripts/initialize b/scripts/initialize index d5dfa75ab8..9d2c2b6976 100644 --- a/scripts/initialize +++ b/scripts/initialize @@ -1,35 +1,42 @@ #!/usr/bin/env bash -if [[ "root" = "$(whoami)" ]] ; then +if [[ -n "$rvm_prefix" && "$rvm_prefix" != "$HOME/"* ]] || [[ "root" = "$(whoami)" ]] ; then rvm_rc_files="${rvm_rc_files:-"/etc/profile /etc/zshenv"}" else rvm_rc_files="${rvm_rc_files:-"$HOME/.bash_profile $HOME/.bashrc $HOME/.zshenv"}" fi -if [[ ! -z "$rvm_archflags" ]] ; then rvm_make_flags_flag=1 ; fi +[[ -n "$rvm_archflags" ]] && rvm_make_flags_flag=1 rvm_project_rvmrc="${rvm_project_rvmrc:-1}" rvm_project_rvmrc_default="${rvm_project_rvmrc_default:-0}" -rvm_archives_path="${rvm_archives_path:-"$rvm_path/archives"}" -rvm_src_path="${rvm_src_path:-"$rvm_path/src"}" -rvm_log_path="${rvm_log_path:-"$rvm_path/log"}" -rvm_bin_path="${rvm_bin_path:-"$rvm_path/bin"}" - -if [[ "root" = "$(whoami)" ]] ; then - rvm_gems_path="${rvm_gems_path:-"$rvm_path/gems"}" - rvm_gems_cache_path="${rvm_gems_cache_path:-"$rvm_gems_path/cache"}" +if [[ -n "$rvm_prefix" && "$rvm_prefix" != "$HOME/"* ]] || [[ "root" = "$(whoami)" ]] ; then + rvm_bin_path="${rvm_bin_path:-"/usr/local/bin"}" + rvm_man_path="${rvm_man_path:-"/usr/local/share/man"}" else - rvm_gems_path="${rvm_gems_path:-"$HOME/.rvm/gems"}" - rvm_gems_cache_path="${rvm_gems_cache_path:-"$HOME/.gem/cache"}" + rvm_man_path="${rvm_man_path:-"$rvm_path/man"}" + rvm_bin_path="${rvm_bin_path:-"$rvm_path/bin"}" fi +rvm_archives_path="${rvm_archives_path:-"$rvm_path/archives"}" +rvm_src_path="${rvm_src_path:-"$rvm_path/src"}" +rvm_repo_path="${rvm_repo_path:-"$rvm_path/repos"}" +rvm_log_path="${rvm_log_path:-"$rvm_path/log"}" +rvm_docs_path="${rvm_docs_path:-"$rvm_path/docs"}" +rvm_gems_path="${rvm_gems_path:-"$rvm_path/gems"}" +rvm_gemsets_path="${rvm_gemsets_path:-"$rvm_path/gemsets"}" +rvm_gems_cache_path="${rvm_gems_cache_path:-"$rvm_gems_path/cache"}" rvm_rubies_path="${rvm_rubies_path:-"$rvm_path/rubies"}" rvm_config_path="${rvm_config_path:-"$rvm_path/config"}" +rvm_environments_path="${rvm_environments_path:-"$rvm_path/environments"}" +rvm_wrappers_path="${rvm_wrappers_path:-"$rvm_path/wrappers"}" rvm_hooks_path="${rvm_hooks_path:-"$rvm_path/hooks"}" rvm_tmp_path="${rvm_tmp_path:-"$rvm_path/tmp"}" rvm_usr_path="${rvm_usr_path:-"$rvm_path/usr"}" -rvm_symlink_path="${rvm_symlink_path:-$rvm_prefix/bin}" +rvm_patches_path="${rvm_patches_path:-"$rvm_path/patches"}" +rvm_patchsets_path="${rvm_patchsets_path:-"$rvm_path/patchsets"}" +rvm_gemset_separator="${rvm_gemset_separator:-"@"}" -export rvm_path rvm_rubies_path rvm_scripts_path rvm_archives_path rvm_src_path rvm_log_path rvm_bin_path rvm_gems_path rvm_config_path rvm_tmp_path rvm_hooks_path rvm_gems_cache_path +export rvm_path rvm_patches_path rvm_rubies_path rvm_scripts_path rvm_archives_path rvm_src_path rvm_log_path rvm_bin_path rvm_gems_path rvm_config_path rvm_tmp_path rvm_hooks_path rvm_gems_cache_path rvm_gemset_separator rvm_gemsets_path rvm_repo_path rvm_patchsets_path diff --git a/scripts/install b/scripts/install index 72d0fedf0a..181fc525dd 100755 --- a/scripts/install +++ b/scripts/install @@ -11,11 +11,11 @@ source scripts/version source scripts/utility usage() { - echo -e " + printf " Usage: - ${0} + ${0} [options] - Options: + options: --auto : Automatically update shell profile files. --prefix : Installation prefix directory. --help : Display help/usage (this) message @@ -23,77 +23,124 @@ usage() { " } +check_rubyopt_conditions() { + if [[ -n "$RUBYOPT" ]]; then + printf "\n\nWARNING: You have RUBYOPT set in your current environment. This may interfere with normal rvm" + printf "\n operation. If errors show up, please try unsetting RUBYOPT first.\n" + fi +} + +spinner_counter=0 +spinner() { + array=('/' '-' '\\' '|' '/' '-' '\\' '|') + index=$((($spinner_counter % 8))) + printf "\r${array[$index]}" + let "spinner_counter=spinner_counter+1" + command -v perl > /dev/null 2>&1 && perl -e 'sleep 0.5' +} + if echo "$*" | grep -q 'trace' ; then echo "$*" ; env | grep '^rvm_' ; set -x ; fi while [[ $# -gt 0 ]] ; do token="$1" ; shift case "$token" in - --auto) rvm_auto_flag=1 ;; - --prefix) prefix_path="$1" ; shift ;; + --auto) rvm_auto_flag=1 ;; + --prefix) rvm_prefix="$1" ; shift ;; --version) rvm_path="$(pwd)" ; __rvm_version ; unset rvm_path ; exit ;; - --help|*) usage ;; + --help|*) usage ;; esac done if [[ -z "$rvm_prefix" ]] ; then __rvm_load_rvmrc if [[ "root" = "$(whoami)" ]] ; then - rvm_prefix="/usr/local/" + rvm_prefix="${rvm_prefix:-"/usr/local/"}" else - rvm_prefix="$HOME/." + rvm_prefix="${rvm_prefix:-"$HOME/."}" fi fi if [[ -z "$rvm_path" ]] ; then rvm_path="${rvm_prefix}rvm" ; fi source scripts/initialize + +if grep -q 'scripts/rvm' $HOME/.bash* || grep -q 'scripts/rvm' $HOME/.zsh*; then + if [[ -d "$rvm_path" ]] && [[ -s "${rvm_path}/scripts/rvm" ]] ; then + export upgrade_flag=1 + else + export upgrade_flag=0 + fi +else + export upgrade_flag=0 +fi + __rvm_initialize # -# Setup +# Setup & Configuration # item="$(tput setaf 2)* $(tput sgr0)" question="\n$(tput setaf 2)$(tput sgr0)" cwd=$(pwd) source_path="${source_path:-$cwd}" - -# State what is required to use rvm -echo -e "\nInstalling rvm to $rvm_path/ ..." rvm_archives_path="${rvm_archives_path:-"$rvm_path/archives"}" rvm_src_path="${rvm_src_path:-"$rvm_path/src"}" rvm_log_path="${rvm_log_path:-"$rvm_path/log"}" -rvm_bin_path="${rvm_bin_path:-"$rvm_path/bin"}" + +if [[ -z "$rvm_prefix" ]] && [[ "root" = "$(whoami)" ]] ; then + rvm_bin_path="${rvm_bin_path:-"/usr/local/bin"}" +else + rvm_bin_path="${rvm_bin_path:-"$rvm_path/bin"}" +fi + rvm_gems_path="${rvm_gems_path:-"$rvm_path/gems"}" rvm_rubies_path="${rvm_rubies_path:-"$rvm_path/rubies"}" rvm_scripts_path="${rvm_scripts_path:-"$rvm_path/scripts"}" rvm_config_path="${rvm_config_path:-"$rvm_path/config"}" rvm_hooks_path="${rvm_hooks_path:-"$rvm_path/hooks"}" rvm_tmp_path="${rvm_tmp_path:-"$rvm_path/tmp"}" -rvm_symlink_path="${rvm_symlink_path:-$rvm_prefix/bin}" -mkdir -p $rvm_archives_path $rvm_src_path $rvm_log_path $rvm_bin_path $rvm_gems_path $rvm_rubies_path $rvm_config_path $rvm_hooks_path $rvm_tmp_path $rvm_symlink_path $HOME/.gem/cache +export rvm_gemset_separator="@" # TODO: Remove this after a while. + +printf "\n$(tput setaf 2)RVM:$(tput sgr0) shell scripts which allow management of multiple ruby interpreters and environments." +printf "\n$(tput setaf 2)RTFM: $(tput sgr0) http://rvm.beginrescueend.com/" +printf "\n$(tput setaf 2)HELP: $(tput sgr0) http://webchat.freenode.net/?channels=rvm (#rvm on irc.freenode.net)" + +if [[ "$upgrade_flag" -eq 1 ]] ;then + printf "\n\n Upgrading the RVM installation in $rvm_path/" +else + printf "\n\n Installing rvm to $rvm_path/" +fi + +spinner + +mkdir -p $rvm_archives_path $rvm_src_path $rvm_log_path $rvm_bin_path $rvm_gems_path $rvm_rubies_path $rvm_config_path $rvm_hooks_path $rvm_patches_path $rvm_tmp_path for file in README LICENCE ; do + spinner cp -f "$source_path/$file" "$rvm_path/" done # # Scripts # -for dir_name in config scripts examples lib hooks ; do +for dir_name in config scripts examples lib hooks help patches; do + spinner mkdir -p "$rvm_path/$dir_name" if [[ -d "$source_path/$dir_name" ]] ; then cp -Rf "$source_path/$dir_name" "$rvm_path" fi done ; unset dir_name +spinner if [[ ! -s "$rvm_config_path/user" ]] ; then mkdir -p "$rvm_config_path/" echo '# Users settings file, overrides db file settings and persists across installs.' >> $rvm_config_path/user fi -scripts="monitor match log install color db fetch log set package" -for script_name in $(echo $scripts) ; do +scripts=("monitor" "match" "log" "install" "color" "db" "fetch" "log" "set" "package") +for script_name in "${scripts[@]}" ; do + spinner chmod +x $rvm_scripts_path/$script_name done @@ -101,96 +148,194 @@ done # Bin Scripts # # Cleanse and purge... -for file in rvm-prompt rvm rvmsudo ; do +for file in rvm-prompt rvm rvmsudo rvm-shell ; do + spinner && perl -e 'sleep 0.2' rm -f "$rvm_bin_path/$file" cp -f "$source_path/binscripts/$file" $rvm_bin_path/ done +spinner chmod +x $rvm_bin_path/* # # RC Files # -if [[ ! -z "$rvm_auto_flag" ]] ; then - echo -e "Checking rc files... ($rvm_rc_files)" +spinner +if [[ -n "$rvm_auto_flag" ]] ; then + printf "Checking rc files... ($rvm_rc_files)" if [[ "$rvm_loaded_flag" != "1" ]] ; then for rcfile in $(echo $rvm_rc_files) ; do if [[ ! -f $rcfile ]] ; then touch $rcfile ; fi if [[ -s "$HOME/.profile" ]] ; then if ! grep -q '.profile' "$rcfile" ; then echo " Adding 'if [[ -s \$HOME/.profile ]] ; then source \$HOME ; fi' to $rcfile." - echo -e "\n# rvm-install added line:\nif [[ -s \$HOME/.profile ]] ; then source \$HOME/.profile ; fi\n" >> $rcfile + printf "\n# rvm-install added line:\nif [[ -s \$HOME/.profile ]] ; then source \$HOME/.profile ; fi\n" >> $rcfile fi fi if ! grep -q "scripts\/rvm" "$rcfile" ; then echo " Adding 'if [[ -s $rvm_scripts_path/rvm ]] ; then source $rvm_scripts_path/rvm ; fi' to $rcfile." - echo -e "\n# rvm-install added:\nif [[ -s $rvm_scripts_path/rvm ]] ; then source $rvm_scripts_path/rvm ; fi\n" >> $rcfile + printf "\n# rvm-install added:\nif [[ -s $rvm_scripts_path/rvm ]] ; then source $rvm_scripts_path/rvm ; fi\n" >> $rcfile fi done fi fi +# +# Initial Interpreter Gemsets. +# +spinner +mkdir -p "$rvm_gemsets_path" +for gemset_file in $(cd gemsets ; find . -iname '*.gems' | sed 's/^\.\///') ; do + source_path="$(pwd)/gemsets" + destination="$rvm_gemsets_path/$gemset_file" + destination_path="$(dirname "$destination")" + if [[ ! -s "$destination" ]] ; then + mkdir -p "$destination_path" + cp "$source_path/$gemset_file" "$destination" + fi +done ; unset destination destination_path source_path gemset_file + +spinner +mkdir -p "$rvm_patchsets_path" +for patchsets_file in $(cd gemsets ; find . -iname '*' | sed 's/^\.\///') ; do + source_path="$(pwd)/gemsets" + destination="$rvm_patchsets_path/$patchset_file" + destination_path="$(dirname "$destination")" + if [[ ! -s "$destination" ]] ; then + mkdir -p "$destination_path" + cp "$source_path/$patchset_file" "$destination" + fi +done ; unset destination destination_path source_path patchset_file + + # # Migrate ~/.rvm/ruby-X,jruby-X,... to ~/.rvm/rubies/ for 0.1.0. # rvm_rubies_path="${rvm_rubies_path:-"$rvm_path/rubies"}" mkdir -p "$rvm_rubies_path/" +spinner for ruby in $rvm_path/ruby-* $rvm_path/jruby-* $rvm_path/mput-* $rvm_path/rbx-* $rvm_path/maglev-* $rvm_path/ree-* ; do if [[ -d "$ruby" ]] ; then mv "$ruby" "$rvm_rubies_path/" new_path="$rvm_rubies_path/$(basename $ruby)" for file in gem rake ; do + spinner if [[ -s "$new_path/bin/$file" ]] ; then - sed -i -e '1,1s=.*=#!'"$new_path/bin/ruby=" "$new_path/bin/$file" - rm -f "$new_path/bin/$file.orig" + sed -e '1,1s=.*=#!'"${new_path}/bin/ruby=" "${new_path}/bin/${file}" > "${new_path}/bin/${file}.new" + mv -f "$new_path/bin/$file.new" "$new_path/bin/$file" chmod +x "$new_path/bin/$file" fi done fi done # -# End of migration. +# End of rubies migration. +# + +# +# Migrate old gemset directories to new gemset pattern. # +spinner +printf "\r*" # Stop spinner. + +for gemset in $rvm_path/gems/*\%* ; do + new_path=${gemset/\%/${rvm_gemset_separator}} + if [[ -d "$gemset" ]] && [[ ! -d "$new_path" ]] ; then + printf "\n Renaming $(basename $gemset) to $(basename $new_path) for new gemset separator." + mv $gemset $new_path + fi +done -if [[ "root" = "$(whoami)" ]] ; then - echo -e "\n Symlinking rvm to $rvm_symlink_path/rvm ..." - mkdir -p $rvm_symlink_path - ln -nfs $rvm_bin_path/rvm $rvm_symlink_path/rvm - ln -nfs $rvm_bin_path/rvmsudo $rvm_symlink_path/rvmsudo - chmod +x $rvm_symlink_path/rvm - chmod +x $rvm_symlink_path/rvmsudo +for gemset in $rvm_path/gems/*\+* ; do + new_path=${gemset/\+/${rvm_gemset_separator}} + if [[ -d "$gemset" ]] && [[ ! -d "$new_path" ]] ; then + printf "\n Renaming $(basename $gemset) to $(basename $new_path) for new gemset separator." + mv $gemset $new_path + fi +done +for gemset in $rvm_path/gems/*\@ ; do + new_path=$(echo $gemset | sed -e 's#\@$##') + if [[ -d "$gemset" ]] && [[ ! -d "$new_path" ]] ; then + printf "\n Fixing: $(basename $gemset) to $(basename $new_path) for new gemset separator." + mv $gemset $new_path + fi +done + +# Move from legacy defaults to the new, alias based system. +if [[ -s "$rvm_config_path/default" ]]; then + original_version="$(basename "$(grep GEM_HOME "$rvm_config_path/default" | awk -F"'" '{print $2}' | sed "s#\%#${rvm_gemset_separator}#")")" + if [[ -n "$original_version" ]]; then + $rvm_scripts_path/alias create default "$original_version" &> /dev/null + fi + unset original_version + rm -rf "$rvm_config_path/default" fi -echo -e "\n$(tput setaf 2)rvm$(tput sgr0) - shell scripts that allows a user to manage multiple ruby versions in their own account." -./scripts/notes +# +# End of gemset migration. +# -echo -e "$(tput setaf 2)RTFM: $(tput sgr0) http://rvm.beginrescueend.com/" -echo -e "\n$(tput setaf 2)HELP: $(tput sgr0) http://webchat.freenode.net/?channels=rvm " -echo -e "\n********************************************************************************" -name="$(awk -F= '/^[[:space:]]*name/{print $2}' ~/.gitconfig 2>/dev/null)" -echo -e "\n${name:-"$(whoami)"},\n" -echo -e "\nThank you for using rvm. I hope that it makes your work easier and more enjoyable." -echo -e "If you have any questions, issues and/or ideas for improvement please hop in #rvm on irc.freenode.net and let me know." -echo -e "My irc nickname is 'wayneeseguin' and I hang out from ~09:00-17:00EST and again from ~21:00EST-~00:00EST." -echo -e "If I do not respond right away, please hang around after asking your question, I will respond as soon as I am back." -echo -e "Be sure to get head often as rvm development happens fast, you can do this by typing 'rvm update --head'." -echo -e "\n w$(tput setaf 2)⦿‿⦿$(tput sgr0)t!" -echo -e "\n ~ Wayne" -echo -e "\n********************************************************************************" - -if [[ "root" != "$(whoami)" ]] ; then - echo -e "\n$(tput setaf 1)You must now finish the install manually:$(tput sgr0)" - echo -e "\n1) Place the folowing line at the end of your shell's loading files(.bashrc and then .bash_profile for bash and .zshrc for zsh), after all path/variable settings:" - echo -e "\n if [[ -s $rvm_path/scripts/rvm ]] ; then source $rvm_path/scripts/rvm ; fi" - echo -e "\n2) Ensure that there is no 'return' from inside the .bashrc file. (otherwise rvm will be prevented from working properly)." - echo -e "\n This means that if you see '[ -z "$PS1" ] && return' then you must remove it and split your .bashrc" - echo -e "\n Put everything *except the return code line(s)* into your .bash_profile, and everything above that code in your .bashrc." - echo -e "\n Be *sure* to REMOVE the '&& return' statement line." - echo -e "\n If you wish to DRY up your config you can 'source ~/.bashrc' at the top of your .bash_profile." - echo -e "\n4) Then $(tput setaf 1)CLOSE THIS SHELL$(tput sgr0) and open a new one in order to use rvm.\n" +printf "\n Correct permissions for base binaries in $rvm_bin_path..." +mkdir -p $rvm_bin_path +for file in rvm rvmsudo rvm-shell ; do + [[ -s "$rvm_bin_path/$file" ]] && chmod +x "$rvm_bin_path/$file" +done; unset file +printf "\n Copying manpages into place." +for man_file in $(\ls "$install_source_path/man"); do + rm -rf "$rvm_man_path/$man_file" + cp -R "$install_source_path/man/$man_file" "$rvm_man_path/" +done + +if [[ "$upgrade_flag" -eq 0 ]] ; then + ./scripts/notes fi -if [[ -s $HOME/.bashrc ]] && grep '&& return' $HOME/.bashrc ; then - echo -e "\n\nWARNING: you have a 'return' statement in your .bashrc, likely this will cause untold havoc. Please remove it and refactor your profiles to be correct. If you have questions about this please visit #rvm on irc.freenode.net.\n\n" +name="$(awk -F= '/^[[:space:]]*name/{print $2}' ~/.gitconfig 2>/dev/null)" +printf "\n\n${name:-"$(whoami)"},\n" +printf "\nThank you for using rvm. I hope that it makes your work easier and more enjoyable." +printf "\nIf you have any questions, issues and/or ideas for improvement please hop in #rvm on irc.freenode.net and let me know." +printf "\nMy irc nickname is 'wayneeseguin' and I hang out from ~09:00-17:00EST and again from ~21:00EST-~00:00EST." +printf "\nIf I do not respond right away, please hang around after asking your question, I will respond as soon as I am back." +printf "\nBe sure to get head often as rvm development happens fast, you can do this by typing 'rvm update --head'." +printf "\n w$(tput setaf 2)⦿‿⦿$(tput sgr0)t!" +printf "\n ~ Wayne\n" + +if [[ "$upgrade_flag" -eq 1 ]] ; then + printf "\n$(tput setaf 6)Upgrade Notes\n" + printf "\n * 'rvm notes' tells you OS dependency packages for installing rubies." + printf "\n * If you encounter any issues with a ruby your best bet is to 'rvm remove X ; rvm install X' " + printf "\n * Gemset separator is '@' and will remain unless any rubies error using it." + printf "\n$(tput sgr0)\n" + check_rubyopt_conditions + printf "\nUpgrade of RVM in $rvm_path/ is complete.\n\n" +else + if [[ -z "$rvm_prefix" ]] && [[ "root" != "$(whoami)" ]] ; then + printf "\n$(tput setaf 1)You must now finish the install manually:$(tput sgr0)" + printf "\n1) Place the folowing line at the end of your shell's loading files(.bashrc or .bash_profile for bash and .zshrc for zsh), after all path/variable settings:" + printf "\n [[ -s \$HOME/.rvm/scripts/rvm ]] && source \$HOME/.rvm/scripts/rvm" + printf "\n Please note that this must only occur once - so, you only need to add it the first time you install rvm." + printf "\n2) Ensure that there is no 'return' from inside the .bashrc file. (otherwise rvm will be prevented from working properly)." + printf "\n This means that if you see '[ -z "\$PS1" ] && return' then you must change this line to:" + printf "\n if [[ -n "\$PS1" ]] ; then" + printf "\n ... original content that was below the && return line ..." + printf "\n fi # <= be sure to close the if." + printf "\n #EOF .bashrc" + printf "\n Be absolutely *sure* to REMOVE the '&& return'." + printf "\n If you wish to DRY up your config you can 'source ~/.bashrc' at the bottom of your .bash_profile." + printf "\n placing all non-interactive items in the .bashrc, including the 'source' line above" + printf "\n3) Then $(tput setaf 1)CLOSE THIS SHELL$(tput sgr0) and open a new one in order to use rvm.\n" + fi + if [[ -s $HOME/.bashrc ]] && grep -q '&& return' $HOME/.bashrc ; then + printf "\n\nWARNING: you have a 'return' statement in your .bashrc, likely this will cause untold havoc." + printf "\n This means that if you see '[ -z "\$PS1" ] && return' then you must change this line to:" + printf "\n if [[ -n "\$PS1" ]] ; then" + printf "\n ... original content that was below the && return line ..." + printf "\n fi # <= be sure to close the if." + printf "\n #EOF .bashrc" + printf "\nEven if you use zsh you should still adjust the .bashrc as above." + printf "\nIf you have any questions about this please visit #rvm on irc.freenode.net.\n" + fi + check_rubyopt_conditions + printf "\nInstallation of RVM to $rvm_path/ is complete.\n\n" fi exit 0 diff --git a/scripts/irbrc.rb b/scripts/irbrc.rb index d8167f889a..6b8c8ee948 100644 --- a/scripts/irbrc.rb +++ b/scripts/irbrc.rb @@ -24,10 +24,11 @@ IRB.conf[:PROMPT_MODE] = :RVM # Load the user's irbrc file, if possible. +# Report any errors that occur. begin load File.join(ENV["HOME"], ".irbrc") if File.exists?("#{ENV["HOME"]}/.irbrc") +rescue LoadError => load_error + puts load_error rescue => exception puts "Error : 'load #{ENV["HOME"]}/.irbrc' : #{exception.message}" end - -# EOF diff --git a/scripts/list b/scripts/list new file mode 100755 index 0000000000..3c5dce902b --- /dev/null +++ b/scripts/list @@ -0,0 +1,161 @@ +#!/usr/bin/env bash + +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 + list_gemset_strings + return 0 + fi + echo + + current_ruby="$(__rvm_environment_identifier)" + + 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}')" + 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 + string="[ x86_64 ]" + else + string="[ $(file $rvm_rubies_path/$ruby_version_name/bin/ruby | awk '/x86.64/ {print "x86_64"} /386/ {print "i386"} /ppc/ {print "ppc"}' | tr "\n" ' ')]" + fi + unset ruby_version_name + printf "\n" + if [[ "$version" = "$current_ruby" ]]; then + printf "=> " + else + printf " " + fi + printf "$(tput setaf 2)$version$(tput sgr0) $string" + done ; unset version + + if [[ -f "$rvm_config_path/default" ]] && [[ -s $rvm_config_path/default ]] ; then + version=$(grep 'MY_RUBY_HOME' $rvm_config_path/default | head -n 1 | awk -F"'" '{print $2}' | xargs basename) + if [[ ! -z "$version" ]] ; then + printf "\n\nDefault Ruby (for new shells)\n" + string="[ $(file $rvm_rubies_path/$version/bin/ruby | awk '/x86.64/ {print "x86_64"} /386/ {print "i386"} /ppc/ {print "ppc"}' | tr "\n" ' ')]" + printf "\n $(tput setaf 2)$version$(tput sgr0) $string" + fi ; unset version + fi + printf "\n" + + unset current_ruby version selected system_ruby system_version string binary + echo +} + +list_default() { + strings="$(echo $rvm_ruby_args | awk '{print $2}')" + if [[ "$strings" = "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 + version=$($rvm_scripts_path/alias show default 2>/dev/null | awk -F"$rvm_gemset_separator" '{print $1}' | xargs basename) + if [[ ! -z "$version" ]] ; then + printf "\n\nDefault Ruby (for new shells)\n" + string="[ $(file $rvm_rubies_path/$version/bin/ruby | awk '/x86.64/ {print "x86_64"} /386/ {print "i386"} /ppc/ {print "ppc"}' | tr "\n" ' ')]" + printf "\n $(tput setaf 2)$version$(tput sgr0) $string\n" + fi ; unset version + fi + fi +} + +list_ruby_svn_tags() { + while read -r tag + do + prefix="$(echo ${tag/\//} | sed 's#^v1_##' | awk -F'_' '{print "(ruby-)1."$1"."$2}' | sed 's#p$##')" + echo "${prefix}-t${tag/\//}" + unset prefix tag + done < <(svn list http://svn.ruby-lang.org/repos/ruby/tags/ | awk '/^v1_[8|9]/') +} + +# Query for valid rvm ruby strings +# This is meant to be used with scripting. +list_strings() { + echo $(\ls $rvm_rubies_path) +} + +# 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 +} + +# This is meant to be used with scripting. +list_known_strings() { + cat "$rvm_config_path/known" | sed -e 's/#.*$//g' -e 's/(//g' -e 's/)//g' | sort -r | uniq +} + +list_known() { + if [[ -z "$rvm_interactive" ]] || [[ -z "$TERM" ]] || [[ "unknown" = "$TERM" ]] ; then + cat "$rvm_config_path/known" + else + cat "$rvm_config_path/known" | ${PAGER:-less} + fi +} + + +list_rubies() { + echo + + current_ruby="$(__rvm_environment_identifier | awk -F"$rvm_gemset_separator" '{print $1}')" + + printf "rvm rubies\n" + for version in $(\ls $rvm_rubies_path/ 2> /dev/null | awk '/[a-z]*-.*/ {print $NF}') ; do + if [[ ! -z "$(echo $version | awk '/^jruby-/')" ]] ; then + string="[ $($rvm_rubies_path/$version/bin/ruby -v | awk '{print $NF}' | sed -e 's/\[//' -e 's/\]//') ]" + elif [[ ! -z "$(echo $version | awk '/^maglev-|^macruby-/')" ]] ; then + string="[ x86_64 ]" + else + string="[ $(file $rvm_rubies_path/$version/bin/ruby | awk '/x86.64/ {print "x86_64"} /386/ {print "i386"} /ppc/ {print "ppc"}' | tr "\n" ' ')]" + fi + printf "\n" + if [[ "$version" = "$current_ruby" ]]; then + printf "=> " + else + printf " " + fi + printf "$(tput setaf 2)$version$(tput sgr0) $string" + done ; unset version + + if [[ -f "$rvm_config_path/default" ]] && [[ -s $rvm_config_path/default ]] ; then + version=$(grep 'MY_RUBY_HOME' $rvm_config_path/default | head -n 1 | awk -F"'" '{print $2}' | xargs basename) + if [[ ! -z "$version" ]] ; then + printf "\n\nDefault Ruby (for new shells)\n" + string="[ $(file $rvm_rubies_path/$version/bin/ruby | awk '/x86.64/ {print "x86_64"} /386/ {print "i386"} /ppc/ {print "ppc"}' | tr "\n" ' ')]" + printf "\n $(tput setaf 2)$version$(tput sgr0) $string" + fi ; unset version + fi + printf "\n" + + unset current_ruby version selected system_ruby system_version string binary + echo +} + +# 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}')" + +if [[ "known" = "$action" ]] ; then + list_known +elif [[ "known_strings" = "$action" ]] ; then + list_known_strings +elif [[ "gemsets" = "$action" ]] ; then + list_gemsets +elif [[ "default" = "$action" ]] ; then + list_default +elif [[ -z "$action" ]] || [[ "rubies" = "$action" ]] ; then + list_rubies +elif [[ "strings" = "$action" ]] ; then + list_strings +elif [[ "ruby_svn_tags" = "$action" ]] ; then + list_ruby_svn_tags +else # help + printf "\nUsage: rvm list {known,gemsets,default,rubies,strings,known_strings}" + false +fi + +exit $? diff --git a/scripts/log b/scripts/log index adbceee816..84ad905e11 100755 --- a/scripts/log +++ b/scripts/log @@ -1,28 +1,31 @@ #!/usr/bin/env bash +# When rvm_silence_logging is set, don't show anything. +[[ -n "$rvm_silence_logging" ]] && exit 0 + if [[ "$rvm_trace_flag" -eq 2 ]] ; then set -x ; export rvm_trace_flag ; fi if [[ ! -z "$2" ]] ; then level=$1 ; shift ; else level="info" ; fi -message=$1 +message="$(echo "$1" | sed 's/%/%%/g')" -if [[ -z "$rvm_interactive" ]] ; then +if [[ -z "$rvm_interactive" ]] || [[ -z "$TERM" ]] || [[ "unknown" = "$TERM" ]] ; then case "$level" in - debug) shift ; echo -e "\n$(tput setaf 5)$(tput sgr0) $message $(tput setaf 5) $(tput sgr0) \n" ;; - info) shift ; echo -e "\n$(tput setaf 2)$(tput sgr0) $message $(tput setaf 2) $(tput sgr0) \n" ;; - warn) shift ; echo -e "\n$(tput setaf 3)$(tput sgr0) $message $(tput setaf 3) $(tput sgr0) \n" ;; - error) shift ; echo -e "\n$(tput setaf 1)$(tput sgr0) $message $(tput setaf 1) $(tput sgr0) \n" >&2 ;; - fail) shift ; echo -e "\n$(tput setaf 1)$(tput sgr0) $message $(tput setaf 1) $(tput sgr0) \n" >&2 ;; - *) echo -e "$message" + debug) shift ; printf "\n$level: $message\n" ;; + info) shift ; printf "\n$level: $message\n" ;; + warn) shift ; printf "\n$level: $message\n" ;; + error) shift ; printf "\n$level: $message\n" >&2 ;; + fail) shift ; printf "\n$level: $message\n" >&2 ;; + *) printf "$message" esac else case "$level" in - debug) shift ; echo -e "\n$(tput setaf 5)$message$(tput sgr0)\n" ;; - info) shift ; echo -e "\n$(tput setaf 2)$message$(tput sgr0)\n" ;; - warn) shift ; echo -e "\n$(tput setaf 3)$message$(tput sgr0)\n" ;; - error) shift ; echo -e "\n$(tput setaf 1)$message$(tput sgr0)\n" >&2 ;; - fail) shift ; echo -e "\n$(tput setaf 1)$message$(tput sgr0)\n" >&2 ;; - *) echo -e "$message" + debug) shift ; printf "\n$(tput setaf 5)$level$(tput sgr0): $message\n" ;; + info) shift ; printf "\n$(tput setaf 2)$level$(tput sgr0): $message\n" ;; + warn) shift ; printf "\n$(tput setaf 3)$level$(tput sgr0): $message\n" ;; + error) shift ; printf "\n$(tput setaf 1)$level$(tput sgr0): $message\n" >&2 ;; + fail) shift ; printf "\n$(tput setaf 1)$level$(tput sgr0): $message\n" >&2 ;; + *) printf "$message" esac fi diff --git a/scripts/maglev b/scripts/maglev index 08c6b7646b..149e260fa5 100755 --- a/scripts/maglev +++ b/scripts/maglev @@ -53,7 +53,7 @@ fi # Check that the current directory is writable if [[ ! -w "." ]]; then $rvm_scripts_path/log "error" "This script requires write permission on your current directory." - /bin/ls -ld $PWD + \ls -ld $PWD exit 1 fi diff --git a/scripts/man b/scripts/man new file mode 100644 index 0000000000..e69de29bb2 diff --git a/scripts/manage b/scripts/manage index 3ba733e908..f7eae03459 100755 --- a/scripts/manage +++ b/scripts/manage @@ -3,20 +3,71 @@ original_ruby_version=$rvm_ruby_version original_ruby_string=$rvm_ruby_string -source $rvm_scripts_path/initialize -source $rvm_scripts_path/utility -source $rvm_scripts_path/selector +source "$rvm_scripts_path/base" +source "$rvm_scripts_path/patches" -trap "rm -f $rvm_tmp_path/$$* > /dev/null 2>&1 ; exit" 0 1 2 3 15 +__rvm_check_for_clang() { + if [[ -n "$rvm_clang_flag" ]] && ! command -v clang >/dev/null ; then + $rvm_scripts_path/log "fail" "You passed the --clang option and clang isn't in your path. Please try again / don't use --clang" + return 1 + fi +} + +# Checks for bison, returns zero iff it is found +__rvm_check_for_bison() { + if [[ "$rvm_head_flag" -gt 0 ]]; then + if ! command -v bison >/dev/null ; then + $rvm_scripts_path/log "fail" "bison is not available in your path. Please ensure it exists before compiling from head." + return 1 + fi + fi +} -if [[ ! -z "$rvm_trace_flag" ]] ; then set -x ; export rvm_trace_flag ; fi +# Returns a number of patches, each on a new name +# Expands patchsets etc. +__rvm_current_patch_names() { + # TODO: Lookup default patches on rvm_ruby_string heirarchy. + local patches="$rvm_patch_names default" + for patch_name in $(echo "$patches" | tr ',' ' ' | __rvm_strip); do + __rvm_expand_patch_name "$patch_name" + done +} + +__rvm_apply_patches() { + local patch_result=0 + local patch_level_seperator="%" + local patch_fuzziness="25" + source_directory="${1:-"$rvm_ruby_src_path"}" + __rvm_pushpop "$source_directory" + unset source_directory + for patch_name in $(__rvm_current_patch_names | __rvm_strip); do + patch_level="1" + # If set, extract the patch level from the patch name. + if echo "$patch_name" | grep -q "$patch_level_seperator"; then + patch_level="$(echo "$patch_name" | awk -F"$patch_level_seperator" '{print $2}')" + patch_name="$(echo "$patch_name" | awk -F"$patch_level_seperator" '{print $1}')" + fi + full_patch_path="$(__rvm_lookup_full_patch_path "$patch_name")" + # Expand paths, and for those we found we then apply the patches. + if [[ -n "$full_patch_path" ]]; then + __rvm_run "patch.apply.$(basename "$patch_name")" "patch -F$patch_fuzziness -p$patch_level -f < '$full_patch_path'" "Applying patch '$patch_name' (located at $full_patch_path)" + # Detect failed patches + [[ "$?" -gt 0 ]] && patch_result=1 + else + $rvm_scripts_path/log "warn" "Patch '$patch_name' not found." + patch_result=1 + fi + done; unset patch_name full_patch_path patch_level + __rvm_pushpop + return $patch_result +} __rvm_install_source() { if [[ -z "$rvm_ruby_selected_flag" ]] ; then __rvm_select ; fi $rvm_scripts_path/log "info" "Installing Ruby from source to: $rvm_ruby_home" __rvm_pushpop "$rvm_src_path" - if [[ ! -z "$rvm_force_flag" ]] ; then rm -rf "$rvm_ruby_home" "$rvm_ruby_src_path" ; fi + if [[ -n "$rvm_force_flag" ]] ; then rm -rf "$rvm_ruby_home" "$rvm_ruby_src_path" ; fi result=0 __rvm_fetch_ruby @@ -25,65 +76,56 @@ __rvm_install_source() { fi builtin cd $rvm_ruby_src_path + result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error, source directory is missing. Did the download or extraction fail? Aborting the installation." ; __rvm_pushpop ; return $result fi if [[ -d "${rvm_path}/usr" ]] ; then export PATH="${rvm_path}/usr/bin:${PATH}" ; fi + __rvm_apply_patches + result="$?" + if [[ "$result" -gt 0 ]]; then + $rvm_scripts_path/log "fail" "There has been an error applying the specified patches. Aborting the installation." + return $result + fi + if [[ -z "$rvm_ruby_configure" ]] && [[ ! -s "$rvm_ruby_src_path/configure" ]] ; then - if which autoconf &> /dev/null ; then + if command -v autoconf > /dev/null ; then __rvm_run "autoconf" "autoconf" "Running autoconf" else result=$? ; $rvm_scripts_path/log "fail" "rvm requires autoconf to install the selected ruby interpreter however autoconf was not found in the PATH." ; return $result fi fi - if [[ "1.8.5" = "$rvm_ruby_version" ]] ; then - # How to install ruby 1.8.5... "sneaky sneaky, sir" - src_dir="ruby-1.8.7-p$(__rvm_db "ruby_1.8.7_patch_level")" - if [[ ! -d "$HOME/.rvm/src/$src_dir/ext/openssl/" ]] ; then $rvm_path/bin/rvm fetch 1.8.6-p248 > /dev/null ; fi - cp ~/.rvm/src/$src_dir/ext/openssl/extconf.rb ~/.rvm/src/ruby-1.8.5-p231/ext/openssl/ - cp ~/.rvm/src/$src_dir/ext/openssl/openssl_missing.* ~/.rvm/src/ruby-1.8.5-p231/ext/openssl/ - cp ~/.rvm/src/$src_dir/ext/openssl/ossl_hmac.c ~/.rvm/src/ruby-1.8.5-p231/ext/openssl/ - src_dir="ruby-1.8.6-p$(__rvm_db "ruby_1.8.6_patch_level")" - if [[ ! -d "$HOME/.rvm/src/$src_dir/ext/openssl/" ]] ; then $rvm_path/bin/rvm fetch 1.8.6-p383 > /dev/null ; fi - cp ~/.rvm/src/$src_dir/ext/readline/* ~/.rvm/src/ruby-1.8.5-p231/ext/readline/ - unset src_dir - fi - - if [[ -s ./Makefile ]] && [[ -z "$rvm_reconfigure_flag" ]] ; then - (($rvm_debug_flag)) && $rvm_scripts_path/log "debug" "Skipping configure step, Makefile exists so configure must have already been run." - elif [[ ! -z "$rvm_ruby_configure" ]] ; then + if [[ -n "$rvm_ruby_configure" ]] ; then __rvm_run "configure" "$rvm_ruby_configure" result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while configuring. Aborting the installation." ; __rvm_pushpop ; return $result fi elif [[ -s ./configure ]] ; then - __rvm_run "configure" "./configure --prefix=$rvm_ruby_home $rvm_ruby_configure_flags $configure_parameters" "Configuring $rvm_ruby_string, this may take a while depending on your cpu(s)..." + # REE stores configure flags differently for head vs. the distributed release. + if [[ "ree" != "$rvm_ruby_interpreter" ]]; then + __rvm_db "${rvm_ruby_interpreter}_configure_flags" "db_configure_flags" + fi + + local configure_command="./configure --prefix=$rvm_ruby_home $db_configure_flags $rvm_ruby_configure_flags $configure_parameters" + __rvm_run "configure" "$configure_command" "Configuring $rvm_ruby_string, this may take a while depending on your cpu(s)..." result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while running configure. Aborting the installation." ; __rvm_pushpop ; return $result - fi - unset configure_parameters + fi ; unset configure_parameters db_configure_flags else - $rvm_scripts_path/log "error" "Skipping configure step, 'configure' script does not exist, did autoconf not run successfully?" - fi - - if [[ ! -z "$rvm_ruby_patch" ]] ; then - for patch in $(echo $rvm_ruby_patch | tr ',' ' ') ; do - __rvm_run "patch" "patch -p0 -f < $patch" "Applying patch '$patch'..." - if [[ $? -gt 0 ]] ; then - $rvm_scripts_path/log "error" "Patch $patch did not apply cleanly... back to the patching board :(" ; exit 1 - fi - done + $rvm_scripts_path/log "error" "Skipping configure step, 'configure' does not exist, did autoconf not run successfully?" fi rvm_ruby_make=${rvm_ruby_make:-"make"} - __rvm_run "make" "$rvm_ruby_make $rvm_make_flags" "Compiling $rvm_ruby_string, this may take a while, depending on your cpu(s)..." + __rvm_run "make" "$rvm_ruby_make $rvm_make_flags" "Compiling $rvm_ruby_string, this may take a while depending on your cpu(s)..." result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while running make. Aborting the installation." ; __rvm_pushpop ; return $result fi + if [[ -d .ext/rdoc ]] ; then rm -rf .ext/rdoc ; fi + rvm_ruby_make_install=${rvm_ruby_make_install:-"make install"} __rvm_run "install" "$rvm_ruby_make_install" "Installing $rvm_ruby_string" result=$? ; if [[ "$result" -gt 0 ]] ; then @@ -104,15 +146,21 @@ __rvm_install_source() { } __rvm_install_ruby() { + if [[ -z "$rvm_ruby_selected_flag" ]] ; then __rvm_select ; fi - if [[ ! -z "$RUBYOPT" ]] ; then ruby_options="$RUBYOPT" ; unset RUBYOPT ; fi + if [[ -n "$RUBYOPT" ]] ; then ruby_options="$RUBYOPT" ; unset RUBYOPT ; fi + + # Check for clang if the flag is set + __rvm_check_for_clang + local result="$?" + [[ "$result" -gt 0 ]] && return $result case "$rvm_ruby_interpreter" in macruby) if [[ "Darwin" = "$(uname)" ]] ; then if [[ "$rvm_head_flag" = 1 ]] ; then - if [[ ! -z "$rvm_llvm_flag" ]] ; then + if [[ -n "$rvm_llvm_flag" ]] ; then $rvm_scripts_path/package llvm install fi macruby_path="/usr/local/bin" @@ -127,7 +175,7 @@ __rvm_install_ruby() { $rvm_scripts_path/log "error" "There has been an error while trying to install from source. Aborting the installation." ; return $result fi elif [[ "nightly" = "$rvm_ruby_version" ]] ; then - macruby_path="/usr/local/bin" + macruby_path="/Library/Frameworks/MacRuby.framework/Versions/0.6/usr/bin" # TODO: Separated nightly from head. $rvm_scripts_path/log "info" "Retrieving the latest nightly macruby build..." $rvm_scripts_path/fetch "$rvm_url" @@ -138,40 +186,39 @@ __rvm_install_ruby() { __rvm_run "macruby/extract" "sudo /usr/sbin/installer -pkg '$rvm_archives_path/macruby_nightly.pkg' -target '/'" mkdir -p "$rvm_ruby_home/bin" else - macruby_path="/usr/local/bin" + macruby_path="/Library/Frameworks/MacRuby.framework/Versions/${rvm_ruby_version}/usr/bin" # TODO: Separated nightly from head. - $rvm_scripts_path/log "info" "Retrieving the latest nightly macruby build..." + $rvm_scripts_path/log "info" "Retrieving MacRuby ${rvm_ruby_version} ..." $rvm_scripts_path/fetch "$rvm_url" result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while trying to fetch the source. Aborting the installation." ; __rvm_pushpop ; return $result fi mkdir -p $rvm_ruby_src_path - unzip -o -j "$rvm_archives_path/$rvm_ruby_package_file" "MacRuby 0.5/MacRuby 0.5.pkg" -d "$rvm_ruby_src_path" - mv "$rvm_ruby_src_path/MacRuby 0.5.pkg" "$rvm_ruby_src_path/$rvm_ruby_string.pkg" + unzip -o -j "$rvm_archives_path/$rvm_ruby_package_file" "MacRuby ${rvm_ruby_version}/MacRuby ${rvm_ruby_version}.pkg" -d "$rvm_ruby_src_path" + mv "$rvm_ruby_src_path/MacRuby ${rvm_ruby_version}.pkg" "$rvm_ruby_src_path/$rvm_ruby_string.pkg" __rvm_run "macruby/extract" "sudo /usr/sbin/installer -pkg '$rvm_ruby_src_path/$rvm_ruby_string.pkg' -target '/'" mkdir -p "$rvm_ruby_home/bin" fi - binaries="erb gem irb rake rdoc ri ruby testrb" # Trick to work in more shells :) - for binary_name in $(echo $binaries); do - # if [[ $binary_name != "gem" ]] ; then prefix="-S" ; fi + binaries=(erb gem irb rake rdoc ri ruby testrb) + for binary_name in ${binaries[@]}; do + # TODO: This should be generated via an external script. ruby_wrapper=$(cat < $file_name - if [[ -f $file_name ]] ; then chmod +x $file_name ; fi - done + file_name="$rvm_ruby_home/bin/$binary_name" + rm -f $file_name + echo "$ruby_wrapper" > $file_name + if [[ -f $file_name ]] ; then chmod +x $file_name ; fi if [[ "$binary_name" = "ruby" ]] ; then echo "$ruby_wrapper" > $rvm_bin_path/$rvm_ruby_string fi @@ -184,7 +231,7 @@ RubyWrapper ;; ree) - if [[ ! -z "$(echo $rvm_ruby_version | awk '/^1\.8/')" ]] && [[ -z "$rvm_head_flag" ]] ; then + if [[ -n "$(echo $rvm_ruby_version | awk '/^1\.8/')" ]] && [[ -z "$rvm_head_flag" ]] ; then rvm_url="$(__rvm_db "ree_${rvm_ruby_version}_url")/$rvm_ruby_package_file.tar.gz" $rvm_scripts_path/log "info" "Installing Ruby Enterprise Edition from source to: $rvm_ruby_home" __rvm_pushpop "$rvm_src_path" @@ -209,7 +256,7 @@ RubyWrapper builtin cd "$rvm_ruby_src_path" mkdir -p "${rvm_ruby_home}/lib/ruby/gems/1.8/gems" - if [[ ! -z "$rvm_ruby_configure_flags" ]] ; then + if [[ -n "$rvm_ruby_configure_flags" ]] ; then rvm_ruby_configure_flags="$(echo $rvm_ruby_configure_flags | sed 's#--#-c --#g')" fi @@ -217,29 +264,29 @@ RubyWrapper rvm_ree_options="${rvm_ree_options} --no-tcmalloc" fi - __rvm_run "install" "./installer -a $rvm_rubies_path/$rvm_ruby_interpreter-$rvm_ruby_version-$rvm_ruby_patch_level $rvm_ree_options --dont-install-useful-gems $rvm_ruby_configure_flags" "Installing $rvm_ruby_string, this may take a while, depending on your cpu(s)..." - result=$? ; if [[ "$result" -gt 0 ]] ; then - $rvm_scripts_path/log "error" "There has been an error while trying to run the ree installer. Aborting the installation." ; __rvm_pushpop ; return $result - fi + __rvm_db "${rvm_ruby_interpreter}_configure_flags" "db_configure_flags" - chmod +x $rvm_ruby_home/bin/* + __rvm_apply_patches "$rvm_ruby_src_path/source" + result=$? ; if [[ "$result" -gt 0 ]] ; then + $rvm_scripts_path/log "error" "There has been an error while trying to apply patches to ree. Aborting the installation." ; __rvm_pushpop ; return $result + fi - __rvm_rubygems_setup + __rvm_run "install" "./installer -a $rvm_rubies_path/$rvm_ruby_interpreter-$rvm_ruby_version-$rvm_ruby_patch_level $rvm_ree_options $db_configure_flags $rvm_ruby_configure_flags" "Installing $rvm_ruby_string, this may take a while depending on your cpu(s)..." + result=$? ; if [[ "$result" -gt 0 ]] ; then + $rvm_scripts_path/log "error" "There has been an error while trying to run the ree installer. Aborting the installation." ; __rvm_pushpop ; return $result + fi - for rvm_gem_name in rake ; do - __rvm_run "gems" "$rvm_ruby_home/bin/gem install $rvm_gem_name $rvm_gem_options" "Installing $rvm_gem_name" - done - __rvm_inject_ruby_shebang "$rvm_ruby_gem_home/bin/rake" - __rvm_inject_gem_env "$rvm_ruby_gem_home/bin/rake" + chmod +x $rvm_ruby_home/bin/* + __rvm_rubygems_setup __rvm_irbrc __rvm_bin_script __rvm_post_install __rvm_pushpop else - __rvm_db "ree_${rvm_ruby_version}_repo_url" "rvm_url" + __rvm_db "${rvm_ruby_interpreter}_${rvm_ruby_version}_repo_url" "rvm_url" if [[ -z "$rvm_url" ]] ; then - $rvm_scripts_path/log "fail" "rvm does not know the rvm repo url for 'ree_${rvm_ruby_version}'" + $rvm_scripts_path/log "fail" "rvm does not know the rvm repo url for '${rvm_ruby_interpreter}_${rvm_ruby_version}'" result=1 else rvm_ruby_repo_url=$rvm_url @@ -251,54 +298,53 @@ RubyWrapper rbx|rubinius) $rvm_scripts_path/log "info" "Installing pre-requisites" - # prereqs, 1.8.6+ + rake. Yes this could all be one line... not pushing our luck. - original_string="$rvm_ruby_string" - export rvm_install_on_use_flag=1 ; $rvm_bin_path/rvm 1.8.7 --install # This should install if missing. + + # Ensure we have a 1.8.7 compatible ruby installed. + __rvm_ensure_has_18_compat_ruby || return 1 # TODO: use 'rvm gems load' here: unset CFLAGS LDFLAGS ARCHFLAGS # Important. - __rvm_unset_ruby_variables ; rvm_ruby_string="$original_string" ; __rvm_select - unset original_string unset BUNDLE_PATH GEM_HOME GEM_PATH MY_RUBY_HOME IRBRC PATH=$(echo $PATH | tr ':' '\n' | awk '$0 !~ /rvm/' | paste -sd : -) PATH=$rvm_bin_path:$PATH ; export PATH - if [[ ! -z "$(echo $rvm_ruby_version | awk '/^1\.0/')" ]] && [[ -z "$rvm_head_flag" ]] ; then - if [[ ! -f "$rvm_archives_path/$rvm_ruby_package_file.tar.gz" ]] ; then - $rvm_scripts_path/log "info" "Downloading $rvm_ruby_file, this may take a while depending on your connection..." - $rvm_scripts_path/fetch "$rvm_url" - result=$? ; if [[ "$result" -gt 0 ]] ; then - $rvm_scripts_path/log "error" "There has been an error while trying to fetch the source. Aborting the installation." ; __rvm_pushpop ; return $result - fi + if [[ -n "$(echo $rvm_ruby_version | awk '/^1\.0/')" ]] && [[ -z "$rvm_head_flag" ]] ; then + $rvm_scripts_path/log "info" "Downloading $rvm_ruby_package_file, this may take a while depending on your connection..." + $rvm_scripts_path/fetch "$rvm_url" + result=$? ; if [[ "$result" -gt 0 ]] ; then + $rvm_scripts_path/log "error" "There has been an error while trying to fetch the source. Aborting the installation." ; __rvm_pushpop ; return $result fi - __rvm_run "extract" "cat $rvm_archives_path/$(basename $rvm_url) | gunzip | tar xf - -C $rvm_src_path" "Extracting $rvm_ruby_package_file ..." + __rvm_run "extract" "cat $rvm_archives_path/$(basename $rvm_ruby_package_file) | gunzip | tar xf - -C $rvm_src_path" "Extracting $rvm_ruby_package_file ..." result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while trying to extract the source. Aborting the installation." ; __rvm_pushpop ; return $result fi - mv "$rvm_src_path/rubinius-$rvm_ruby_version-${rvm_ruby_patch_level/^p//}" $rvm_ruby_src_path + + # Remove the left over folder first. + rm -rf "$rvm_ruby_src_path" + mv "$rvm_src_path/rubinius-${rvm_ruby_version}" "$rvm_ruby_src_path" else __rvm_db "rubinius_repo_url" "rvm_ruby_repo_url" #rvm_ruby_home="$rvm_rubies_path/$rvm_ruby_interpreter-$rvm_ruby_version" - if [[ ! -d "$rvm_ruby_src_path" ]] || [[ ! -d "$rvm_ruby_src_path/.git" ]] ; then - rm -rf "$rvm_ruby_src_path" ; builtin cd "$rvm_home" - __rvm_run "rbx.repo" "git clone --depth 1 $rvm_ruby_repo_url $rvm_ruby_src_path" "Cloning $rvm_ruby_repo_url" - builtin cd "$rvm_ruby_src_path" - else - builtin cd "$rvm_ruby_src_path" - __rvm_run "rbx.repo" "git pull origin master" "Pulling from origin master" - fi + __rvm_fetch_from_github "rbx" result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while fetching the rbx git repo. Aborting the installation." ; __rvm_pushpop ; return $result fi fi - #if [[ ! -x "$rvm_ruby_distclean" ]] ; then - # __rvm_run "rake.distclean" "\$(rvm 1.8.7 ; rake distclean --trace)" "Running distclean." - #fi - builtin cd "$rvm_ruby_src_path" ; chmod +x ./configure - rvm_ruby_configure="./configure --prefix=$rvm_ruby_home" ; message="Configuring rbx" + + __rvm_apply_patches + result=$? ; if [[ "$result" -gt 0 ]] ; then + $rvm_scripts_path/log "error" "There has been an error while trying to apply patches to rubinius. Aborting the installation." ; __rvm_pushpop ; return $result + fi + + __rvm_db "${rvm_ruby_interpreter}_configure_flags" "db_configure_flags" + + export ruby="$(__rvm_18_compat_ruby)" + + rvm_ruby_configure_flags="${rvm_ruby_configure_flags:-"--skip-system"}" + rvm_ruby_configure="$rvm_bin_path/$ruby configure --prefix=$rvm_ruby_home $db_configure_flags $rvm_ruby_configure_flags" ; message="Configuring rbx" if [[ "$rvm_llvm_flag" = "0" ]] ; then rvm_ruby_configure="$rvm_ruby_configure --disable-llvm" else @@ -312,43 +358,33 @@ RubyWrapper fi if [[ "$rvm_trace_flag" -eq 1 ]] ; then - rvm_ruby_make="$rvm_bin_path/ruby-1.8.7-p$(__rvm_db "ruby_1.8.7_patch_level") -S rake install --trace" ; message="Compiling rbx (with --trace)" + rvm_ruby_make="$rvm_wrappers_path/$ruby/rake install --trace" ; message="Compiling rbx (with --trace)" else - rvm_ruby_make="$rvm_bin_path/ruby-1.8.7-p$(__rvm_db "ruby_1.8.7_patch_level") -S rake install" ; message="Compiling rbx" + rvm_ruby_make="$rvm_wrappers_path/$ruby/rake install" ; message="Compiling rbx" fi __rvm_run "rake" "$rvm_ruby_make" "$message" result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while running '$rvm_ruby_configure'. Aborting the installation." ; __rvm_pushpop ; return $result fi - binaries="ruby irb" # Trick to work in more shells :) - for binary_name in $(echo $binaries) ; do - ln -fs $rvm_ruby_home/bin/rbx $rvm_ruby_home/bin/$binary_name - done ; unset binary_name binaries + unset ruby - for binary_name in "gem" ; do - if [[ $binary_name != "gem" ]] ; then prefix="-S " ; else unset prefix; fi + # Symlink rubinius wrappers + ln -fs "$rvm_ruby_home/bin/rbx" "$rvm_ruby_home/bin/ruby" - ruby_wrapper=$(cat < "$file_name" + printf "exec '$rvm_ruby_home/bin/rbx' 'irb' \"\$@\"\n" >> "$file_name" + [[ -f "$file_name" ]] && chmod +x "$file_name" -export GEM_HOME="$rvm_ruby_gem_home" -export GEM_PATH="$rvm_ruby_gem_path" -export BUNDLE_PATH="$rvm_ruby_gem_home" -export MY_RUBY_HOME="$rvm_ruby_home" -export PATH="$rvm_ruby_home/bin:$rvm_ruby_gem_home/bin:$rvm_ruby_global_gems_path/bin:\$PATH" - -exec $rvm_ruby_home/bin/rbx $prefix$binary_name "\$@" -RubyWrapper -) - for file_name in "$rvm_ruby_home/bin/$binary_name" "$rvm_bin_path/$binary_name-$rvm_ruby_string" ; do - rm -f $file_name - echo "$ruby_wrapper" > $file_name - if [[ -f $file_name ]] ; then chmod +x $file_name ; fi - done - - unset file_name binaries ruby_wrapper binary_name files prefix - done ; unset binary_name + # Install Gem Wrapper on Rubinius. + file_name="$rvm_ruby_home/bin/gem" + cp -f "$rvm_ruby_home/lib/bin/gem.rb" "$file_name" + __rvm_inject_ruby_shebang "$file_name" + [[ -f "$file_name" ]] && chmod +x "$file_name" + unset file_name binaries="erb ri rdoc" __rvm_post_install @@ -357,8 +393,8 @@ RubyWrapper ;; jruby) - if ! which java &> /dev/null ; then - echo -e "java must be installed and in your path in order to install JRuby." ; return 1 + if ! command -v java > /dev/null; then + printf "java must be installed and in your path in order to install JRuby." ; return 1 fi __rvm_pushpop $rvm_src_path @@ -368,7 +404,7 @@ RubyWrapper fi builtin cd "$rvm_ruby_src_path" - if [[ ! -z "$rvm_head_flag" ]] ; then __rvm_run "ant.dist" "ant dist" "Running 'ant dist' (this could take a few minutes) ..." ; fi + if [[ -n "$rvm_head_flag" ]] ; then __rvm_run "ant.dist" "ant dist" "Running 'ant dist' (this could take a few minutes) ..." ; fi mkdir -p "$rvm_ruby_home/bin/" if $rvm_scripts_path/match "$rvm_ruby_version" "1\.3" || $rvm_scripts_path/match "$rvm_ruby_version" "1\.2" ; then @@ -380,6 +416,7 @@ RubyWrapper __rvm_pushpop if [[ -z "$rvm_ruby_home" ]] || [[ "$rvm_ruby_home" = "/" ]] ; then echo "WTH?!?! rvm_ruby_home == / ??? not removing." ; return 1000000 ; fi + rm -rf $rvm_ruby_home __rvm_run "install" "/bin/cp -Rf $rvm_ruby_src_path $rvm_ruby_home" "Installing JRuby to $rvm_ruby_home" @@ -389,22 +426,31 @@ RubyWrapper done ; unset binary __rvm_pushpop + # -server is "a lot slower for short-lived scripts like rake tasks, and takes longer to load" + #sed -e 's#^JAVA_VM=-client#JAVA_VM=-server#' $rvm_ruby_home/bin/jruby > $rvm_ruby_home/bin/jruby.new && + # mv $rvm_ruby_home/bin/jruby.new $rvm_ruby_home/bin/jruby + chmod +x $rvm_ruby_home/bin/jruby + for binary in jrubyc jirb_swing jirb jgem rdoc ri spec autospec testrb ast generate_yaml_index.rb ; do __rvm_inject_gem_env $rvm_ruby_home/bin/$binary done ; unset binary + __rvm_inject_ruby_shebang "$rvm_ruby_home/bin/rake" # #!/Users/nicksieger/Projects/ruby/jruby-15/dist/jruby-bin-1.5.0/bin/jruby -- lol! + __rvm_rubygems_setup __rvm_irbrc __rvm_bin_script __rvm_use - for rvm_gem_name in jruby-openssl ; do + __rvm_post_install + + for rvm_gem_name in rake jruby-openssl ; do __rvm_run "gems" "$rvm_ruby_home/bin/gem install $rvm_gem_name $rvm_gem_options" "Installing $rvm_gem_name" done ; unset rvm_gem_name ;; maglev) - export rvm_install_on_use_flag=1 ; $rvm_bin_path/rvm 1.8.7 --install # This should install if missing. + __rvm_ensure_has_18_compat_ruby $rvm_scripts_path/log "info" "Running MagLev prereqs checking script." $rvm_scripts_path/maglev @@ -414,7 +460,7 @@ RubyWrapper __rvm_pushpop $rvm_src_path - if [[ ! -d "$rvm_src_path/$rvm_ruby_string" ]] || [[ ! -z "$rvm_force_flag" ]] ; then + if [[ ! -d "$rvm_src_path/$rvm_ruby_string" ]] || [[ -n "$rvm_force_flag" ]] ; then rm -rf "$rvm_src_path/$rvm_ruby_string/" "$rvm_src_path/$rvm_ruby_string/" __rvm_fetch_ruby result=$? ; if [[ "$result" -gt 0 ]] ; then @@ -422,8 +468,8 @@ RubyWrapper fi fi - if [[ ! -z "$rvm_head_flag" ]] ; then - cd $rvm_ruby_src_path + if [[ -n "$rvm_head_flag" ]] ; then + builtin cd $rvm_ruby_src_path rvm_gemstone_package_file="GemStone-$(grep ^GEMSTONE version.txt | cut -f2 -d-).$(uname -sm | tr ' ' '-')" rvm_gemstone_url="${rvm_gemstone_url:-"$maglev_url/${rvm_gemstone_package_file}.${rvm_archive_extension}"}" fi @@ -467,25 +513,28 @@ RubyWrapper done ; unset binary builtin cd "$rvm_ruby_home" - if [[ ! -z "$rvm_head_flag" ]] ; then + if [[ -n "$rvm_head_flag" ]] ; then git submodule update --init $rvm_ruby_home/bin/maglev force-reload ln -sf maglev.demo.key-$(uname -sm | tr ' ' '-') etc/maglev.demo.key fi #ln -fs "$rvm_ruby_home/$(echo $rvm_gemstone_package_file | awk -F'.' '{print $1}')" "$rvm_ruby_home/gemstone" + + compatible_ruby="$(__rvm_18_compat_ruby)" if [[ ! -e ${rvm_ruby_home}/etc/conf.d/maglev.conf ]] ; then $rvm_scripts_path/log "info" "Creating default 'maglev' repository." - $rvm_bin_path/rvm 1.8.7 rake "stone:create[maglev]" >/dev/null 2>&1 + $rvm_wrappers_path/$compatible_ruby/rake "stone:create[maglev]" >/dev/null 2>&1 fi $rvm_scripts_path/log "info" "Generating maglev HTML documentation" - $rvm_bin_path/rvm 1.8.7 rake rdoc >/dev/null 2>&1 + $rvm_wrappers_path/$compatible_ruby/rake rdoc >/dev/null 2>&1 $rvm_scripts_path/log "info" "Generating smalltalk FFI." - $rvm_bin_path/rvm 1.8.7 rake stwrappers >/dev/null 2>&1 + $rvm_wrappers_path/$compatible_ruby/rake stwrappers >/dev/null 2>&1 + unset compatible_ruby # TODO: Figure out if anything needs to be done with rubygems. #__rvm_rubygems_setup @@ -495,8 +544,8 @@ RubyWrapper ;; ironruby|ir) - if ! which mono &> /dev/null ; then - echo -e "mono must be installed and in your path in order to install IronRuby." ; return 1 + if ! command -v mono > /dev/null ; then + printf "mono must be installed and in your path in order to install IronRuby." ; return 1 fi if [[ "$rvm_head_flag" = 1 ]] ; then @@ -505,84 +554,73 @@ RubyWrapper mono_major_ver="$(echo $mono_version | cut -d '.' -f1)" mono_minor_ver="$(echo $mono_version | cut -d '.' -f2)" if [[ $mono_major_ver -lt 2 ]] || ( [[ $mono_major_ver -eq 2 ]] && [[ $mono_minor_ver -lt 6 ]] ) ; then - echo -e "Mono 2.6 (or greater) must be installed and in your path in order to build IronRuby from the repository." - echo -e "Version detected: ${mono_version}" + printf "Mono 2.6 (or greater) must be installed and in your path in order to build IronRuby from the repository." + printf "Version detected: ${mono_version}" return 1 fi else - echo -e "Cannot recognize mono version." + printf "Cannot recognize mono version." return 1 fi + __rvm_ensure_has_18_compat_ruby + __rvm_fetch_ruby if [[ $? -gt 0 ]] ; then result=$? ; return $result ; fi + builtin cd $rvm_ruby_src_path + + compatible_ruby="$(__rvm_18_compat_ruby)" + + $rvm_wrappers_path/$compatible_ruby/gem install pathname2 --no-rdoc --no-ri + + # MONO_LIB=/Library/Frameworks/Mono.framework/Versions/current/lib/ + rvm_ruby_make="$rvm_wrappers_path/$compatible_ruby/rake MERLIN_ROOT=\"$rvm_ruby_src_path/Merlin/Main\" compile mono=1 configuration=release --trace" + __rvm_run "rake" "$rvm_ruby_make" "Building IronRuby..." + unset compatible_ruby + if [[ $? -gt 0 ]] ; then result=$? ; return $result ; fi + + rm -rf $rvm_ruby_home/* + mkdir -p $rvm_ruby_home/bin $rvm_ruby_home/lib $rvm_ruby_home/lib/ruby $rvm_ruby_home/lib/IronRuby + + cp -r $rvm_ruby_src_path/Merlin/Main/Bin/mono_release/* $rvm_ruby_home/bin/ + cp -r $rvm_ruby_src_path/Merlin/Main/Languages/Ruby/Scripts/bin/* $rvm_ruby_home/bin/ + cp -r $rvm_ruby_src_path/Merlin/External.LCA_RESTRICTED/Languages/Ruby/redist-libs/ruby/* $rvm_ruby_home/lib/ruby + cp -r $rvm_ruby_src_path/Merlin/Main/Languages/Ruby/Libs/* $rvm_ruby_home/lib/IronRuby else $rvm_scripts_path/log "info" "Retrieving IronRuby" + $rvm_scripts_path/fetch "$rvm_url" "$rvm_ruby_package_file" result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while trying to fetch the source. Aborting the installation." ; __rvm_pushpop ; return $result fi - __rvm_run "extract" "tar zxf $rvm_archives_path/$rvm_ruby_package_file -C $rvm_src_path" "Extracting $rvm_ruby_package_file ..." - result=$? ; if [[ "$result" -gt 0 ]] ; then - $rvm_scripts_path/log "error" "There has been an error while trying to extract the source. Aborting the installation." ; __rvm_pushpop ; return $result + mkdir -p $rvm_ruby_src_path $rvm_ruby_home + unzip -o -d ${rvm_ruby_src_path} ${rvm_archives_path}/${rvm_ruby_package_file} >> "$rvm_ruby_log_path/extract.log" 2>> "$rvm_ruby_log_path/extract.error.log" + result=$? ; if [[ "$result" -gt 1 ]] ; then + $rvm_scripts_path/log "error" "There has been an error while trying to extract $rvm_ruby_package_file. Aborting the installation." ; __rvm_pushpop ; return $result fi - rm -rf $rvm_ruby_src_path - mv $rvm_src_path/$rvm_ruby_package_name $rvm_ruby_src_path - - #mv $rvm_ruby_home/ironruby/* $rvm_ruby_home - #rm -rf $rvm_ruby_home/ironruby - #mv $rvm_ruby_src_path/$rvm_ruby_package_file/* $rvm_ruby_home - #mv $rvm_ruby_home/lib/ironruby $rvm_ruby_home/lib/IronRuby + for dir in bin lib silverlight ; do + cp -Rf $rvm_src_path/$rvm_ruby_string/$dir "$rvm_ruby_home/$dir" + done fi - builtin cd $rvm_ruby_src_path - - $rvm_bin_path/rvm 1.8.7 -S gem install pathname2 --no-rdoc --no-ri - - # MONO_LIB=/Library/Frameworks/Mono.framework/Versions/current/lib/ - rvm_ruby_make="$rvm_bin_path/rvm 1.8.7 -S rake MERLIN_ROOT=\"$rvm_ruby_src_path/Merlin/Main\" compile mono=1 configuration=release --trace" - __rvm_run "rake" "$rvm_ruby_make" "Building IronRuby..." - if [[ $? -gt 0 ]] ; then result=$? ; return $result ; fi - - rm -rf $rvm_ruby_home/* - mkdir -p $rvm_ruby_home/bin $rvm_ruby_home/lib $rvm_ruby_home/lib/ruby $rvm_ruby_home/lib/IronRuby - - cp -r $rvm_ruby_src_path/Merlin/Main/Bin/mono_release/* $rvm_ruby_home/bin/ - cp -r $rvm_ruby_src_path/Merlin/Main/Languages/Ruby/Scripts/bin/* $rvm_ruby_home/bin/ - cp -r $rvm_ruby_src_path/Merlin/External.LCA_RESTRICTED/Languages/Ruby/redist-libs/ruby/* $rvm_ruby_home/lib/ruby - cp -r $rvm_ruby_src_path/Merlin/Main/Languages/Ruby/Libs/* $rvm_ruby_home/lib/IronRuby - - binaries="gem irb rake rdoc ri ruby" - for binary_name in $(echo $binaries); do - binary_path="" - if [[ "ruby" != "$binary_name" ]] ; then - binary_path="$rvm_ruby_home/bin/i$binary_name" + binaries=(gem irb rdoc rake ri ruby) + for binary_name in ${binaries[@]} ; do + if [[ -s $rvm_ruby_home/bin/$binary_name ]] ; then + cat "$rvm_ruby_home/bin/$binary_name" | tr -d '\r' > "$rvm_ruby_home/bin/$binary_name.new" + #sed -e '1,1s=.*=#!'"/usr/bin/env ir=" "$rvm_ruby_home/bin/$binary_name" > "$rvm_ruby_home/bin/$binary_name.new" + mv -f "$rvm_ruby_home/bin/$binary_name.new" "$rvm_ruby_home/bin/$binary_name" + chmod +x $rvm_ruby_home/bin/$binary_name fi - ruby_wrapper=$(cat < "$rvm_ruby_home/bin/ir.new" + mv -f "$rvm_ruby_home/bin/ir.new" "$rvm_ruby_home/bin/ir" + chmod +x $rvm_ruby_home/bin/ir + ln -fs $rvm_ruby_home/bin/ir $rvm_ruby_home/bin/ruby -exec mono $rvm_ruby_home/bin/ir.exe $binary_path "\$@" -RubyWrapper -) - files="$rvm_ruby_home/bin/$binary_name $rvm_bin_path/$binary_name-$rvm_ruby_string" - for file_name in $(echo $files) ; do - rm -f $file_name - echo "$ruby_wrapper" > $file_name - if [[ -f $file_name ]] ; then chmod +x $file_name ; fi - done - if [[ "$binary_name" = "ruby" ]] ; then - echo "$ruby_wrapper" > $rvm_bin_path/$rvm_ruby_string - fi - unset file_name ruby_wrapper binary_name binary_path files prefix - done + __rvm_run "gems.install" "PATH=$rvm_ruby_gem_home/bin:$rvm_ruby_global_gems_path/bin:$rvm_ruby_home/bin:$PATH GEM_HOME=$rvm_ruby_gem_home GEM_PATH=$rvm_ruby_gem_home $rvm_ruby_home/bin/gem install --no-rdoc --no-ri rake $rvm_gem_options" "Installing $rvm_gem_name to $dir" ;; mput|shyouhei) @@ -593,35 +631,32 @@ RubyWrapper rvm_ruby_home="$rvm_rubies_path/$rvm_ruby_interpreter-$rvm_ruby_version" - builtin cd $rvm_src_path + __rvm_fetch_from_github "mput" "trunk" - if [[ ! -d "$rvm_ruby_src_path" ]] || [[ ! -d "$rvm_ruby_src_path/.git" ]] ; then - rm -rf $rvm_ruby_src_path - __rvm_run "mput.repo" "git clone --depth 1 $rvm_ruby_repo_url $rvm_ruby_src_path" "Cloning $rvm_ruby_repo_url" - builtin cd $rvm_ruby_src_path - else - builtin cd $rvm_ruby_src_path - __rvm_run "mput.repo" "git pull origin trunk" "Pulling from origin trunk" + __rvm_apply_patches + result=$? ; if [[ "$result" -gt 0 ]] ; then + $rvm_scripts_path/log "error" "There has been an error while trying to apply patches to mput. Aborting the installation." ; return $result fi if [[ ! -s "$rvm_ruby_src_path/configure" ]] ; then - if which autoconf &> /dev/null ; then + if command -v autoconf &> /dev/null ; then __rvm_run "autoconf" "autoconf" "Running autoconf" else - $rvm_scripts_path/log "fail" "rvm expects autoconf to install this ruby interpreter, autoconf was not found in PATH. Aborting installation." ; result=$? ; return $result + result=$?; $rvm_scripts_path/log "fail" "rvm expects autoconf to install this ruby interpreter, autoconf was not found in PATH. Aborting installation." ; return $result fi fi if [[ -s ./Makefile ]] && [[ -z "$rvm_reconfigure_flag" ]] ; then (($rvm_debug_flag)) && $rvm_scripts_path/log "debug" "Skipping configure step, Makefile exists so configure must have already been run." - elif [[ ! -z "$rvm_ruby_configure" ]] ; then + elif [[ -n "$rvm_ruby_configure" ]] ; then __rvm_run "configure" "$rvm_ruby_configure" result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while trying to configure the source. Aborting the installation." ; __rvm_pushpop ; return $result fi elif [[ -s ./configure ]] ; then - __rvm_run "configure" "./configure --prefix=$rvm_ruby_home $rvm_ruby_configure_flags" "Configuring $rvm_ruby_string using $rvm_ruby_configure_flags, this may take a while depending on your cpu(s)..." + local configure_command="./configure --prefix=$rvm_ruby_home $rvm_ruby_configure_flags" + __rvm_run "configure" "" "Configuring $rvm_ruby_string using $rvm_ruby_configure_flags, this may take a while depending on your cpu(s)..." result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while trying to configure the source. Aborting the installation." ; __rvm_pushpop ; return $result fi @@ -630,7 +665,7 @@ RubyWrapper fi rvm_ruby_make=${rvm_ruby_make:-"make"} - __rvm_run "make" "$rvm_ruby_make $rvm_make_flags" "Compiling $rvm_ruby_string, this may take a while, depending on your cpu(s)..." + __rvm_run "make" "$rvm_ruby_make $rvm_make_flags" "Compiling $rvm_ruby_string, this may take a while depending on your cpu(s)..." result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while trying to run make. Aborting the installation." ; __rvm_pushpop ; return $result fi @@ -655,6 +690,9 @@ RubyWrapper ;; ruby) + __rvm_check_for_bison + result=$? ; if [[ "$result" -gt 0 ]] ; then return $result ; fi + if [[ "rvm_make_flags_flag" -eq 1 ]] ; then __rvm_make_flags ; fi __rvm_install_source $* ;; @@ -667,7 +705,24 @@ RubyWrapper esac - if [[ ! -z "$ruby_options" ]] ; then RUBYOPT=$ruby_options ; export RUBYOPT ; fi + rvm_hook="after_install" ; source $rvm_scripts_path/hook + + if [[ -n "$ruby_options" ]] ; then RUBYOPT=$ruby_options ; export RUBYOPT ; fi +} + +__rvm_fetch_from_github() { + rm -rf "$rvm_ruby_src_path" + if [[ ! -d "$rvm_ruby_repo_path/.git" ]] ; then + rm -rf "$rvm_ruby_repo_path" + builtin cd "$rvm_home" + __rvm_run "$1.repo" "git clone --depth 1 $rvm_ruby_repo_url $rvm_ruby_repo_path" "Cloning $rvm_ruby_repo_url" + else + local branch="${2:-"master"}" + builtin cd "$rvm_ruby_repo_path" + __rvm_run "$1.repo" "git pull origin $branch" "Pulling from origin $branch" + fi + __rvm_run "$1.copy" "cp -R \"$rvm_ruby_repo_path\" \"$rvm_ruby_src_path\"" "Copying from repo to source..." + builtin cd "$rvm_ruby_src_path" } __rvm_fetch_ruby() { @@ -679,7 +734,7 @@ __rvm_fetch_ruby() { rvm_archive_extension="${rvm_archive_extension:-tar.gz}" if [[ ! -s "$rvm_archives_path/$rvm_ruby_package_file.$rvm_archive_extension" ]] ; then if [[ "ruby" = "$rvm_ruby_interpreter" ]] ; then - rvm_url="ftp://ftp.ruby-lang.org/pub/ruby/1.$rvm_major_version/$rvm_ruby_package_file.$rvm_archive_extension" + rvm_url="$(__rvm_db "${rvm_ruby_interpreter}_${rvm_release_version}.${rvm_major_version}_url")/$rvm_ruby_package_file.$rvm_archive_extension" elif [[ "ree" = "$rvm_ruby_interpreter" ]] ; then rvm_url="$(__rvm_db "${rvm_ruby_interpreter}_${rvm_ruby_version}_url")/$rvm_ruby_package_file.$rvm_archive_extension" elif [[ "jruby" = "$rvm_ruby_interpreter" ]] ; then @@ -697,7 +752,7 @@ __rvm_fetch_ruby() { fi # Only re-extract if forced. - if [[ ! -d "$rvm_src_path/$rvm_ruby_string" ]] || [[ ! -z "$rvm_force_flag" ]] ; then + if [[ ! -d "$rvm_src_path/$rvm_ruby_string" ]] || [[ -n "$rvm_force_flag" ]] ; then if [[ "tar.gz" = "$rvm_archive_extension" ]] || [[ "tgz" = "$rvm_archive_extension" ]] ; then __rvm_run "extract" "cat $rvm_archives_path/$rvm_ruby_package_file.$rvm_archive_extension | gunzip | tar xf - -C $rvm_src_path" "Extracting $rvm_ruby_package_file ..." result=$? ; if [[ "$result" -gt 0 ]] ; then @@ -713,12 +768,13 @@ __rvm_fetch_ruby() { $rvm_scripts_path/log "info" "$rvm_ruby_src_path has already been extracted." ; __rvm_pushpop ; return 0 fi else - if [[ ! -z "$(echo $rvm_url | awk '/^git/')" ]] ; then - if [[ -d "$rvm_ruby_src_path/.git" ]] ; then - builtin cd $rvm_ruby_src_path + mkdir -p "$rvm_repo_path" + if [[ -n "$(echo $rvm_url | awk '/^git/')" ]] ; then + if [[ -d "$rvm_ruby_repo_path/.git" ]] ; then + builtin cd $rvm_ruby_repo_path if [[ -z "$rvm_ruby_revision" ]] ; then $rvm_scripts_path/log "info" "Pulling from $rvm_ruby_repo_url, this may take a while depending on your connection..." - git pull origin master + git pull origin master --force result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while trying to update the source from the remote repository. Aborting the installation." ; __rvm_pushpop ; return $result fi @@ -733,59 +789,73 @@ __rvm_fetch_ruby() { fi fi else + rm -rf "$rvm_ruby_repo_path" $rvm_scripts_path/log "info" "Cloning from $rvm_ruby_repo_url, this may take a while depending on your connection..." - git clone --depth 1 $rvm_ruby_repo_url $rvm_ruby_src_path + git clone --depth 1 "$rvm_ruby_repo_url" "$rvm_ruby_repo_path" result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while trying to fetch the repository. Aborting the installation." ; __rvm_pushpop ; return $result fi fi else - if [[ ! -z "$rvm_ruby_tag" ]] ; then + if [[ -n "$rvm_ruby_tag" ]] ; then # TODO: Check if tag v is valid rvm_url="${rvm_url:-"$rvm_ruby_repo_url/tags/$(echo $rvm_ruby_tag | sed 's/^t//')"}" - elif [[ -z "$rvm_ruby_version" ]] && [[ ! -z "$rvm_head_flag" ]] ; then + elif [[ -z "$rvm_ruby_version" ]] && [[ -n "$rvm_head_flag" ]] ; then rvm_url="${rvm_url:-"$rvm_ruby_repo_url/trunk"}" elif [[ "$rvm_major_version" = "9" ]] ; then - if [[ -z "$rvm_minor_version" ]] || [[ "$rvm_minor_version" = 2 ]] ; then + if [[ -z "$rvm_minor_version" ]] || [[ "$rvm_minor_version" = 3 ]] ; then rvm_url="${rvm_url:-"$rvm_ruby_repo_url/trunk"}" else - rvm_url="${rvm_url:-"$rvm_ruby_repo_url/branches/ruby_1_${rvm_major_version}_${rvm_minor_version}"}" + rvm_url="${rvm_url:-"$rvm_ruby_repo_url/branches/ruby_${rvm_release_version}_${rvm_major_version}_${rvm_minor_version}"}" fi elif [[ -z "$rvm_minor_version" ]] || [[ "$rvm_major_version.$rvm_minor_version" = "8.8" ]] ; then - rvm_url="${rvm_url:-"$rvm_ruby_repo_url/branches/ruby_1_${rvm_major_version}"}" + rvm_url="${rvm_url:-"$rvm_ruby_repo_url/branches/ruby_${rvm_release_version}_${rvm_major_version}"}" else - rvm_url="${rvm_url:-"$rvm_ruby_repo_url/branches/ruby_1_${rvm_major_version}_${rvm_minor_version}"}" + rvm_url="${rvm_url:-"$rvm_ruby_repo_url/branches/ruby_${rvm_release_version}_${rvm_major_version}_${rvm_minor_version}"}" fi rvm_rev="" - if [ ! -z "$rvm_ruby_revision" ] ; then + if [ -n "$rvm_ruby_revision" ] ; then rvm_rev="-$rvm_ruby_revision" fi - if [[ -d "$rvm_ruby_src_path/.svn" ]] ; then - builtin cd $rvm_ruby_src_path + if [[ -d "$rvm_ruby_repo_path/.svn" ]] ; then + builtin cd $rvm_ruby_repo_path $rvm_scripts_path/log "info" "Updating ruby from $rvm_url" + __rvm_run "svn.switch" "svn switch $rvm_url" __rvm_run "svn.update" "svn update" - if [[ ! -z "$rvm_rev" ]] ; then + if [[ -n "$rvm_rev" ]] ; then $rvm_scripts_path/log "info" "Checking out revision ${rvm_rev/-r/-r } from $rvm_url" __rvm_run "svn.checkout" "svn update -q ${rvm_rev/-r/-r }" fi else - rm -rf $rvm_ruby_src_path - __rvm_run "svn.checkout" "svn checkout -q ${rvm_rev/-r/-r } $rvm_url $rvm_ruby_src_path" + rm -rf $rvm_ruby_repo_path + __rvm_run "svn.checkout" "svn checkout -q ${rvm_rev/-r/-r } $rvm_url $rvm_ruby_repo_path" "Downloading source from ${rvm_url}." fi result=$? ; if [[ "$result" -gt 0 ]] ; then $rvm_scripts_path/log "error" "There has been an error while trying to fetch / update the source. Aborting the installation." ; __rvm_pushpop ; return $result fi fi + $rvm_scripts_path/log "info" "Copying from repo to src path..." + rm -rf "$rvm_ruby_src_path" + cp -R "$rvm_ruby_repo_path" "$rvm_ruby_src_path" + fi +} + +__rvm_check_default() { + default_ruby_interpreter="$(rvm alias show default 2>/dev/null | awk -F"${rvm_gemset_seperator:-"@"}" '{print $1}')" + current_ruby_interpreter="$(echo "$rvm_ruby_string" | awk -F"${rvm_gemset_seperator:-"@"}" '{print $1}')" + if [[ -n "$current_ruby_interpreter" && "$current_ruby_interpreter" == "$default_ruby_interpreter" ]]; then + __rvm_run_with_env 'default.restore' 'system' 'rvm use system --default' 'Removing default ruby interpreter' fi + unset default_ruby_interpreter current_ruby_interpreter } __rvm_uninstall_ruby() { if [[ -z "$rvm_ruby_selected_flag" ]] ; then __rvm_select ; fi - if [[ ! -z "$rvm_ruby_string" ]] ; then + if [[ -n "$rvm_ruby_string" ]] ; then for dir in $rvm_rubies_path ; do if [[ -d $dir/$rvm_ruby_string ]] ; then $rvm_scripts_path/log "info" "Removing $dir/$rvm_ruby_string..." @@ -797,7 +867,10 @@ __rvm_uninstall_ruby() { rm -f $rvm_bin_path/$rvm_ruby_string fi done ; unset dir - rm -rf $rvm_gems_path/$rvm_ruby_interpreter/$rvm_ruby_version*/ + __rvm_remove_gemsets + + __rvm_check_default + else $rvm_scripts_path/log "fail" "Cannot uninstall unknown package '$rvm_ruby_string'" fi ; unset rvm_uninstall_flag @@ -806,7 +879,7 @@ __rvm_uninstall_ruby() { __rvm_remove_ruby() { if [[ -z "$rvm_ruby_selected_flag" ]] ; then __rvm_select ; fi - if [[ ! -z "$rvm_ruby_string" ]] ; then + if [[ -n "$rvm_ruby_string" ]] ; then for dir in $rvm_src_path $rvm_rubies_path ; do if [[ -d $dir/$rvm_ruby_string ]] ; then $rvm_scripts_path/log "info" "Removing $dir/$rvm_ruby_string..." @@ -814,56 +887,124 @@ __rvm_remove_ruby() { else $rvm_scripts_path/log "info" "it seems that $dir/$rvm_ruby_string is already non existent." fi + if [[ -e $rvm_bin_path/$rvm_ruby_string ]] ; then rm -f $rvm_bin_path/$rvm_ruby_string fi + + __rvm_check_default + done ; unset dir + __rvm_remove_gemsets + __rvm_remove_archives + __rvm_remove_aliases + __rvm_remove_wrappers + __rvm_remove_environments + __rvm_remove_binaries else - $rvm_scripts_path/log "fail" "Cannot uninstall unknown package '$rvm_ruby_string'" + $rvm_scripts_path/log "fail" "Cannot remove unknown package '$rvm_ruby_string'" fi ; unset rvm_remove_flag } -__rvm_post_install() { - binaries="${binaries:-"gem irb erb ri rdoc testrb rake"}" - for binary in $(echo $binaries) ; do - if [[ -e "$rvm_ruby_home/bin/$binary" ]] || [[ -e "$rvm_ruby_src_path/bin/$binary" ]] ; then - if [[ "$rvm_ruby_src_path" != "$rvm_ruby_home" ]] && [[ -f "$rvm_ruby_src_path/bin/$binary" ]] ; then - cp -f "$rvm_ruby_src_path/bin/$binary" "$rvm_ruby_home/bin/$binary" - elif [[ -f "$rvm_ruby_gem_home/bin/$binary" ]] ; then - cp -f "$rvm_ruby_gem_home/bin/$binary" "$rvm_ruby_home/bin/$binary" - fi - __rvm_inject_gem_env "$rvm_ruby_home/bin/$binary" - __rvm_inject_ruby_shebang "$rvm_ruby_home/bin/$binary" - chmod +x "$rvm_ruby_home/bin/$binary" - fi - done ; unset binary binaries +__rvm_remove_gemsets() { + if [[ -n "$rvm_gems_flag" ]] ; then + $rvm_scripts_path/log "info" "Removing $rvm_ruby_string gemsets..." + gemsets="$rvm_gems_path/$rvm_ruby_string $(\ls -d "${rvm_gems_path}"/* | awk '/'$rvm_ruby_string'@/')" + for gemset in $gemsets ; do + if [[ -d "$gemset" ]] ; then + rm -rf "$gemset" + fi + done ; unset gemset gemsets + fi +} - $rvm_scripts_path/log "info" "Installing gems for $rvm_ruby_string." +__rvm_remove_wrappers() { + $rvm_scripts_path/log "info" "Removing $rvm_ruby_string wrappers..." + wrappers="$rvm_wrappers_path/$rvm_ruby_string $(\ls -d "$rvm_wrappers_path"/* 2>/dev/null | awk '/'$rvm_ruby_string'@/')" + for wrapper in $wrappers ; do + rm -rf "$wrapper" + done ; unset wrapper wrappers +} - for rvm_gem_name in rake ; do - home="$GEM_HOME" ; path="$GEM_PATH" # Save - export GEM_HOME="$rvm_ruby_global_gems_path" - export GEM_PATH="$rvm_ruby_global_gems_path" - export BUNDLE_PATH="$rvm_ruby_global_gems_path" - __rvm_run "gems.install" "$rvm_ruby_home/bin/gem install $rvm_gem_name $rvm_gem_options" "Installing $rvm_gem_name" - export GEM_HOME="$home" ; export GEM_PATH="$path" ; export BUNDLE_PATH="$home" ; unset home path - done ; unset rvm_gem_name - - $rvm_scripts_path/log "info" "Installation of gems for $rvm_ruby_string is complete." - - binary=rake - if [[ -x $rvm_ruby_gem_home/bin/$binary ]] ; then - if [[ "$rvm_ruby_gem_home" != "$rvm_ruby_home" ]] ; then - cp $rvm_ruby_gem_home/bin/$binary $rvm_ruby_home/bin/$binary +__rvm_remove_environments() { + $rvm_scripts_path/log "info" "Removing $rvm_ruby_string environments..." + environments="$rvm_environments_path/$rvm_ruby_string $(\ls -d "$rvm_environments_path"/* | awk '/'$rvm_ruby_string'@/')" + for environment in $environments ; do + rm -rf "$environment" + done ; unset environment environments +} + +__rvm_remove_aliases() { + $rvm_scripts_path/log "info" "Removing $rvm_ruby_string aliases..." + aliases=$(awk '/'$rvm_ruby_string'/' $rvm_config_path/alias | sed 's/=.*//') + for alias_name in $aliases ; do + # Remove from alias key-value store + $rvm_scripts_path/alias delete "$alias_name" >/dev/null 2>&1 + done ; unset alias_name aliases +} + +__rvm_remove_archives() { + if [[ -n "$rvm_archive_flag" ]] ; then + $rvm_scripts_path/log "info" "Removing $rvm_ruby_string archives..." + rm -f $rvm_archives_path/${rvm_ruby_package_file}.${rvm_archive_extension} + fi +} + +__rvm_remove_binaries() { + $rvm_scripts_path/log "info" "Removing $rvm_ruby_string binaries..." + # Iterate over all binaries and check for symlinked wrappers etc. + for binary_name in $(\ls "$rvm_bin_path"); do + full_binary_path="$rvm_bin_path/$binary_name" + if [[ -L "$full_binary_path" ]] && $rvm_scripts_path/match "$(readlink "$full_binary_path")" "$rvm_ruby_string"; then + rm -f "$full_binary_path" fi - __rvm_inject_ruby_shebang "$rvm_ruby_home/bin/$binary" - __rvm_inject_gem_env "$rvm_ruby_home/bin/$binary" - fi ; unset binary + unset full_binary_path + done; unset binary_name +} + +__rvm_post_install() { + if [[ "$rvm_ruby_interpreter" != "jruby" ]] ; then + binaries="${binaries:-"gem irb erb ri rdoc testrb rake"}" + $rvm_scripts_path/log "info" "adjusting shebangs for $rvm_ruby_string ($binaries)." + for binary in $(echo $binaries) ; do + if [[ -e "$rvm_ruby_home/bin/$binary" ]] || [[ -e "$rvm_ruby_src_path/bin/$binary" ]] ; then + if [[ "$rvm_ruby_src_path" != "$rvm_ruby_home" ]] && [[ -f "$rvm_ruby_src_path/bin/$binary" ]] ; then + cp -f "$rvm_ruby_src_path/bin/$binary" "$rvm_ruby_home/bin/$binary" + elif [[ -f "$rvm_ruby_gem_home/bin/$binary" ]] ; then + cp -f "$rvm_ruby_gem_home/bin/$binary" "$rvm_ruby_home/bin/$binary" + fi + __rvm_inject_gem_env "$rvm_ruby_home/bin/$binary" + __rvm_inject_ruby_shebang "$rvm_ruby_home/bin/$binary" + chmod +x "$rvm_ruby_home/bin/$binary" + fi + done ; unset binary binaries + fi + + # Import the initial gemsets. + __rvm_run_with_env "gemsets.initial" "$rvm_ruby_string" 'rvm gemset initial' "Importing initial gems..." + __rvm_irbrc + __rvm_generate_default_docs + + if [[ -n "$rvm_ruby_aliases" ]]; then + $rvm_scripts_path/log "info" "Setting up aliases for $rvm_ruby_string" + for ruby_alias in $rvm_ruby_aliases; do + $rvm_scripts_path/log info "Aliasing $rvm_ruby_string to $ruby_alias" + $rvm_scripts_path/alias delete "$ruby_alias" > /dev/null 2>&1 + $rvm_scripts_path/alias create "$ruby_alias" "$rvm_ruby_string" > /dev/null 2>&1 + done + unset rvm_ruby_aliases ruby_alias + fi +} + +__rvm_generate_default_docs() { + if [[ "$rvm_docs_flag" = "1" && "$rvm_ruby_interpreter" != "macruby" ]]; then + __rvm_run_with_env "docs.generate" "$rvm_ruby_string" "rvm docs generate-ri" "Attempting to generate ri documentation..." + fi } __rvm_rubygems_setup() { - if [[ ! -z "$(echo $rvm_ruby_version | awk '/^1\.9/')" ]] || [[ ! -z "$(echo $rvm_ruby_interpreter | awk '/^mput/')" ]] ; then + if [[ -n "$(echo $rvm_ruby_version | awk '/^1\.9/')" ]] || [[ -n "$(echo $rvm_ruby_interpreter | awk '/^mput/')" ]] ; then install=0 elif [[ "$rvm_ruby_string" = "ruby-head" ]] ; then install=0 @@ -871,32 +1012,52 @@ __rvm_rubygems_setup() { install=1 fi + __rvm_use + if [[ "$install" -eq 0 ]] ; then # 1.9.X has it's own built-in gem command __rvm_inject_ruby_shebang "$rvm_ruby_src_path/bin/gem" __rvm_inject_gem_env "$rvm_ruby_home/bin/gem" + cp $rvm_ruby_src_path/bin/gem $rvm_ruby_home/bin/gem + home="$GEM_HOME" ; path="$GEM_PATH" # Save - export GEM_HOME="$rvm_ruby_global_gems_path" - export GEM_PATH="$rvm_ruby_global_gems_path" - export BUNDLE_PATH="$rvm_ruby_global_gems_path" - __rvm_run "rubygems.update" "$rvm_ruby_home/bin/gem update --system" "Updating rubygems for $rvm_ruby_string" - export GEM_HOME="$home" ; export GEM_PATH="$path" ; export BUNDLE_PATH="$home" unset home path + for dir in $rvm_ruby_global_gems_path $rvm_ruby_gem_home ; do + export GEM_HOME="$dir" ; export GEM_PATH="$dir" ; export BUNDLE_PATH="$dir" + __rvm_run "rubygems.update" "$rvm_ruby_home/bin/gem update --system" "Updating rubygems for $dir" + done ; unset home path dir + GEM_HOME="$home" ; GEM_PATH="$path" ; BUNDLE_PATH="$home" + export GEM_HOME GEM_PATH BUNDLE_PATH __rvm_inject_ruby_shebang "$rvm_ruby_home/bin/gem" __rvm_inject_gem_env "$rvm_ruby_home/bin/gem" - ruby_lib_gem_path="$rvm_ruby_home/lib/ruby/gems/1.$rvm_major_version" - elif [[ ! -z "$(echo $rvm_ruby_interpreter | awk '/^rbx|jruby/')" ]] ; then - if [[ ! -z "$rvm_debug_flag" ]] ; then $rvm_scripts_path/log "debug" "Skipping rubygems update for $rvm_ruby_version" ; fi + + directory_name="$rvm_ruby_home/lib/ruby/gems" + version_number="${rvm_release_version}.${rvm_major_version}" + if [[ "$version_number" == "." ]]; then + version_number="$(\ls "$directory_name" | grep '^[[:digit:]].[[:digit:]]\(.[[:digit:]]\)\?' | head -n1)" + if [[ -n "$version_number" ]]; then + ruby_lib_gem_path="${directory_name}/${version_number}" + else + ruby_lib_gem_path="" + fi + else + ruby_lib_gem_path="${directory_name}/${version_number}" + fi + unset directory_name version_number + elif [[ -n "$(echo $rvm_ruby_interpreter | awk '/^rbx|jruby/')" ]] ; then + # Hands off rubygems for rbx & jruby + if [[ -n "$rvm_debug_flag" ]] ; then $rvm_scripts_path/log "debug" "Skipping rubygems update for $rvm_ruby_version" ; fi ruby_lib_gem_path="$rvm_ruby_home/lib/ruby/gems/jruby" else $rvm_scripts_path/log "info" "Installing rubygems dedicated to $rvm_ruby_string..." - rvm_rubygems_version=$(__rvm_db "rubygems_version") + rvm_rubygems_version="$(__rvm_db "${rvm_ruby_interpreter}_rubygems_version")" + rvm_rubygems_version="${rvm_rubygems_version:-"$(__rvm_db "rubygems_version")"}" rvm_rubygems_url=$(__rvm_db "rubygems_${rvm_rubygems_version}_url") rvm_gem_package_name="rubygems-$rvm_rubygems_version" rvm_gem_url="$rvm_rubygems_url/$rvm_gem_package_name.tgz" - - # Sanity check... + # Sanity check... If setup.rb is missing from the rubygems source path, + # something went wrong. Cleanup, aisle 3! if [[ ! -f "$rvm_src_path/$rvm_gem_package_name/setup.rb" ]]; then rm -rf "$rvm_src_path/$rvm_gem_package_name" fi @@ -923,20 +1084,27 @@ __rvm_rubygems_setup() { __rvm_inject_ruby_shebang "$rvm_ruby_home/bin/gem" - if [[ ! -z "$rvm_major_version" ]] ; then - ruby_lib_gem_path="$rvm_ruby_home/lib/ruby/gems/1.$rvm_major_version" + if [[ -n "$rvm_major_version" ]] ; then + ruby_lib_gem_path="$rvm_ruby_home/lib/ruby/gems/${rvm_release_version}.$rvm_major_version" else ruby_lib_gem_path="$rvm_ruby_home/lib/ruby/gems/$interpreter" fi fi - # Add ruby's gem path to ruby's lib direcotry. - mkdir -p $(dirname $ruby_lib_gem_path) - if [[ -d "$ruby_lib_gem_path" ]] ; then - rm -rf "$ruby_lib_gem_path" + if [[ -n "$ruby_lib_gem_path" ]]; then + # Add ruby's gem path to ruby's lib direcotry. + mkdir -p $(dirname $ruby_lib_gem_path) + if [[ -d "$ruby_lib_gem_path" ]] ; then rm -rf "$ruby_lib_gem_path" ; fi + ln -nfs "$rvm_ruby_gem_home" "$ruby_lib_gem_path" + fi; unset ruby_lib_gem_path + + if [[ -s "$rvm_ruby_src_path/bin/rdoc" ]] ; then + __rvm_inject_ruby_shebang "$rvm_ruby_src_path/bin/rdoc" + fi + + if [[ -s "$rvm_ruby_src_path/bin/rake" ]] ; then + __rvm_inject_ruby_shebang "$rvm_ruby_src_path/bin/rake" fi - ln -nfs "$rvm_ruby_gem_home" "$ruby_lib_gem_path" - unset ruby_lib_gem_path return $result } @@ -945,20 +1113,20 @@ __rvm_inject_ruby_shebang() { __rvm_actual_file $1 if [[ -f "$actual_file" ]] ; then - sed -i -e '1,1s=.*=#!'"$rvm_ruby_home/bin/ruby=" $actual_file - rm -f $actual_file.orig ; chmod +x "$actual_file" + sed -e '1,1s=.*=#!'"/usr/bin/env ruby=" ${actual_file} > "${actual_file}.new" + mv "${actual_file}.new" "${actual_file}" ; chmod +x "$actual_file" fi ; unset actual_file } __rvm_inject_gem_env() { __rvm_actual_file $1 if [[ -f "$actual_file" ]] ; then - if [[ ! -z "$(head -n 1 $actual_file | awk '/[j]*ruby/')" ]] ; then - string="ENV['GEM_HOME']=ENV['GEM_HOME'] || '$rvm_ruby_gem_home'\nENV['GEM_PATH']=ENV['GEM_PATH'] || '$rvm_ruby_gem_path'\nENV['PATH']='$rvm_ruby_home/bin:$rvm_ruby_gem_home/bin:' + ENV['PATH']\nENV['BUNDLE_PATH']=ENV['BUNDLE_PATH'] || '$rvm_ruby_gem_home'\n" - elif [[ ! -z "$(head -n 1 $actual_file | awk '/bash/')" ]] ; then - string="GEM_HOME=\${GEM_HOME:-'$rvm_ruby_gem_home'}\nGEM_PATH=\${GEM_PATH:-'$rvm_ruby_gem_path'}\nPATH=$rvm_ruby_home/bin:$rvm_ruby_gem_home/bin:\$PATH\nBUNDLE_PATH=\${BUNDLE_PATH:-'$rvm_ruby_gem_home'}\n" + if [[ -n "$(head -n 1 $actual_file | awk '/[j]*ruby/')" ]] ; then + string="ENV['GEM_HOME']=ENV['GEM_HOME'] || '$rvm_ruby_gem_home'\nENV['GEM_PATH']=ENV['GEM_PATH'] || '$rvm_ruby_gem_path'\nENV['PATH']='$rvm_ruby_gem_home/bin:$rvm_ruby_global_gems_path/bin:$rvm_ruby_home/bin:' + ENV['PATH']\nENV['BUNDLE_PATH']=ENV['BUNDLE_PATH'] || '$rvm_ruby_gem_home'\n" + elif [[ -n "$(head -n 1 $actual_file | awk '/bash/')" ]] ; then + string="GEM_HOME=\${GEM_HOME:-'$rvm_ruby_gem_home'}\nGEM_PATH=\${GEM_PATH:-'$rvm_ruby_gem_path'}\nPATH=$rvm_ruby_gem_home/bin:$rvm_ruby_global_gems_path/bin:$rvm_ruby_home/bin:\$PATH\nBUNDLE_PATH=\${BUNDLE_PATH:-'$rvm_ruby_gem_home'}\n" fi - if [[ ! -z "$string" ]] ; then + if [[ -n "$string" ]] ; then awk "NR==2 {print \"$string\"} {print}" "$actual_file" > "$actual_file.new" mv $actual_file.new $actual_file ; chmod +x "$actual_file" unset string @@ -975,28 +1143,18 @@ __rvm_actual_file() { } __rvm_manage_rubies() { - rubies=() ; successes=() ; errors=() ; statuses=() - unset rvm_gemset_name rvm_ruby_selected_flag - rvm_ruby_gem_home=$(echo $rvm_ruby_gem_home | awk -F'%' '{print $1}') - rvm_ruby_string=$(echo $rvm_ruby_string | awk -F'%' '{print $1}') - - # TODO: Extract the common functionality out of the if below - #if [[ ! -z "$rvm_ruby_string" ]] ; then - # unset rvm_ruby_interpreter rvm_ruby_version - # eval "__rvm_${rvm_action}_ruby" - # __rvm_unset_ruby_variables - #elif [[ ! -z "$rvm_ruby_version" ]] ;then - if [[ ! -z "$rubies_string" ]] ;then - for rvm_ruby_string in $(echo $rubies_string | tr ',' ' ') ; do + rvm_ruby_gem_home=$(echo $rvm_ruby_gem_home | awk -F${rvm_gemset_separator} '{print $1}') + rvm_ruby_string=$(echo $rvm_ruby_string | awk -F${rvm_gemset_separator} '{print $1}') + + local manage_result=0 + + if [[ -n "$rubies_string" ]] ;then + for rvm_ruby_string in $(echo "$rubies_string" | tr ',' ' ') ; do eval "__rvm_${rvm_action}_ruby" __rvm_unset_ruby_variables done - #elif [[ ! -z "$rvm_ruby_interpreter" ]] ; then - # unset rvm_ruby_string rvm_ruby_version - # eval "__rvm_${rvm_action}_ruby" - # __rvm_unset_ruby_variables else # all if [[ "$rvm_action" != "install" ]] ; then while read -r bin_line @@ -1012,12 +1170,11 @@ __rvm_manage_rubies() { fi fi - if [[ ! -z "$rvm_summary_flag" ]] ; then __rvm_summary ; fi - if [[ ! -z "$rvm_yaml_flag" ]] ; then __rvm_yaml ; fi - if [[ ! -z "$rvm_json_flag" ]] ; then __rvm_json ; fi + # TODO: This should return the exit status of the command that got called. + return $manage_result + } rvm_action="$1" ; rubies_string="$2" __rvm_manage_rubies exit $? - diff --git a/scripts/manpages b/scripts/manpages new file mode 100755 index 0000000000..aab2cd0c8e --- /dev/null +++ b/scripts/manpages @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +source "$rvm_scripts_path/initialize" + +# Take if a semicolon is encountered at the end of the +# manpath env variable, man also processes the usual, +# generated manpaths as well as the variable contents. +export MANPATH="${rvm_man_path}:${MANPATH}" diff --git a/scripts/match b/scripts/match index 12ae174746..3cb82926cf 100755 --- a/scripts/match +++ b/scripts/match @@ -1,16 +1,5 @@ #!/usr/bin/env bash -if [[ -z "$1" ]] || [[ -z "$2" ]] ; then - exit 1 -fi +if [[ -z "$1" ]] || [[ -z "$2" ]] ; then exit 1 ; fi -if [[ ! -z "$BASH_VERSION" ]] && [[ ${BASH_VERSION:0:1} -gt 2 ]] ; then - [[ "$1" =~ $2 ]] - exit $? -else - if echo "$1" | grep -q "${2}" ; then - exit 0 - else - exit 1 - fi -fi +if [[ -n "$(echo "$1" | awk "/${2}/")" ]] ; then exit 0 ; else exit 1 ; fi diff --git a/scripts/md5 b/scripts/md5 index 311f49d783..ca0dd7c90c 100755 --- a/scripts/md5 +++ b/scripts/md5 @@ -2,17 +2,16 @@ if [[ "$rvm_trace_flag" -eq 1 ]] ; then set -x ; export rvm_trace_flag ; fi -file=$1 ; md5=$2 +file="$1" +md5="$2" if [[ "Linux" = "$(uname)" ]] ; then command="md5sum" - #md5sum --status -c "$file" elif [[ "Darwin" = "$(uname)" ]] ; then - #md5 --status -c "$1" - command="/sbin/md5" + command="/sbin/md5 -q" fi -file_md5=$($command $file | awk '{print $NF}') +file_md5=$($command "$file" | awk '{print $1}') if [[ "$file_md5" = "$md5" ]] ; then exit 0 diff --git a/scripts/monitor b/scripts/monitor index e0c0b237a4..90fa29e03a 100755 --- a/scripts/monitor +++ b/scripts/monitor @@ -1,16 +1,12 @@ #!/usr/bin/env bash -if [[ -z "$rvm_trace_flag" ]] ; then set +x ; else set -x ; fi - -original_ruby_version=$rvm_ruby_version +original_ruby_strings=$rvm_ruby_strings original_ruby_string=$rvm_ruby_string -source $rvm_scripts_path/rvm +source "$rvm_scripts_path/base" rvm_monitor_sleep="${rvm_monitor_sleep:-2}" -trap "rm -f $rvm_tmp_path/$$* > /dev/null 2>&1 ; exit" 0 1 2 3 15 - timestamp() { if [[ "Darwin" = "$(uname)" ]] ; then echo $(stat -f "%m" $1) @@ -57,32 +53,31 @@ while : ; do done if [[ "$(array_length "changed_${framework}_files")" -gt 0 ]] ; then - rvm_ruby_version=$original_ruby_version + rvm_ruby_strings=$original_ruby_strings rvm_ruby_string=$original_ruby_string if [[ "spec" = "$framework" ]] ; then rvm_action="spec" rvm_ruby_args="spec/spec_helper.rb ${changed_spec_files[*]}" - __rvm_do - + $rvm_scripts_path/set $rvm_action $rvm_ruby_args elif [[ "test" = "$framework" ]] ; then rvm_action="ruby" rvm_ruby_args=" -r$(echo "${changed_test_files[*]}" | sed 's/ / -r/g') test/test_helper.rb" - __rvm_do + $rvm_scripts_path/set $rvm_action $rvm_ruby_args fi update=1 fi if [[ "$(array_length "changed_code_files")" -gt 0 ]] ; then - rvm_ruby_version=$original_ruby_version + rvm_ruby_strings=$original_ruby_strings rvm_ruby_string=$original_ruby_string if [[ "spec" = "$framework" ]] ; then rvm_action="spec" rvm_ruby_args="spec/" - __rvm_do + $rvm_scripts_path/set $rvm_action $rvm_ruby_args elif [[ "test" = "$framework" ]] ; then rvm_action="rake" rvm_ruby_args="test" - __rvm_do + $rvm_scripts_path/set $rvm_action $rvm_ruby_args fi update=1 fi diff --git a/scripts/notes b/scripts/notes index e64914f86a..1158a14590 100755 --- a/scripts/notes +++ b/scripts/notes @@ -3,67 +3,69 @@ system="$(uname)" item="$(tput setaf 2)* $(tput sgr0)" -echo -e "\n$(tput setaf 6)**** NOTICE *************************************************************************************" -echo -e "* The rubies install path has moved to \$rvm_path/rubies/ instead of directly in \$rvm_path. *" -echo -e "* If you encounter any issues with a ruby your best bet is to 'rvm remove X ; rvm install X' *" -echo -e "* Gems are now per interpreter installation instead of per interpreter/version *" -echo -e "* so for example to upgrade an older install of 1.8.6 and preserve gems: *" -echo -e "* rm -rf ~/.rvm/gems/ruby-1.8.6-p383 ; mv ~/.rvm/gems/ruby/1.8.6 ~/.rvm/gems/ruby-1.8.6-p383 *" -echo -e "*************************************************************************************************$(tput sgr0)\n" - if [[ "Linux" = "$system" ]] ; then for file in /etc/*-release ; do release="( $(cat $file) )" ; break done - echo -e "\n$(tput setaf 2)Notes for ${system} $release$(tput sgr0)\n" - - rvm_apt_get_binary="$(which aptitude 2> /dev/null)" - rvm_emerge_binary="$(which emerge 2> /dev/null)" - rvm_pacman_binary="$(which pacman 2> /dev/null)" - rvm_yum_binary="$(which yum 2> /dev/null)" - - echo -e "\n $item curl is required.\n" - echo -e "\n $item patch is required (for ree, some ruby head's).\n" - if [[ ! -z "$rvm_apt_get_binary" ]] ; then - echo -e " $item For JRuby (if you wish to use it) you will need:" - echo -e "\n $ aptitude install curl sun-java6-bin sun-java6-jre sun-java6-jdk" - echo -e "\n $item For MRI & ree (if you wish to use it) you will need:" - echo -e "\n $ aptitude install curl bison build-essential zlib1g-dev libssl-dev libreadline5-dev libxml2-dev git-core" - echo -e "\n $item For IronRuby (if you wish to use it) you will need:" - echo -e "\n $ aptitude install curl mono-2.0-devel" + printf "\n\n$(tput setaf 2)Notes for ${system} $release$(tput sgr0)\n" + + rvm_aptitude_binary="$(command -v aptitude)" + rvm_emerge_binary="$(command -v emerge)" + rvm_pacman_binary="$(command -v pacman)" + rvm_yum_binary="$(command -v yum)" + + printf "\n $item curl is required.\n" + printf "\n $item patch is required (for ree, some ruby head's).\n" + printf "\n $item If you wish to install rbx and/or any MRI head (eg. 1.9.2-head) then you must install and use rvm 1.8.7 first.\n" + if [[ ! -z "$rvm_aptitude_binary" ]] ; then + printf "\n $item For JRuby (if you wish to use it) you will need:" + printf "\n $ aptitude install curl sun-java6-bin sun-java6-jre sun-java6-jdk" + + printf "\n $item For MRI & ree (if you wish to use it) you will need (depending on what you are installing):" + printf "\n $ aptitude install build-essential bison openssl libreadline5 libreadline-dev curl git-core zlib1g zlib1g-dev libssl-dev vim libsqlite3-0 libsqlite3-dev sqlite3 libreadline5-dev libreadline6-dev libxml2-dev git-core subversion autoconf" + + printf "\n $item For IronRuby (if you wish to use it) you will need:" + printf "\n $ aptitude install curl mono-2.0-devel" elif [[ ! -z "$rvm_emerge_binary" ]] ; then - echo -e " $item For JRuby (if you wish to use it) you will need:" - echo -e "\n $ emerge dev-java/sun-jdk dev-java/sun-jre-bin" - echo -e "\n $item For IronRuby (if you wish to use it) you will need:" - echo -e "\n $ emerge dev-lang/mono" + printf "\n $item For JRuby (if you wish to use it) you will need:" + printf "\n $ emerge dev-java/sun-jdk dev-java/sun-jre-bin" + + printf "\n $item For IronRuby (if you wish to use it) you will need:" + printf "\n $ emerge dev-lang/mono" elif [[ ! -z "$rvm_pacman_binary" ]] ; then - echo -e " $item For JRuby (if you wish to use it) you will need:" - echo -e "\n $ pacman -Sy jdk jre curl" - echo -e "\n $item For IronRuby (if you wish to use it) you will need:" - echo -e "\n $ pacman -Sy mono" + printf "\n $item For MRI based rubies you will need:" + printf "\n $ pacman -Sy autoconf diffutils patch curl bison zlib readline libxml2 git" + + printf "\n $item For JRuby (if you wish to use it) you will need:" + printf "\n $ pacman -Sy jdk jre curl" + + printf "\n $item For IronRuby (if you wish to use it) you will need:" + printf "\n $ pacman -Sy mono" elif [[ ! -z "$rvm_yum_binary" ]] ; then - echo -e " $item For MRI/ree (if you wish to use it) you will need:" - echo -e "\n $ yum install -y gcc-c++ patch readline readline-devel iconv-devel" - echo -e " $item For JRuby (if you wish to use it) you will need:" - echo -e "\n $ yum install -y java" + printf "\n $item For MRI/ree (if you wish to use it) you will need:" + printf "\n $ yum install -y gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel libffi-devel" + printf "\n $ yum install -y iconv-devel # NOTE: For centos 5.4 final iconv-devel might not be available :(" + + printf "\n $item For JRuby (if you wish to use it) you will need:" + printf "\n $ yum install -y java" else - echo -e " $item For JRuby (if you wish to use it) you will need:" - echo -e "\n The SUN java runtime environment and development kit." - echo -e "\n $item For IronRuby (if you wish to use it) you will need:" - echo -e "\n The Mono Runtime and Development Platform (version 2.6 or greater is recommended)." + printf "\n $item For JRuby (if you wish to use it) you will need:" + printf "\n The SUN java runtime environment and development kit." + printf "\n $item For IronRuby (if you wish to use it) you will need:" + printf "\n The Mono Runtime and Development Platform (version 2.6 or greater is recommended)." fi elif [[ "Darwin" = "$system" ]] ; then release="( $(sw_vers -productName) )" - echo -e "\n$(tput setaf 2)Notes for ${system} $release $(tput sgr0)\n" - echo -e "\n $item For Snow Leopard be sure to have XCode Tools Version 3.2.1 (1613) or later (there were bugs with the dvd release version)." - echo -e "\n $item You should download the latest XCode tools from developer.apple.com. This is necessary since the dvd install for Snow Leopard has bugs." - echo -e "\n $item If you intend on installing MacRuby you must install LLVM first." - echo -e "\n $item If you intend on installing JRuby you must install the JDK." - echo -e "\n $item If you intend on installing IronRuby you must install Mono (version 2.6 or greater is recommended)." + printf "\n$(tput setaf 2)Notes for ${system} $release $(tput sgr0)\n" + printf "\n $item For Snow Leopard be sure to have XCode Tools Version 3.2.1 (1613) or later (there were bugs with the dvd release version)." + printf "\n $item You should download the latest XCode tools from developer.apple.com. This is necessary since the dvd install for Snow Leopard has bugs." + printf "\n $item If you intend on installing MacRuby you must install LLVM first." + printf "\n $item If you intend on installing JRuby you must install the JDK." + printf "\n $item If you intend on installing IronRuby you must install Mono (version 2.6 or greater is recommended)." fi echo diff --git a/scripts/package b/scripts/package index a204d18ccf..9acb694d58 100755 --- a/scripts/package +++ b/scripts/package @@ -1,21 +1,17 @@ #!/usr/bin/env bash +rvm_base_except="selector" +source "$rvm_scripts_path/base" -# -# ruby dependency packages: -# +# Tools to make managing ruby dependencies inside of rvm easier. -source $rvm_scripts_path/initialize -source $rvm_scripts_path/utility - -trap "rm -f $rvm_tmp_path/$$* > /dev/null 2>&1 ; exit" 0 1 2 3 15 -if [[ ! -z "$rvm_trace_flag" ]] ; then set -x ; export rvm_trace_flag ; fi - -action="$(echo $* | awk '{print $1}')" -library="$(echo $* | awk '{print $2}')" +action="$(echo "$*" | awk '{print $1}')" +library="$(echo "$*" | awk '{print $2}')" args=$(echo "$*" | awk '{$1="" ; $2="" ; print}' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') install_package() { + __rvm_db "${package}_url" "package_url" + if [[ ! -z "$rvm_make_flags_flag" ]] ; then __rvm_make_flags ; fi __rvm_pushpop $rvm_src_path @@ -30,14 +26,14 @@ install_package() { __rvm_run "$package/extract" "tar jxf $rvm_archives_path/$package-$version.$archive_format -C $rvm_src_path" "Extracting $package-$version.$archive_format to $rvm_src_path" elif [[ "$archive_format" = "zip" ]] ; then $rvm_scripts_path/fetch "$package_url/$package-$version.$archive_format" || (result=$? && return $result) - __rvm_run "$package/extract" "unzip -q -o $rvm_archives_path/$package-$version.$archive_format -d $rvm_src_path/$package-$version" "Extracting $package-$version.$archive_format to $rvm_src_path" + __rvm_run "$package/extract" "unzip -q -o $rvm_archives_path/$package-$version.$archive_format -d $rvm_src_path/$package-$version" "Extracting $package-$version.$archive_format to $rvm_src_path" else - echo -e "Unrecognized archive format '$archive_format'" ; return 1 + printf "\nUnrecognized archive format '$archive_format'" ; return 1 fi builtin cd "$rvm_src_path/$package-$version" - __rvm_run "$package/configure" "${configure:-"./configure --prefix=$rvm_usr_path"} $configure_flags" "Configuring $package in $rvm_src_path/$package-$version." + __rvm_run "$package/configure" "${configure:-"./configure --prefix=${prefix_path:-"$rvm_usr_path"}"} $configure_flags" "Configuring $package in $rvm_src_path/$package-$version." unset configure_flags @@ -48,13 +44,14 @@ install_package() { __rvm_run "$package/make.install" "/usr/bin/make install" "Installing $package to $rvm_usr_path" fi - __rvm_pushpop + touch "$rvm_config_path/packages" + $rvm_scripts_path/db "$rvm_config_path/packages" "${package}" "${version}" + __rvm_pushpop } readline() { package="readline" ; archive_format="tar.gz" - package_url="ftp://ftp.gnu.org/gnu/readline" for version in 5.2 6.0 ; do configure_flags="--disable-dependency-tracking --disable-static --enable-shared" install_package @@ -63,56 +60,92 @@ readline() { iconv() { package="libiconv" ; version=1.13.1 ; archive_format="tar.gz" - package_url="http://ftp.gnu.org/pub/gnu/libiconv" install_package } curl() { package="curl" ; version=7.19.7 ; archive_format="tar.gz" - package_url="http://curl.haxx.se/download" install_package } openssl() { - if $rvm_scripts_path/match "$rvm_archflags" "x86_64" ; then - export openssl_os="os/compiler darwin64-x86_64-cc" + package="openssl" ; version="0.9.8n" ; archive_format="tar.gz" + if [[ "Darwin" = "$(uname)" ]] ; then + if [[ ! -z "$rvm_archflags" ]]; then + if $rvm_scripts_path/match "$rvm_archflags" "64"; then + hw_cpu64bit=1 + fi + if $rvm_scripts_path/match "$rvm_archflags" "ppc"; then + hw_machine="Power Macintosh" + fi + else + hw_machine=$(sysctl hw.machine | awk -F: '{print $2}' | sed 's/^ //') + hw_cpu64bit=$(sysctl hw.cpu64bit_capable | awk '{print $2}') + fi + if [[ "Power Macintosh" = "$hw_machine" ]] ; then + if [[ $hw_cpu64bit = 1 ]]; then + openssl_os="darwin64-ppc-cc" + else + openssl_os="darwin-ppc-cc" + fi + else + if [[ $hw_cpu64bit = 1 ]]; then + openssl_os="darwin64-x86_64-cc" + else + openssl_os="darwin-i386-cc" + fi + fi + configure_command="./Configure" + patches="$rvm_patches_path/$package/Makefile.org.patch,$rvm_patches_path/$package/crypto-Makefile.patch" + # Don't use -j option for make OpenSSL + if [[ ! -z "$rvm_make_flags" ]] ; then + rvm_make_flags=$(echo $rvm_make_flags | sed -e "s/-j[[:space:]]*[[0-9]]*//") + fi else - export openssl_os="os/compiler darwin-i386-cc" + configure_command="./config" fi - package="openssl" ; version="0.9.8k" ; archive_format="tar.gz" - package_url="http://www.openssl.org/source" - configure="./config --prefix=$rvm_usr_path zlib no-asm no-krb5 shared" + configure="$configure_command $openssl_os -I$rvm_usr_path/include -L$rvm_usr_path/lib --prefix=$rvm_usr_path zlib no-asm no-krb5 shared" install_package } zlib() { - package="zlib" ; version="1.2.3" ; archive_format="tar.gz" - package_url="http://www.zlib.net" + package="zlib" ; version="1.2.5" ; archive_format="tar.gz" + install_package +} + +autoconf() { + package="autoconf" ; version="2.65" ; archive_format="tar.gz" + prefix_path="${rvm_bin_path:-"${rvm_path:-"$HOME/.rvm"}"}" install_package } ncurses() { - package_url="ftp://invisible-island.net/ncurses/ncurses" package="ncurses" ; version="5.7" ; archive_format="tar.gz" configure_flags="--with-shared --disable-rpath --without-debug --without-ada --enable-safe-sprintf --enable-sigwinch --without-progs" install_package } pkgconfig() { - package_url="http://pkgconfig.freedesktop.org/releases" package="pkg-config" ; version="0.23" archive_format="tar.gz" install_package } gettext() { - package_url="ftp://ftp.gnu.org/pub/gnu/gettext" package="gettext" ; version="0.17" ; archive_format="tar.gz" install_package } +libxml2() { + package="libxml2" ; version="2.7.3" ; archive_format="tar.gz" + if [[ "Darwin" = "$(uname)" ]] ; then + configure="./configure --prefix=${rvm_usr_path} --build=i686-apple-darwin$(uname -r) --host=i686-apple-darwin$(uname -r)" + fi + install_package + unset prefix_path +} + glib() { package="glib" ; version="2.23.1" ; archive_format="tar.gz" - package_url="http://ftp.gnome.org/pub/gnome/sources/glib/2.23" configure="CC=\"cc -L$rvm_usr_path/lib\" ./configure --prefix=$rvm_usr_path" install_package @@ -125,17 +158,17 @@ mono() { __rvm_mono_env package="mono" ; version="2.6.1" ; archive_format="tar.bz2" - packge_url="http://ftp.novell.com/pub/mono/sources/mono/" - install_package } llvm() { + package="llvm" ; version="89156" if [[ ! -z "$rvm_make_flags_flag" ]] ; then __rvm_make_flags ; fi __rvm_pushpop $rvm_src_path if [[ ! -d "$rvm_src_path/llvm/.svn" ]] ; then + __rvm_db "${package}_url" "package_url" rm -rf "$rvm_src_path/llvm" - svn co -r 89156 https://llvm.org/svn/llvm-project/llvm/trunk llvm + svn co -r "$version" "$package_url" llvm builtin cd "$rvm_src_path/llvm" ./configure --enable-bindings=none UNIVERSAL=1 UNIVERSAL_ARCH="i386 x86_64" ENABLE_OPTIMIZED=1 make -j2 @@ -144,13 +177,14 @@ llvm() { __rvm_pushpop } -if [[ ! -z "$library" ]] && is_a_function ${library} ; then - ${library} -else - if [[ ! -z "$library" ]] ; then +if [[ ! -z "$library" ]] ; then + if [[ " readline iconv curl openssl zlib autoconf ncurses pkgconfig gettext glib mono llvm libxml2 " =~ "$library" ]] ; then + ${library} + else $rvm_scripts_path/log "error" "Package '${library}' is unknown." fi - $rvm_scripts_path/log "info" "Usage: 'rvm package {install,uninstall} {openssl,zlib,readline,iconv,ncurses}'" +else + $rvm_scripts_path/log "info" "Usage: 'rvm package {install,uninstall} {readline,iconv,curl,openssl,zlib,autoconf,ncurses,pkgconfig,gettext,glib,mono,llvm,libxml2}'" exit 1 fi diff --git a/scripts/patches b/scripts/patches new file mode 100644 index 0000000000..09bbb5762f --- /dev/null +++ b/scripts/patches @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +# General tools for manipulating patches +# and dealing with patches. + +# Returns the path used to look for a patch given a specific name. +__rvm_patch_lookup_path() { + echo "/" + [[ -n "$rvm_patch_original_pwd" ]] && echo "$rvm_patch_original_pwd/" + echo "$PWD/" + __rvm_ruby_string_paths_under "$rvm_patches_path" | sed 's/$/\//' +} + +__rvm_expand_patch_name() { + [[ -z "$1" ]] && return + expanded_patch_name="$($rvm_scripts_path/patchsets show "$1")" + if [[ "$?" == "0" ]]; then + echo "$expanded_patch_name" + elif [[ "$1" != "default" ]]; then + echo "$1" + fi + unset expanded_patch_name +} + +# Return the full patch for a given patch. +__rvm_lookup_full_patch_path() { + # Absolute path, pwd and then finally the rvm patches path. + for directory in $(__rvm_patch_lookup_path) ; do + for extension in {"",.patch,.diff}; do + patch_path="${directory}${1}${extension}" + if [[ -s "$patch_path" ]]; then + echo "$patch_path" + return + fi + done; unset extension patch_path + done; unset directory + return 1 +} diff --git a/scripts/patchsets b/scripts/patchsets new file mode 100755 index 0000000000..49f7173723 --- /dev/null +++ b/scripts/patchsets @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +rvm_base_except="selector" +source "$rvm_scripts_path/base" +source "$rvm_scripts_path/patches" + +lookup_patchset() { + if [[ -z "$1" ]]; then + echo "Usage: rvm patchset show name" + return 1 + fi + for lookup_path in $(__rvm_ruby_string_paths_under "$rvm_patchsets_path") ; do + if [[ -s "$lookup_path/$1" ]]; then + cat "$lookup_path/$1" + return + fi + done; unset lookup_path + return 1 +} + +# Return the full patch for a given patch. +__rvm_lookup_full_patch_path() { + # Absolute path, pwd and then finally the rvm patches path. + for directory in $(__rvm_patch_lookup_path) ; do + for extension in {"",.patch,.diff}; do + patch_path="${directory}${1}${extension}" + if [[ -s "$patch_path" ]]; then + echo "$patch_path" + return + fi + done; unset extension patch_path + done; unset directory + return 1 +} + +usage() { + echo "Usage: 'rvm patchset {show,lookup}'" + echo " Tools for manipulating patchsets." + return 1 +} + +case "$1" in + show|lookup) lookup_patchset "$2" ;; + *) usage ;; +esac + +exit $? diff --git a/scripts/rubygems b/scripts/rubygems new file mode 100755 index 0000000000..f17322eb5b --- /dev/null +++ b/scripts/rubygems @@ -0,0 +1,100 @@ +#!/usr/bin/env bash + +source "$rvm_scripts_path/base" + +result=0 + +__rvm_become + +rubygems_setup() { + __rvm_warn_on_rubyopt + unset RUBYOPT + if [[ ! -z "$(echo $rvm_ruby_version | awk '/^1\.9/')" ]] || [[ ! -z "$(echo $rvm_ruby_interpreter | awk '/^mput/')" ]] ; then + install=0 + elif [[ "$rvm_ruby_string" = "ruby-head" ]] ; then + install=0 + elif [[ -n "$(echo "$rvm_ruby_string" | awk '/^rbx|jruby|rubinius/')" ]]; then + install=0 + else + install=1 + fi + + if [[ "$install" -eq 0 ]] ; then + $rvm_scripts_path/log "error" "Cannot switch to ${version} for this interpreter." + exit 1 + else + $rvm_scripts_path/log "info" "Removing old Rubygems files..." + rubygems_dir="$(ruby -rrbconfig -e "puts Config::CONFIG.values_at('sitelibdir','vendorlibdir').detect {|path| File.directory?(File.join(path, 'rubygems')) }.to_s")" + if [[ -n "$rubygems_dir" && -d "$rubygems_dir" ]]; then + # Remove common files installed by ruby gems. + rm -rf "${rubygems_dir}/ubygems.rb" "${rubygems_dir}/rubygems.rb" "${rubygems_dir}/rubygems" "${rubygems_dir}/gauntlet_rubygems.rb" + fi + + $rvm_scripts_path/log "info" "Installing rubygems dedicated to $rvm_ruby_string..." + rvm_rubygems_version="$version" + rvm_gem_package_name="rubygems-$rvm_rubygems_version" + rvm_rubygems_url=$(__rvm_db "rubygems_${rvm_rubygems_version}_url") + rvm_gem_url="$rvm_rubygems_url/$rvm_gem_package_name.tgz" + + # Sanity check... If setup.rb is missing from the rubygems source path, + # something went wrong. Cleanup, aisle 3! + if [[ ! -f "$rvm_src_path/$rvm_gem_package_name/setup.rb" ]]; then + rm -rf "$rvm_src_path/$rvm_gem_package_name" + fi + + if [[ ! -d "$rvm_src_path/$rvm_gem_package_name" ]] ; then + $rvm_scripts_path/log "info" "Retrieving $rvm_gem_package_name" + $rvm_scripts_path/fetch "$rvm_gem_url" + result=$? ; if [[ "$result" -gt 0 ]] ; then + $rvm_scripts_path/log "error" "There has been an error while trying to fetch the source. Aborting the installation." ; __rvm_pushpop ; return $result + fi + mkdir -p "$rvm_src_path/$rvm_gem_package_name" + __rvm_run "rubygems.extract" "cat $rvm_archives_path/$rvm_gem_package_name.tgz | gunzip | tar xf - -C $rvm_src_path" "Extracting $rvm_gem_package_name ..." + fi + + builtin cd "$rvm_src_path/$rvm_gem_package_name" + + __rvm_run "rubygems.install" "GEM_PATH=$rvm_ruby_gem_path GEM_HOME=$rvm_ruby_gem_home BUNDLE_PATH=$rvm_ruby_gem_home $rvm_ruby_home/bin/ruby $rvm_src_path/$rvm_gem_package_name/setup.rb" "Installing rubygems for $rvm_ruby_home/bin/ruby" + result=$? + if [[ "$result" == 0 ]] ; then + $rvm_scripts_path/log "info" "Installation of rubygems completed successfully." + else + $rvm_scripts_path/log "warning" "Installation of rubygems did not complete successfully." + fi + + if [[ ! -z "$rvm_major_version" ]] ; then + ruby_lib_gem_path="$rvm_ruby_home/lib/ruby/gems/${rvm_release_version}.${rvm_major_version}" + else + ruby_lib_gem_path="$rvm_ruby_home/lib/ruby/gems/$interpreter" + fi + fi + + # Add ruby's gem path to ruby's lib direcotry. + mkdir -p "$(dirname $ruby_lib_gem_path)" + + if [[ -d "$ruby_lib_gem_path" ]] ; then rm -rf "$ruby_lib_gem_path" ; fi + + ln -nfs "$rvm_ruby_gem_home" "$ruby_lib_gem_path" + + unset ruby_lib_gem_path +} + +if ! command -v ruby > /dev/null ; then + $rvm_scripts_path/log "error" "'ruby' was not found, cannot install rubygems unless ruby is present (Do you have an RVM ruby installed & selected?)" + exit 1 +fi + +# +# rvm rubygems use X +# +if [[ $# -gt 0 ]] ; then + version="$1" ; shift + args="$(echo "$@" | __rvm_strip)" +else + $rvm_scripts_path/log "error" "A version must be specified, for example 'rvm rubygems 1.3.7'" + exit 1 +fi + +rubygems_setup + +exit $result diff --git a/scripts/rvm b/scripts/rvm index 52a0e93735..65a87c7241 100755 --- a/scripts/rvm +++ b/scripts/rvm @@ -1,28 +1,34 @@ #!/usr/bin/env bash -# rvm : Ruby Version Manager +# rvm : Ruby enVironment Manager # http://rvm.beginrescueend.com # http://gitub.com/wayneeseguin/rvm if [[ "$rvm_loaded_flag" != "1" ]] || [[ "$rvm_reload_flag" = "1" ]] ; then unset rvm_reload_flag - mkdir -p $HOME/.gem/cache - - if [[ -f /etc/rvmrc ]] ; then source /etc/rvmrc ; fi - if [[ -f "$HOME/.rvmrc" ]] ; then source "$HOME/.rvmrc" ; fi + for rvmrc in /etc/rvmrc $HOME/.rvmrc ; do + if [[ -f "$rvmrc" ]] ; then + if grep -q '^\s*rvm .*$' $rvmrc ; then + printf "\nError: $rvmrc is for rvm settings only.\nrvm CLI may NOT be called from within $rvmrc. \nSkipping the loading of $rvmrc" + return 1 + else + source "$rvmrc" + fi + fi + done if [[ -z "$rvm_prefix" ]] ; then if [[ "root" = "$(whoami)" ]] ; then rvm_prefix="/usr/local" else - rvm_prefix="$HOME" + rvm_prefix="$HOME/." fi fi if [[ -z "$rvm_path" ]] ; then unset rvm_path - if [[ "root" = "$(whoami)" ]] ; then + if [[ "root" = "$(whoami)" ]] ; then rvm_path="$rvm_prefix/rvm" else if [[ -d "$HOME/.rvm" ]] && [[ -s "$HOME/.rvm/scripts/rvm" ]]; then @@ -56,6 +62,7 @@ if [[ "$rvm_loaded_flag" != "1" ]] || [[ "$rvm_reload_flag" = "1" ]] ; then source $rvm_scripts_path/version source $rvm_scripts_path/selector source $rvm_scripts_path/cli + source $rvm_scripts_path/manpages source $rvm_scripts_path/cd rvm_loaded_flag=1 @@ -64,15 +71,11 @@ if [[ "$rvm_loaded_flag" != "1" ]] || [[ "$rvm_reload_flag" = "1" ]] ; then alias rvm-restart="source '${rvm_path}/scripts/rvm'" - if [[ -s "$HOME/.rvm/default" ]] ; then - source "$HOME/.rvm/default" - elif [[ -s "$rvm_config_path/default" ]] ; then - source "$rvm_config_path/default" - elif [[ -s "$rvm_prefix/rvm/config/default" ]] ; then - source "$rvm_prefix/rvm/config/default" + if ! command -v ruby >/dev/null 2>&1 || command -v ruby | grep -v rvm >/dev/null ; then + [[ -s "$rvm_environments_path/default" ]] && source "$rvm_environments_path/default" fi else - echo -e "\$rvm_path is not set. rvm cannot load." + printf "\n\$rvm_path is not set. rvm cannot load." fi fi diff --git a/scripts/selector b/scripts/selector index 3821207741..31c49494e2 100755 --- a/scripts/selector +++ b/scripts/selector @@ -31,7 +31,7 @@ __rvm_select() { else __rvm_db "macruby_version" "rvm_ruby_version" __rvm_db "macruby_url" "rvm_url" - rvm_ruby_package_name="MacRuby%200.5.zip" + rvm_ruby_package_name="MacRuby%20${rvm_ruby_version}.zip" rvm_ruby_package_file="$rvm_ruby_package_name" rvm_url="$rvm_url/$rvm_ruby_package_name" fi @@ -43,19 +43,19 @@ __rvm_select() { ;; rbx|rubinius) + rvm_archive_extension="tar.gz" rvm_ruby_interpreter="rbx" rvm_ruby_version=${rvm_ruby_version:-$(__rvm_db "rbx_version")} rvm_ruby_repo_url=${rvm_rbx_repo_url:-$(__rvm_db "rubinius_repo_url")} - __rvm_db "rbx_url" "rvm_url" if [[ -z "$rvm_head_flag" ]] ; then rvm_ruby_patch_level=${rvm_ruby_patch_level:-$(__rvm_db "rbx_patch_level")} - rvm_ruby_string="$rvm_ruby_interpreter-$rvm_ruby_version-p$rvm_ruby_patch_level" rvm_ruby_string="${rvm_ruby_string/-prc/-rc}" - rvm_ruby_string="$(echo $rvm_ruby_string | sed 's#-pp#-p#')" - rvm_ruby_file="rubinius-$rvm_ruby_version-$rvm_ruby_patch_level" + rvm_ruby_string="$(echo "$rvm_ruby_string" | sed 's#-p*#-#')" + rvm_ruby_package_file="$(echo "rubinius-${rvm_ruby_version}-${rvm_ruby_patch_level}.${rvm_archive_extension}" | sed 's#-p*#-#' )" + __rvm_db "rbx_url" "rvm_url" + rvm_url="$rvm_url/$rvm_ruby_package_file" else - unset rvm_ruby_patch_level - unset rvm_ruby_version + unset rvm_ruby_patch_level rvm_ruby_version rvm_ruby_string="$rvm_ruby_interpreter-head" fi ;; @@ -68,12 +68,14 @@ __rvm_select() { rvm_ruby_repo_url="${rvm_ruby_repo_url:-$(__rvm_db "jruby_repo_url")}" rvm_url="${rvm_ruby_repo_url:-$(__rvm_db "jruby_repo_url")}" else - rvm_archive_extension="zip" + rvm_archive_extension="tar.gz" rvm_ruby_version="${rvm_ruby_version:-"$(__rvm_db "jruby_version")"}" + jruby_url="$(__rvm_db "jruby_url")" rvm_ruby_package_file="${rvm_ruby_interpreter}-bin-${rvm_ruby_version}" rvm_ruby_package_name="${rvm_ruby_interpreter}-${rvm_ruby_version}" rvm_ruby_string="${rvm_ruby_interpreter}-${rvm_ruby_version}" - rvm_url="http://jruby.org.s3.amazonaws.com/downloads/${rvm_ruby_version}/${rvm_ruby_package_file}.tar.gz" + rvm_url="${jruby_url}/${rvm_ruby_version}/${rvm_ruby_package_file}.tar.gz" + unset jruby_url fi alias jruby_ng="jruby --ng" alias jruby_ng_server="jruby --ng-server" @@ -104,20 +106,20 @@ __rvm_select() { ironruby) unset rvm_ruby_patch_level if [[ "$rvm_head_flag" -eq 1 ]] ; then - export rvm_ruby_version="head" - export rvm_ruby_string="${rvm_ruby_interpreter}-${rvm_ruby_version}" - export rvm_ruby_package_name="${rvm_ruby_string}" - export rvm_ruby_repo_url="${rvm_ruby_repo_url:-$(__rvm_db "ironruby_repo_url")}" - export rvm_url="${rvm_ruby_repo_url:-$(__rvm_db "ironruby_repo_url")}" + rvm_ruby_version="head" + rvm_ruby_string="${rvm_ruby_interpreter}-${rvm_ruby_version}" + rvm_ruby_package_name="${rvm_ruby_string}" + rvm_ruby_repo_url="${rvm_ruby_repo_url:-$(__rvm_db "ironruby_repo_url")}" + rvm_url="${rvm_ruby_repo_url:-$(__rvm_db "ironruby_repo_url")}" else - export rvm_archive_extension="tar.gz" - export rvm_ruby_version=${rvm_ruby_version:-"$(__rvm_db "ironruby_version")"} - export rvm_ruby_string="${rvm_ruby_interpreter}-${rvm_ruby_version}" - sha1=$(curl -s http://github.com/api/v2/yaml/repos/show/ironruby/ironruby/tags | awk '/'${rvm_ruby_version}'/{print $NF}') - export rvm_ruby_package_file="ironruby-ironruby-${sha1:0:7}.${rvm_archive_extension}" - export rvm_ruby_package_name="ironruby-ironruby-${sha1:0:7}" - export rvm_url="$(__rvm_db "ironruby_url")v${rvm_ruby_version}" + rvm_archive_extension="zip" + rvm_ruby_version=${rvm_ruby_version:-"$(__rvm_db "ironruby_version")"} + rvm_ruby_string="${rvm_ruby_interpreter}-${rvm_ruby_version}" + rvm_ruby_package_name="${rvm_ruby_interpreter}-${rvm_ruby_version}" + rvm_ruby_package_file="${rvm_ruby_interpreter}-${rvm_ruby_version}.${rvm_archive_extension}" + rvm_url="$(__rvm_db "ironruby_${rvm_ruby_version}_url")${rvm_ruby_package_file}" fi + export rvm_ruby_version rvm_ruby_string rvm_ruby_package_name rvm_ruby_repo_url rvm_url rvm_archive_extension ;; ree) @@ -164,8 +166,8 @@ __rvm_select() { ;; current) - ruby_binary="$(which binary 2>/dev/null)" - if $rvm_scripts_path/match "$ruby_binary" "rvm" ; then + ruby_binary="$(command -v ruby)" + if [[ $? -eq 0 ]] && $rvm_scripts_path/match "$ruby_binary" "rvm" ; then rvm_ruby_string="$(dirname "$ruby_binary" | xargs dirname | xargs basename)" else rvm_ruby_interpreter="system" @@ -190,8 +192,9 @@ __rvm_select() { __rvm_gemset_select - if [[ ! -z "$rvm_ruby_interpreter" ]] && [[ "system" != "$rvm_ruby_interpreter" ]] && [[ "default" != "$rvm_ruby_interpreter" ]] ; then + if [[ -n "$rvm_ruby_interpreter" && "system" != "$rvm_ruby_interpreter" && "default" != "$rvm_ruby_interpreter" ]] ; then if [[ ! -z "$rvm_ruby_version" ]] ; then + rvm_release_version=$(echo $rvm_ruby_version | awk -F'.' '{ print $1 }') rvm_major_version=$(echo $rvm_ruby_version | awk -F'.' '{ print $2 }') rvm_minor_version=$(echo $rvm_ruby_version | awk -F'.' '{ print $3 }') fi @@ -199,10 +202,12 @@ __rvm_select() { rvm_ruby_package_name="${rvm_ruby_package_name:-$rvm_ruby_string}" rvm_ruby_home="$rvm_rubies_path/$rvm_ruby_string" rvm_ruby_log_path="$rvm_log_path/$rvm_ruby_string" + rvm_ruby_repo_path="$rvm_repo_path/$rvm_ruby_string" rvm_ruby_src_path="$rvm_src_path/$rvm_ruby_string" rvm_ruby_binary="$rvm_ruby_home/bin/ruby" rvm_ruby_irbrc="$rvm_ruby_home/.irbrc" rvm_ruby_gem_home="${rvm_gems_path}/${rvm_ruby_string}" + rvm_ruby_gem_path="${rvm_ruby_gem_home}:${rvm_ruby_gem_home}@global" if [[ "maglev" = "$rvm_ruby_interpreter" ]] ; then export MAGLEV_HOME="$rvm_ruby_home" @@ -210,14 +215,15 @@ __rvm_select() { fi if [[ ! -z "$rvm_gemset_name" ]] ; then - rvm_ruby_gem_home="${rvm_ruby_gem_home}%${rvm_gemset_name}" + rvm_ruby_gem_home="${rvm_ruby_gem_home}${rvm_gemset_separator}${rvm_gemset_name}" + rvm_ruby_gem_path="${rvm_ruby_gem_home}:${rvm_gems_path}/${rvm_ruby_string}${rvm_gemset_separator}global" fi rvm_ruby_selected_flag=1 mkdir -p $rvm_ruby_log_path - export rvm_ruby_interpreter rvm_ruby_version rvm_ruby_repo_url rvm_ruby_package_name rvm_url rvm_ruby_patch_level rvm_ruby_configure rvm_ruby_configure_flags rvm_ruby_make rvm_ruby_make_install rvm_ruby_revision rvm_ruby_tag rvm_major_version rvm_minor_version rvm_gemset_name rvm_gems_path rvm_ruby_gem_home rvm_path rvm_src_path rvm_bin_path rvm_ruby_binary rvm_ruby_home rvm_log_path rvm_ruby_log_path rvm_src_path rvm_ruby_src_path rvm_ruby_irbrc rvm_ruby_selected_flag rvm_ruby_string + export rvm_ruby_interpreter rvm_ruby_version rvm_ruby_repo_url rvm_ruby_package_name rvm_url rvm_ruby_patch_level rvm_ruby_configure rvm_ruby_configure_flags rvm_ruby_make rvm_ruby_make_install rvm_ruby_revision rvm_ruby_tag rvm_release_version rvm_major_version rvm_minor_version rvm_gemset_name rvm_gems_path rvm_ruby_gem_home rvm_path rvm_src_path rvm_bin_path rvm_ruby_binary rvm_ruby_home rvm_log_path rvm_ruby_log_path rvm_src_path rvm_ruby_src_path rvm_ruby_irbrc rvm_ruby_selected_flag rvm_ruby_string else rvm_ruby_interpreter="${rvm_ruby_interpreter:-system}" fi @@ -226,27 +232,9 @@ __rvm_select() { __rvm_use() { if [[ -z "$rvm_ruby_selected_flag" ]] ; then __rvm_select $* ; fi - if [[ -z "$rvm_ruby_interpreter" ]] ; then rvm_ruby_interpreter="default" ; fi - - if [[ "default" = "$rvm_ruby_interpreter" ]] ; then + if [[ -z "$rvm_ruby_interpreter" ]] ; then rvm_ruby_interpreter="system" ; fi - new_path="$(echo $PATH | tr ':' '\n' | awk '$0 !~ /rvm/' | paste -sd : -)" - new_path="$rvm_bin_path:$new_path" - - if [[ -s $rvm_config_path/default ]] ; then - unset new_path - source $rvm_config_path/default - if [[ ! -z "$rvm_verbose_flag" ]] ; then - $rvm_scripts_path/log "info" "Now using default ruby." - fi - else - rvm_ruby_interpreter="system" - $rvm_scripts_path/log "warn" "no default rvm specified, defaulting to pre-rvm system." - unset GEM_HOME GEM_PATH BUNDLE_PATH MY_RUBY_HOME RUBY_VERSION IRBRC - if [[ -s $rvm_config_path/system ]] ; then source $rvm_config_path/system ; fi - fi - - elif [[ "system" = "$rvm_ruby_interpreter" ]] ; then + if [[ "system" = "$rvm_ruby_interpreter" ]] ; then unset GEM_HOME GEM_PATH BUNDLE_PATH MY_RUBY_HOME RUBY_VERSION IRBRC new_path="$(echo $PATH | tr ':' '\n' | awk '$0 !~ /rvm/' | paste -sd : -)" @@ -261,8 +249,8 @@ __rvm_use() { fi if [[ "root" = "$(whoami)" ]] ; then - for binary in erb gem irb rake rdoc ri ruby testrb ; do - rm -f $rvm_symlink_path/$binary + for binary in ruby gem irb ri rdoc rake erb testrb ; do + rm -f "$rvm_bin_path/$binary" done fi @@ -294,56 +282,52 @@ __rvm_use() { fi fi + # Ensure the environment file for the selected ruby exists. + __rvm_ensure_has_enviroment_files + if [[ ! -z "$rvm_verbose_flag" ]] ; then - $rvm_scripts_path/log "info" "Now using $(echo $rvm_ruby_string | tr '-' ' ')" + $rvm_scripts_path/log "info" "Using $(basename $GEM_HOME | tr '-' ' ' | sed 's/'${rvm_gemset_separator}'/ with gemset /')" fi new_path="$(echo $PATH | tr ':' '\n' | awk '$0 !~ /rvm/' | paste -sd : -)" - new_path="$MY_RUBY_HOME/bin:$GEM_HOME/bin:$rvm_ruby_global_gems_path/bin:$rvm_bin_path:$new_path" + new_path="$GEM_HOME/bin:$rvm_ruby_global_gems_path/bin:$MY_RUBY_HOME/bin:$rvm_bin_path:$new_path" fi + # Export ruby string and gem set me for extrenal scripts to take advantage of them. + if [[ ! -z "$rvm_ruby_string" ]] ; then export rvm_ruby_string ; fi + if [[ ! -z "$rvm_gemset_name" ]] ; then export rvm_gemset_name ; fi + if [[ ! -z "$new_path" ]] ; then export PATH="$new_path" ; unset new_path ; fi + if [[ ! -z "$rvm_rvmrc_flag" ]] ; then __rvm_set_rvmrc ; fi + + environment_id="$(__rvm_environment_identifier)" + if [[ ! -z "$rvm_default_flag" ]] && [[ "default" != "$rvm_ruby_interpreter" ]] ; then if [[ "root" = "$(whoami)" ]] ; then - for binary in erb gem irb rake rdoc ri ruby testrb ; do - rm -f $rvm_symlink_path/$binary - ln -nfs $rvm_ruby_home/bin/$binary $rvm_symlink_path/$binary - rm -f $rvm_symlink_path/passenger_ruby - ln -nfs $rvm_bin_path/$rvm_ruby_string $rvm_symlink_path/passenger_ruby - done + # Sets up the default wrappers. + $rvm_scripts_path/wrapper "$rvm_ruby_string" fi - if [[ "system" = "$rvm_ruby_interpreter" ]] ; then + $rvm_scripts_path/alias delete default &> /dev/null rm -f $rvm_config_path/default rm -f $rvm_bin_path/default* + rm -f $rvm_environments_path/default + rm -f $rvm_wrappers_path/default else RUBY_VERSION="$($rvm_ruby_home/bin/ruby -v | sed 's#^\(.*\) (.*$#\1#')" export GEM_HOME GEM_PATH BUNDLE_PATH MY_RUBY_HOME RUBY_VERSION - - echo "export PATH=\"$rvm_ruby_home/bin:$rvm_ruby_gem_home/bin:$rvm_ruby_global_gems_path/bin:$rvm_bin_path:\$PATH\"" > $rvm_config_path/default - - for variable in RUBY_VERSION GEM_HOME GEM_PATH BUNDLE_PATH MY_RUBY_HOME IRBRC rvm_ruby_string rvm_gemset_name MAGLEV_HOME ; do - eval "export $variable" - eval value=\$${variable} - if [[ ! -z "$value" ]] ; then - echo "export ${variable}='$value'" >> $rvm_config_path/default - else - echo "unset ${variable}" >> $rvm_config_path/default - fi - done ; unset variable value - - if [[ ! -z "$rvm_default_flag" ]] ; then $rvm_scripts_path/symlink "default" ; fi + $rvm_scripts_path/alias delete default &> /dev/null + $rvm_scripts_path/alias create default "$environment_id" >& /dev/null + ln -nfs $rvm_environments_path/$environment_id $rvm_environments_path/default + ln -nfs $rvm_wrappers_path/$environment_id $rvm_wrappers_path/default fi + fi ; unset rvm_default_flag + + if [[ ! -z "$rvm_wrapper_name" ]] ; then + $rvm_scripts_path/wrapper "$environment_id" "$rvm_wrapper_name" > /dev/null 2>&1 + unset rvm_wrapper_name fi - unset rvm_default_flag - if [[ ! -z "$rvm_symlink_name" ]] ; then $rvm_scripts_path/symlink "$rvm_symlink_name" ; unset rvm_symlink_name ; fi - if [[ ! -z "$rvm_editor_flag" ]] ; then $rvm_scripts_path/symlink "editor" ; unset rvm_editor_flag ; fi - if [[ ! -z "$rvm_passenger_flag" ]] ; then $rvm_scripts_path/symlink "passenger" ; unset rvm_passenger_flag ; fi - if [[ ! -z "$rvm_rvmrc_flag" ]] ; then __rvm_set_rvmrc ; fi - # Export ruby string and gem set name for extrnal scripts to take advantage of them. - if [[ ! -z "$rvm_ruby_string" ]] ; then export rvm_ruby_string ; fi - if [[ ! -z "$rvm_gemset_name" ]] ; then export rvm_gemset_name ; fi - if [[ ! -z "$new_path" ]] ; then export PATH="$new_path" ; unset new_path ; fi + unset environment_id if [[ "maglev" = "$rvm_ruby_interpreter" ]] ; then export MAGLEV_HOME="$rvm_ruby_home" @@ -354,7 +338,7 @@ __rvm_use() { fi fi - $rvm_scripts_path/hook "after_use" + rvm_hook="after_use" ; source $rvm_scripts_path/hook } __rvm_ruby_string() { @@ -365,11 +349,22 @@ __rvm_ruby_string() { # * rvm_ruby_patch_level # * rvm_ruby_revision # * rvm_ruby_tag - # * rvm_ruby_patch - set_name=$(echo "$rvm_ruby_string" | awk -F'%' '{print $2}') + # Alias'd rubies + if [[ -z "$rvm_expanding_aliases" ]]; then + rvm_ruby_string="${rvm_ruby_string:-"default"}" + expanded_alias_name="$($rvm_scripts_path/alias show "$rvm_ruby_string" 2>/dev/null)" + if [[ -n "$expanded_alias_name" ]]; then + rvm_ruby_string="$expanded_alias_name" + elif [[ "$rvm_ruby_string" = default ]]; then + # Default is not a known value. Instead, we need to therefore set it to system. + rvm_ruby_string="system" + fi + fi + + set_name=$(echo "$rvm_ruby_string" | awk -F${rvm_gemset_separator} '{print $2}') if [[ ! -z "$set_name" ]] ; then rvm_gemset_name="$set_name" ; fi - ruby_string=$(echo "$rvm_ruby_string" | awk -F'%' '{print $1}') + ruby_string=$(echo "$rvm_ruby_string" | awk -F${rvm_gemset_separator} '{print $1}') __rvm_unset_ruby_variables @@ -378,10 +373,6 @@ __rvm_ruby_string() { rvm_ruby_revision="head" unset rvm_ruby_patch_level rvm_ruby_revision rvm_ruby_tag export rvm_head_flag=1 - elif [[ "default" = "$string" ]] ; then - rvm_ruby_interpreter="default" - unset rvm_ruby_patch_level rvm_ruby_tag rvm_head_flag rvm_ruby_revision rvm_ruby_version rvm_gemset_name - return elif [[ "system" = "$string" ]] ; then rvm_ruby_interpreter="system" unset rvm_ruby_patch_level rvm_ruby_tag rvm_head_flag rvm_ruby_revision rvm_ruby_version rvm_gemset_name @@ -403,6 +394,8 @@ __rvm_ruby_string() { if [[ "ree" = "$rvm_ruby_interpreter" ]] ; then rvm_ruby_patch_level="$string" unset rvm_ruby_revision + elif [[ "rbx" = "$rvm_ruby_interpreter" ]] ; then + rvm_ruby_patch_level="$string" elif [[ "maglev" = "$rvm_ruby_interpreter" ]] ; then rvm_ruby_version="$string" unset rvm_ruby_revision rvm_ruby_patch_level @@ -420,9 +413,6 @@ __rvm_ruby_string() { rvm_ruby_tag="$string" elif $rvm_scripts_path/match "$string" "^m[0-9]" ; then rvm_ruby_mode="$string" - elif $rvm_scripts_path/match "$string" "^h[a-z0-9]" ; then - unset rvm_ruby_patch_level rvm_ruby_revision rvm_ruby_tag - rvm_ruby_patch="$string" elif $rvm_scripts_path/match "$string" "^u[a-z0-9]" ; then unset rvm_ruby_patch_level rvm_ruby_revision rvm_ruby_tag rvm_ruby_patch rvm_ruby_user_tag="$string" @@ -472,11 +462,22 @@ __rvm_ruby_string() { rvm_ruby_string="${rvm_ruby_string}-${rvm_ruby_user_tag}" else patch_level="$(__rvm_db "${rvm_ruby_interpreter}_${rvm_ruby_version}_patch_level")" - if [[ ! -z "$patch_level" ]] ; then rvm_ruby_patch_level="p${patch_level}" ; fi + if [[ ! -z "$patch_level" ]] ; then + if [[ "ree" = "$rvm_ruby_interpreter" ]] || [[ "rbx" = "$rvm_ruby_interpreter" ]] ; then + rvm_ruby_patch_level="${patch_level}" + else + rvm_ruby_patch_level="p${patch_level}" + fi + fi if [[ ! -z "$rvm_ruby_patch_level" ]] ; then rvm_ruby_patch_level="$(echo $rvm_ruby_patch_level | sed 's#^pp#p#')" rvm_ruby_string="${rvm_ruby_string}-${rvm_ruby_patch_level}" - rvm_ruby_string="$(echo $rvm_ruby_string | sed 's#-pp#-p#')" + if [[ "ree" = "$rvm_ruby_interpreter" ]] || [[ "rbx" = "$rvm_ruby_interpreter" ]] ; then + rvm_ruby_string="$(echo $rvm_ruby_string | sed 's#-p*#-#')" + else + rvm_ruby_string="$(echo $rvm_ruby_string | sed 's#-pp#-p#')" + rvm_ruby_string="$(echo $rvm_ruby_string | sed 's#-prc#-rc#')" + fi fi fi } diff --git a/scripts/set b/scripts/set index adf85f5d33..7bc1906554 100755 --- a/scripts/set +++ b/scripts/set @@ -1,62 +1,65 @@ #!/usr/bin/env bash -source $rvm_scripts_path/initialize -source $rvm_scripts_path/utility -source $rvm_scripts_path/selector +source "$rvm_scripts_path/base" -if [[ ! -z "$rvm_trace_flag" ]] ; then set -x ; export rvm_trace_flag ; fi - -trap "if [[ -d $rvm_tmp_path/ ]] && [[ -s $rvm_tmp_path/$$ ]] ; then rm -f $rvm_tmp_path/$$ > /dev/null 2>&1 ; fi ; exit" 0 1 2 3 15 - -action="$1" ; shift -args="$*" -if [[ -z "$action" ]] ; then +if [[ -z "$1" ]] ; then $rvm_scripts_path/log "error" "Action must be specified." exit 1 fi +action="$1" ; shift +args="$*" + +__rvm_attempt_single_exec() { + # Return if we have multiple rubies. or we're not running exec. + if [[ "$action" != "exec" ]] || $rvm_scripts_path/match "$rvm_ruby_strings" ' '; then + return 1 + fi + __rvm_become "$rvm_ruby_strings" + eval "exec $args" +} + # Perform an action using one of a selected ruby's specified binaries. __rvm_ruby_do() { - __rvm_select - __rvm_use - - binary="$(echo $action | sed 's#do$##')" - if [[ -x "$rvm_ruby_home/bin/$binary" ]] ; then - rm -f "$rvm_path/gems/cache" - ln -nfs "$HOME/.gem/cache" "$rvm_path/gems/cache" - binary="$rvm_ruby_home/bin/$binary" - elif [[ -x "$rvm_ruby_global_gems_path/bin/$binary" ]] ; then - binary="$rvm_ruby_global_gems_path/bin/$binary" - elif [[ -x "$rvm_ruby_gem_home/bin/$binary" ]] ; then - binary="$rvm_ruby_gem_home/bin/$binary" - elif [[ "system" = "$rvm_ruby_string" ]] && [[ -x "$(which $binary)" ]] ; then - binary="$(basename $(which $binary 2>/dev/null) 2>/dev/null)" + # Return on invalid rubies. + __rvm_become "$current_set_ruby" || return 1 + if [[ "$action" = "exec" ]]; then + # Exec is a special case. + rvm_command="$args" else - $rvm_scripts_path/log "warn" "'$binary not found for $rvm_ruby_string' either does not exist or is not executable? :(" - __rvm_unset_ruby_variables - return 1 - fi + binary="$(echo $action | sed 's#do$##')" + if [[ -x "$rvm_ruby_home/bin/$binary" ]] ; then + binary="$rvm_ruby_home/bin/$binary" + elif [[ -x "$rvm_ruby_global_gems_path/bin/$binary" ]] ; then + binary="$rvm_ruby_global_gems_path/bin/$binary" + elif [[ -x "$rvm_ruby_gem_home/bin/$binary" ]] ; then + binary="$rvm_ruby_gem_home/bin/$binary" + elif [[ "system" = "$rvm_ruby_string" ]] && [[ -x "$(command -v $binary)" ]] ; then + binary="$(basename $(command -v $binary) 2>/dev/null)" + else + $rvm_scripts_path/log "warn" "'$binary not found for $rvm_ruby_string' either does not exist or is not executable? :(" + __rvm_unset_ruby_variables + return 1 + fi - if [[ ! -z "$rvm_ruby_mode" ]] ; then - rvm_ruby_string="${rvm_ruby_string}-${rvm_ruby_mode}" - rvm_ruby_mode="--$(echo $rvm_ruby_mode | sed 's/^m//')" - fi + if [[ ! -z "$rvm_ruby_mode" ]] ; then + rvm_ruby_string="${rvm_ruby_string}-${rvm_ruby_mode}" + rvm_ruby_mode="--$(echo "$rvm_ruby_mode" | sed 's/^m//')" + fi - load_path="$(dirname $(which $binary 2>/dev/null) 2>/dev/null):$rvm_ruby_load_path" - # TODO: the else case below should be run if $args =~ /\.rb$/ - if [[ "ruby" = "$(basename $binary)" ]] && [[ "$rvm_benchmark_flag" -ne 1 ]] ; then - if $rvm_scripts_path/match "$args" "\.rb$" ; then - if [[ -z "$prefix" ]] ; then prefix="-S" ; fi - if ! $rvm_scripts_path/match "$args" "$prefix" ; then - args="$prefix $args" + load_path="$(dirname $(command -v $binary) 2>/dev/null):$rvm_ruby_load_path" + # TODO: the else case below should be run if $args =~ /\.rb$/ + if [[ "ruby" = "$(basename $binary)" ]] && [[ "$rvm_benchmark_flag" -ne 1 ]] ; then + if $rvm_scripts_path/match "$args" "\.rb$" ; then + if [[ -z "$prefix" ]] ; then prefix="-S" ; fi + if ! $rvm_scripts_path/match "$args" "$prefix" ; then + args="$prefix $args" + fi fi + rvm_command="$binary $rvm_ruby_mode $rvm_ruby_require -I$load_path $args" + else + rvm_command="$binary $rvm_ruby_mode $args" fi - rvm_command="$binary $rvm_ruby_mode $rvm_ruby_require -I$load_path $args" - elif [[ "gem" = "$(basename $binary)" ]] && $rvm_scripts_path/match "$args" '^install' ; then - #$rvm_scripts_path/gem install $args - rvm_command="$rvm_scripts_path/gemsets $rvm_ruby_mode $args $rvm_gem_options" - else - rvm_command="$binary $rvm_ruby_mode $args" fi if [[ ! -z "$rvm_json_flag" ]] || [[ ! -z "$rvm_yaml_flag" ]] || [[ ! -z "$rvm_summary_flag" ]] ; then @@ -64,7 +67,14 @@ __rvm_ruby_do() { touch ./log/$rvm_ruby_string/$action.log ./log/$rvm_ruby_string/$action.error.log eval "$rvm_command" >> ./log/$rvm_ruby_string/$action.log 2>> ./log/$rvm_ruby_string/$action.error.log else - $rvm_scripts_path/log "info" "$rvm_ruby_string: $($rvm_ruby_home/bin/ruby -v $rvm_ruby_mode | tr "\n" ' ')" + if [[ "$rvm_verbose_flag" != "0" ]] ; then + current_env="$(__rvm_environment_identifier)" + if [[ "$current_env" != "$current_set_ruby" ]]; then + current_env="$current_set_ruby ($current_env)" + fi + $rvm_scripts_path/log "info" "$current_env: $(ruby -v $rvm_ruby_mode | tr "\n" ' ')\n" + unset current_env + fi eval "$rvm_command" fi result=$? @@ -93,7 +103,7 @@ __rvm_summary() { fi total=${#rubies[*]} if [[ ! -z "$ZSH_VERSION" ]] ; then array_start=1 ; else array_start=0 ; fi - echo -e "$summary" | tee -a log/summary.log + printf "$summary" | tee -a log/summary.log return ${#errors[*]} } @@ -114,7 +124,7 @@ __rvm_yaml() { yaml="$yaml\n \"${rubies[$index]}\": ${statuses[$index]}" done ; unset index array_start mkdir -p log - echo -e "$yaml" | tee -a log/summary.yaml + printf "$yaml" | tee -a log/summary.yaml return ${#errors[*]} } @@ -122,9 +132,9 @@ __rvm_yaml() { # Output the summary in a json format. __rvm_json() { json="{" - json="$json\n \"totals\": { \"rubies\": ${#rubies[*]}, \"successes\": ${#successes[*]}, \"errors\": ${#errors[*]}}," - json="$json\n \"successful\": [ "$(echo ${successes[*]} | sed 's# #", "#g')" ]," - json="$json\n \"errors\": [ "$(echo ${errors[*]} | sed 's# #", "#g')" ]," + json="$json\n \"totals\": { \"rubies\": ${#rubies[*]}, \"successes\": ${#successes[*]}, \"errors\": ${#errors[*]} }," + json="$json\n \"successful\": [$(echo \"${successes[*]}\" | sed 's# #", "#g' | sed 's#\"\"##')]," + json="$json\n \"errors\": [$(echo \"${errors[*]}\" | sed 's# #", "#g' | sed 's#\"\"##')]," json="$json\n \"rubies\": {" total=${#rubies[*]} @@ -139,41 +149,30 @@ __rvm_json() { json="$json\n }\n}" mkdir -p log - echo -e "$json" | tee -a log/summary.json + printf "$json" | tee -a log/summary.json return ${#errors[*]} } # Loop over a set or all rvm installed rubies to perform some action. # Record the results and report based on CLI selections. -#__rvm_do() { + rubies=() ; successes=() ; errors=() ; statuses=() -# TODO: Extract the common functionality out of the if below -if [[ ! -z "$rvm_ruby_string" ]] ; then - unset rvm_ruby_interpreter rvm_ruby_version + +rvm_ruby_strings="${rvm_ruby_strings:-"$($rvm_scripts_path/list strings)"}" +rvm_ruby_strings="$(echo "$rvm_ruby_strings" | tr ',' ' ')" + +# Check for a single ruby && exec if present. +__rvm_attempt_single_exec + +for current_set_ruby in ${rvm_ruby_strings} ; do __rvm_ruby_do -elif [[ ! -z "$rvm_ruby_version" ]] ;then - for rvm_ruby_string in $(echo $rvm_ruby_version | tr ',' ' ') ; do - __rvm_ruby_do - done -elif [[ ! -z "$rvm_ruby_interpreter" ]] ; then - unset rvm_ruby_string rvm_ruby_version - __rvm_ruby_do -else # all - for full_binary in $rvm_rubies_path/*/bin/ruby ; do - if [[ -x "$full_binary" ]] ; then - rvm_ruby_string="$(dirname $full_binary | xargs dirname | xargs basename)" - __rvm_ruby_do - fi - done ; unset full_binary -fi +done; unset current_set_ruby if [[ ! -z "$rvm_summary_flag" ]] ; then __rvm_summary ; fi if [[ ! -z "$rvm_yaml_flag" ]] ; then __rvm_yaml ; fi if [[ ! -z "$rvm_json_flag" ]] ; then __rvm_json ; fi -$rvm_scripts_path/hook "after_do" +rvm_hook="after_do" ; source $rvm_scripts_path/hook exit ${#errors[*]} -#} - diff --git a/scripts/symlink b/scripts/symlink deleted file mode 100755 index e22e0c0759..0000000000 --- a/scripts/symlink +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -if [[ "$rvm_trace_flag" -eq 1 ]] ; then set -x ; export rvm_trace_flag ; fi - -trap "rm -f $rvm_tmp_path/$$* > /dev/null 2>&1 ; exit" 0 1 2 3 15 - -flag="$1" ; symlink_flag=0 -if [[ -s "$rvm_bin_path/$rvm_ruby_string" ]] ; then - rm -f ${rvm_bin_path}/${flag}_* - ln -fs "$rvm_bin_path/$rvm_ruby_string" "$rvm_bin_path/${flag}_ruby" - for binary in gem irb rake ; do - ln -fs "$rvm_ruby_home/bin/${binary}" "$rvm_bin_path/${flag}_${binary}" - done - exit 0 -else - $rvm_scripts_path/log "error" "Cannot set ${flag}_ruby since $rvm_bin_path/$rvm_ruby_string is missing." - exit 1 -fi diff --git a/scripts/tools b/scripts/tools new file mode 100755 index 0000000000..de58990bf2 --- /dev/null +++ b/scripts/tools @@ -0,0 +1,34 @@ +source "$rvm_scripts_path/base" + +usage() { + echo "Usage: rvm tools {identifier,path-identifier}" 1>&2 + exit 1 +} + +# Return the identifier that's current in use. +tools_identifier() { + __rvm_environment_identifier +} + +tools_path_identifier() { + if [[ -z "$1" || ! -d "$1" ]]; then + echo "Usage: rvm tools path-identifier 'path-to-heck'" + return 1 + fi + # Change to the directory. Do in subshell to keep the env correct. + (source $rvm_scripts_path/rvm + cd "$1" >/dev/null 2>&1 + __rvm_environment_identifier) +} + +[[ -z "$1" ]] && usage + +action="$1"; shift + +case "$action" in + identifier) tools_identifier ;; + path-identifier) tools_path_identifier "$@" ;; + *) usage ;; +esac + +exit $? diff --git a/scripts/utility b/scripts/utility index 53bbc899fa..7c7d5ca796 100644 --- a/scripts/utility +++ b/scripts/utility @@ -1,5 +1,54 @@ #!/usr/bin/env bash +__rvm_setup() { + # ZSH has 1 based array indexing, bash has 0 based. + if [[ ! -z "$ZSH_VERSION" ]] ; then + __shell_array_start=1 + # Set clobber for zsh users, for compatibility with bash's append operator ( >> file ) behavior + setopt | grep -qs '^noclobber$' + rvm_zsh_clobber=$? + setopt clobber + else + __shell_array_start=0 + fi ; export __shell_array_start +} + +__rvm_teardown() { + if [[ ! -z "$ZSH_VERSION" ]] ; then + if [[ "$rvm_zsh_clobber" -eq 0 ]] ; then + setopt noclobber + fi ; unset rvm_zsh_clobber + else + : + fi + # Ruby strings are scoped to their action. + # Hence, we ensure we remove them at in + # the cleanup phase. + + # Clean up after CC switch + if [[ -n "$rvm_clang_flag" ]] ; then + if [[ -n "$rvm_prior_cc" ]] ; then + export CC="$rvm_prior_cc" + else + unset CC + fi + unset rvm_prior_cc + fi + + unset rvm_ruby_strings +} + +# Return a list of directories under a given base path. +# Derived from rvm_ruby_string. +__rvm_ruby_string_paths_under() { + local patch_parts="$(echo "$rvm_ruby_string" | tr '-' ' ' | __rvm_strip)" + while true; do + echo "$1/$patch_parts" | tr ' ' '/' | sed 's#\/$##' + [[ -z "$patch_parts" ]] && break + patch_parts="$(echo "$patch_parts" | awk '{$NF=""; print}' | __rvm_strip)" + done +} + # Query the rvm key-value database for a specific key # Allow overrides from user specifications in $rvm_config_path/user __rvm_db() { @@ -16,7 +65,7 @@ __rvm_db() { if [[ -z $variable ]] ; then echo $value else - eval "$variable=$value" + eval "$variable='$value'" fi fi unset key value variable @@ -24,106 +73,35 @@ __rvm_db() { is_a_function() { type $1 | head -n 1 | grep -q "function" ; } -# Ouput rvm environment information. -__rvm_info() { - - if [[ ! -z "$rvm_ruby_args" ]] ; then - echo $(rvm_ruby_string="$rvm_ruby_args"; __rvm_select ; __rvm_use ; __rvm_environment_info) - echo -e $info ; unset info - else - __rvm_environment_info - fi - -} - -__rvm_environment_info() { - if [[ ! -z "$(/usr/bin/which ruby 2>/dev/null)" ]] ; then full_version=$(ruby -v) ; fi - echo -e "system:\n uname: \"$(uname -a)\"" - - if [[ ! -z "$ZSH_VERSION" ]] ; then echo -e " shell: \"zsh\"\n version: \"$ZSH_VERSION\"" ; fi - if [[ ! -z "$BASH_VERSION" ]] ; then echo -e " shell: \"bash\"\n version: \"$BASH_VERSION\"" ; fi - - cat </dev/null)" - irb: "$(which irb 2>/dev/null)" - gem: "$(which gem 2>/dev/null)" - rake: "$(which rake 2>/dev/null)" - -environment: - GEM_HOME: "$GEM_HOME" - GEM_PATH: "$GEM_PATH" - BUNDLE_PATH: "$BUNDLE_PATH" - MY_RUBY_HOME: "$MY_RUBY_HOME" - IRBRC: "$IRBRC" - -Info - if [[ ! -z "$MAGLEV_HOME" ]] ; then info="$info\n MAGLEV_HOME: \"$MAGLEV_HOME\"" ; fi - - unset full_version -} - -# Output debugging information that has been found useful to help people identify and resolve issues. -__rvm_debug() { - __rvm_version - __rvm_environment_info - $rvm_scripts_path/log "debug" "PATH:\n$(echo $PATH | awk -F":" '{print $1":"$2":"$3":"$4":"$5}')" - $rvm_scripts_path/log "debug" "uname -a: $(uname -a)" - $rvm_scripts_path/log "debug" "permissions: $(ls -la $rvm_path{,/rubies})" - - if [[ "Darwin" = "$(uname)" ]] ; then - $rvm_scripts_path/log "debug" "uname -r: $(uname -r)" - $rvm_scripts_path/log "debug" "uname -m: $(uname -m)" - $rvm_scripts_path/log "debug" "sw_vers: $(sw_vers | tr "\n" ',')" - $rvm_scripts_path/log "debug" "ARCHFLAGS: $ARCHFLAGS" - $rvm_scripts_path/log "debug" "LDFLAGS: $LDFLAGS" - $rvm_scripts_path/log "debug" "CFLAGS: $CFLAGS" - $rvm_scripts_path/log "debug" "/Developer/SDKs/*:$(/usr/bin/basename -a /Developer/SDKs/* | tr "\n" ',')" - fi - - for file_name in $(echo $rc_files) ; do - if [[ -s "$file_name" ]] ; then - $rvm_scripts_path/log "debug" "$file_name:\n$(grep 'rvm' $file_name 2>/dev/null)" +__rvm_quote_args() { + local quoted_string="" + for quoted_argument in "$@"; do + if printf "%s" "$quoted_argument" | grep -vq "^[[:alnum:]]$"; then + quoted_string="$quoted_string '$(printf "%s" "$quoted_argument" | sed "s/'/\'\\\'\'/g")'" + else + quoted_string="$quoted_string $quoted_argument" fi done + echo "$quoted_string" | sed -e 's/^ *//g' -e 's/ *$//g' +} - if [[ "root" = "$(whoami)" ]] ; then - debug_files="$rvm_config_path/default $rvm_config_path/system $rvm_config_path/db /etc/rvmrc /etc/gemrc" +__rvm_warn_on_rubyopt() { + if [[ -n "$RUBYOPT" ]]; then + $rvm_scripts_path/log "warn" "Please note: You have the RUBYOPT environment variable set and this may interfere with normal rvm operations. We sugges unsetting it." + return 1 else - debug_files="$rvm_config_path/default $rvm_config_path/system $rvm_config_path/db $HOME/.rvmrc $HOME/.gemrc" + return 0 fi - - for file_name in $(echo $debug_files); do - if [[ -f "$file_name" ]] && [[ -s "$file_name" ]] ; then - $rvm_scripts_path/log "debug" "$file_name (filtered):\n$(cat $file_name | awk '!/assword|_key/')\n" - fi - done - - $rvm_scripts_path/log "debug" "gem sources:\n$(gem sources | awk '/gems/')" } __rvm_strings() { unset results for rvm_ruby_string in $(echo $rvm_ruby_args) ; do - __rvm_ruby_string + #__rvm_ruby_string if [[ $? -gt 0 ]] ; then return 1 else results="$results $(__rvm_select ; echo $rvm_ruby_string)" - unset rvm_ruby_string fi done echo $results @@ -131,9 +109,6 @@ __rvm_strings() { return 0 } -# ZSH has 1 based array indexing, bash has 0 based. -if [[ ! -z "$ZSH_VERSION" ]] ; then __shell_array_start=1 ; else __shell_array_start=0 ; fi - # Push an item onto a given array. __rvm_push() { array=$1 ; shift ; item=$2 @@ -176,6 +151,28 @@ __rvm_run() { unset log_file command } +# Runs a command in a given env. +__rvm_run_with_env() { + log_file_name="$1" ; env_name="$2" ; command="$3" ; message="$4" + if [[ -z "$env_name" ]]; then env_name="$(__rvm_environment_identifier)"; fi + if [[ -z "$rvm_ruby_log_path" ]] ; then rvm_ruby_log_path="$rvm_log_path" ; fi + if [[ ! -z "$message" ]] ; then $rvm_scripts_path/log "info" "$message" ; fi + if [[ ! -z "$rvm_debug_flag" ]] ; then + $rvm_scripts_path/log "debug" "Executing: $command in environment "$env_name"" + fi + + mkdir -p "$(dirname "$rvm_ruby_log_path/$log_file_name.log")" + touch "$rvm_ruby_log_path/$log_file_name.log" "$rvm_ruby_log_path/$log_file_name.error.log" # for zsh :( + echo "[$(date +'%Y-%m-%d %H:%M:%S')] $command # under $env_name" | tee "$rvm_ruby_log_path/$log_file_name.log" >> "$rvm_ruby_log_path/$log_file_name.error.log" + if [[ -z "$rvm_niceness" ]] || [[ "0" = "$rvm_niceness" ]] ; then + eval "__rvm_with_env '$env_name' '$command'" >> "$rvm_ruby_log_path/$log_file_name.log" 2>> "$rvm_ruby_log_path/$log_file_name.error.log" + else + eval "nice -n $rvm_niceness __rvm_with_env '$env_name' '$command'" >> $rvm_ruby_log_path/$log_file_name.log 2>> $rvm_ruby_log_path/$log_file_name.error.log + fi + if [[ $? -gt 0 ]] ; then $rvm_scripts_path/log "error" "Error running '$command' under $env_name, please check $rvm_ruby_log_path/$log_file_name*.log" ; __rvm_pushpop ; return 1 ; fi + unset log_file command env_name +} + # Unset both rvm variables as well as ruby-specific variables # Preserve gemset if 'rvm_sticky' is set (persist gemset unless clear is explicitely called). __rvm_cleanup_variables() { @@ -183,44 +180,128 @@ __rvm_cleanup_variables() { if [[ "$rvm_sticky_flag" = "1" ]] ; then export rvm_gemset_name ; else unset rvm_gemset_name ; fi - unset rvm_action rvm_irbrc_file rvm_command rvm_error_message rvm_url rvm_force_flag rvm_all_flag rvm_reconfigure_flag rvm_make_flags rvm_bin_flag rvm_import_flag rvm_export_flag rvm_self_flag rvm_gem_flag rvm_rubygems_flag rvm_debug_flag rvm_delete_flag rvm_summary_flag rvm_test_flag _rvm_spec_flag rvm_json_flag rvm_yaml_flag rvm_shebang_flag rvm_env_flag rvm_tail_flag rvm_use_flag rvm_dir_flag rvm_list_flag rvm_empty_flag rvm_file_name rvm_benchmark_flag rvm_clear_flag rvm_name_flag rvm_verbose_flag rvm_user_flag rvm_system_flag rvm_ruby_configure_flags rvm_uninstall_flag rvm_install_flag rvm_llvm_flag rvm_ruby_bits rvm_ruby_patch rvm_sticky_flag + unset rvm_action rvm_irbrc_file rvm_command rvm_error_message rvm_url rvm_force_flag rvm_all_flag rvm_reconfigure_flag rvm_make_flags rvm_bin_flag rvm_import_flag rvm_export_flag rvm_self_flag rvm_gem_flag rvm_rubygems_flag rvm_debug_flag rvm_delete_flag rvm_summary_flag rvm_test_flag _rvm_spec_flag rvm_json_flag rvm_yaml_flag rvm_shebang_flag rvm_env_flag rvm_tail_flag rvm_use_flag rvm_dir_flag rvm_list_flag rvm_empty_flag rvm_file_name rvm_benchmark_flag rvm_clear_flag rvm_name_flag rvm_verbose_flag rvm_user_flag rvm_system_flag rvm_ruby_configure_flags rvm_uninstall_flag rvm_install_flag rvm_llvm_flag rvm_ruby_bits rvm_sticky_flag rvm_rvmrc_flag rvm_gems_flag rvm_only_path_flag rvm_docs_flag rvm_ruby_aliases rvm_ruby_aliases rvm_patch_names rvm_clang_flag } # Unset ruby-specific variables __rvm_unset_ruby_variables() { - unset rvm_ruby_interpreter rvm_ruby_version rvm_url rvm_ruby_repo_url rvm_ruby_package_name rvm_ruby_patch_level rvm_ruby_make rvm_ruby_make_install rvm_ruby_revision rvm_ruby_tag rvm_major_version rvm_minor_version rvm_ruby_gem_home rvm_ruby_binary rvm_ruby_home rvm_ruby_log_path rvm_ruby_src_path rvm_ruby_irbrc rvm_ruby_selected_flag rvm_ruby_string rvm_ruby_string rvm_ruby_src_path rvm_ruby_repo_url rvm_major_version rvm_minor_version rvm_ruby_gem_home rvm_head_flag rvm_ruby_configure rvm_ruby_mode rvm_ruby_package_file rvm_ruby_package_name rvm_ruby_gem_path + unset rvm_ruby_interpreter rvm_ruby_version rvm_url rvm_ruby_repo_url rvm_ruby_package_name rvm_ruby_patch_level rvm_ruby_make rvm_ruby_make_install rvm_ruby_revision rvm_ruby_tag rvm_release_version rvm_major_version rvm_minor_version rvm_ruby_gem_home rvm_ruby_binary rvm_ruby_home rvm_ruby_log_path rvm_ruby_src_path rvm_ruby_irbrc rvm_ruby_selected_flag rvm_ruby_src_path rvm_ruby_repo_url rvm_major_version rvm_minor_version rvm_ruby_gem_home rvm_head_flag rvm_ruby_configure rvm_ruby_mode rvm_ruby_package_file rvm_ruby_package_name rvm_ruby_gem_path rvm_ruby_name rvm_ruby_alias rvm_ruby_strings rvm_ruby_repo_path +} + +# Usage: __rvm_with_env 'env-name' 'command' +__rvm_with_env() { + [[ -n "$rvm_trace_flag" ]] && rvm_env_args="--trace" + rvm_env_command="$(echo "$2" | sed "s/rvm /rvm $rvm_env_args /")" + # Subshells! + ( + source $rvm_scripts_path/rvm + rvm $rvm_env_args use $1 && eval "$rvm_env_command" + ) + unset rvm_env_args rvm_env_command +} + +# Returns the first 1.8.7-compatible (partly) ruby for use +# with things like rbx etc which require a ruby be installed. +__rvm_18_compat_ruby() { + rubies="" + for ruby_name in $(\ls $rvm_rubies_path); do + if [[ ! -L "$rvm_rubies_path/$ruby_name" ]] && $rvm_scripts_path/match "$ruby_name" '^(ruby-1.8.[[:digit:]]|rbx|ree)-'; then + rubies="$rubies $ruby_name" + fi + done; unset ruby_name + echo "$rubies" | sed 's/^ //' | tr ' ' '\n' | sort | tail -n1 + unset rubies +} + +__rvm_ensure_has_18_compat_ruby() { + if [[ -z "$(__rvm_18_compat_ruby)" ]]; then + # TODO: install currently doesn't return the correct status. + local compat_result=0 + if ! ( rvm install 1.8.7 ); then + $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." + $rvm_scripts_path/log "fatal" "Please install it manually (or a compatible alternative) to proceed." + compat_result=1 + fi + unset original_ruby + return $compat_result + fi +} + +__rvm_inherit_trace_flag() { + if [[ -n "$rvm_trace_flag" ]]; then + set -x + export rvm_trace_flag + fi +} + +# Cleans up temp folders for a given prefix, +# typically the current process id. +__rvm_cleanup_temp_for() { + [[ -z "$1" ]] && return 1 + if [[ -d "$rvm_tmp_path/" ]]; then + rm -rf "$rvm_tmp_path/$1"* >/dev/null 2>&1 + fi + exit +} + +__rvm_cleanup_temp_on_exit() { + trap "__rvm_cleanup_temp_for '$$'" 0 1 2 3 15 } __rvm_set_rvmrc() { if [[ "$HOME" != "$(pwd)" ]] ; then + if [[ "$rvm_verbose_flag" -eq 1 ]] ; then flags="use " ; fi + if [[ -s .rvmrc ]] ; then mv .rvmrc .rvmrc.$(date +%m.%d.%Y-%H:%M:%S) + $rvm_scripts_path/log "warning" ".rvmrc is not empty, moving aside to preserve." fi - echo "rvm use $(basename $rvm_ruby_gem_home)" > .rvmrc + + local identifier=$(__rvm_environment_identifier) + printf "if [[ -s \"$rvm_environments_path/$identifier\" ]] ; then\n . \"$rvm_environments_path/$identifier\"" > .rvmrc + printf "\nelse\n rvm --create $flags \"$identifier\"\nfi" >> .rvmrc + + unset flags else - echo -e "Not setting a project specific rvmrc file, currently in the HOME directory." + $rvm_scripts_path/log "error" ".rvmrc cannot be set in your home directory. \n The home .rvmrc is for global rvm settings only." fi + } __rvm_load_rvmrc() { - if [[ -f /etc/rvmrc ]] ; then source /etc/rvmrc ; fi - if [[ -f "$HOME/.rvmrc" ]] ; then source "$HOME/.rvmrc" ; fi + for rvmrc in /etc/rvmrc $HOME/.rvmrc ; do + if [[ -f "$rvmrc" ]] ; then + if grep -q '^\s*rvm .*$' $rvmrc ; then + $rvm_scripts_path/log "error" "$rvmrc is for rvm settings only.\nrvm CLI may NOT be called from within $rvmrc. \nSkipping the loading of $rvmrc" + return 1 + else + source "$rvmrc" + fi + fi + done } # Wrap the specified ruby code file in a Benchmark.bmbm block and execute it. __rvm_benchmark() { code="require \"benchmark\" \n Benchmark.bmbm do |benchmark| \n benchmark.report(\"${rvm_ruby_file}\") do \n" - echo -e "$code" > "$rvm_tmp_path/$$.rb" + printf "\n$code" > "$rvm_tmp_path/$$.rb" unset code cat $rvm_ruby_file >> "$rvm_tmp_path/$$.rb" - echo -e "\n end \nend\n" >> "$rvm_tmp_path/$$.rb" + printf "\n end \nend\n" >> "$rvm_tmp_path/$$.rb" rvm_ruby_args="$rvm_tmp_path/$$.rb" rvm_benchmark_flag=1 - action="ruby" - if [[ ! -z "$rvm_debug_flag" ]] ; then echo -e "$rvm_tmp_path/$$.rb:\n$(cat $rvm_tmp_path/$$.rb)" ; fi + rvm_action="ruby" + if [[ ! -z "$rvm_debug_flag" ]] ; then printf "\n$rvm_tmp_path/$$.rb:\n$(cat $rvm_tmp_path/$$.rb)" ; fi + # Override ruby string stuff, pass through. + old_rvm_ruby_string=$rvm_ruby_string + unset rvm_ruby_string + export rvm_ruby_strings $rvm_scripts_path/set $rvm_action $rvm_ruby_args + result=$? + # Restore the state pre-sets. + [[ -n "$old_rvm_ruby_string" ]] && rvm_ruby_string=$old_rvm_ruby_string + unset old_rvm_ruby_string } - # Loop over the currently installed rubies and refresh their binscripts. __rvm_bin_scripts() { for rvm_ruby_binary in $rvm_rubies_path/*/bin/ruby ; do @@ -235,65 +316,7 @@ __rvm_bin_scripts() { # Write the bin/ wrapper script for currently selected ruby. # TODO: Adjust binscript to be able to handle all rubies not just the standard interpreteres. __rvm_bin_script() { - - if [[ -z "$rvm_ruby_selected_flag" ]] ; then __rvm_select ; fi - -ruby_wrapper=$(cat < $rvm_bin_path/$rvm_ruby_package_name - unset ruby_wrapper - chmod +x $rvm_bin_path/$rvm_ruby_package_name -} - -# Load default ruby, if default is not set load system ruby. -__rvm_load_defaults() { - if [[ ! -s "$rvm_config_path/system" ]] ; then - for variable in RUBY_VERSION GEM_HOME GEM_PATH BUNDLE_PATH MY_RUBY_HOME ; do - eval value=\$${variable} - if [[ -z "${value/ /}" ]] ; then - echo "unset ${variable}" >> $rvm_config_path/system - else - eval "export $variable" - eval value=\$${variable} - echo "${variable}='$value' ; export ${variable}" >> $rvm_config_path/system - fi - done - fi - - __rvm_db "system_ruby" "rvm_system_ruby" - if [[ ! -z "$rvm_system_ruby" ]] ; then - rvm_system_ruby=$(which ruby 2>/dev/null) - if [[ $? -ne 0 ]] ; then - $rvm_scripts_path/log "info" "System ruby not found, no system default will be stored." - else - $rvm_scripts_path/db "$rvm_config_path/user" "system_ruby" "$rvm_system_ruby" - - # Now store system system & user gem paths - if [[ ! -z "$(which gem 2>/dev/null)" ]] ; then - __rvm_db "system_user_gem_path" "rvm_system_user_gem_path" - if [[ -z "$rvm_system_user_gem_path" ]] ; then - rvm_system_user_gem_path=$( rvm system ; gem env gemdir user; ) - $rvm_scripts_path/db "$rvm_config_path/user" "system_user_gem_path" "$rvm_system_user_gem_path" - fi - __rvm_db "system_gem_path" "rvm_system_gem_path" - if [[ -z "$rvm_system_gem_path" ]] ; then - rvm_system_gem_path=$( rvm system ; gem env gemdir; ) - $rvm_scripts_path/db "$rvm_config_path/user" "system_gem_path" "$rvm_system_gem_path" - fi - fi - fi - fi + $rvm_scripts_path/wrapper "$rvm_ruby_string" } # Reset any rvm gathered information about the system and its state. @@ -302,16 +325,16 @@ __rvm_reset() { PATH="$(echo $PATH | tr ':' '\n' | awk '$0 !~ /rvm/' | paste -sd : -)" PATH="$rvm_bin_path:$PATH" ; export PATH - for variable in RUBY_VERSION GEM_HOME BUNDLE_PATH MY_RUBY_HOME ; do unset $variable ; done - for flag in default passenger editor ; do rm -f "$rvm_bin_path"/${flag}_* ; done + unset flag for file in system default ; do - if [[ -f "$rvm_path/$file" ]] ; then rm -f $rvm_path/$file ; fi - if [[ -f "$rvm_config_path/$file" ]] ; then rm -f $rvm_config_path/$file ; fi - done - rvm_ruby_interpreter="system" - __rvm_select + rm -f "$rvm_path/$file" "$rvm_config_path/$file" "$rvm_environments_path/$file" + done; unset file + + # Go back to a clean state. + __rvm_become "system" + __rvm_unset_ruby_variables for system_config in system_ruby system_gem_path system_user_gem_path ; do $rvm_scripts_path/db "$rvm_config_path/user" "$system_config" "delete" @@ -355,110 +378,6 @@ __rvm_source_dir() { fi } -# Query for valid rvm ruby strings -# This is meant to be used with scripting. -__rvm_list_strings() { - echo $(\ls $rvm_rubies_path) -} - -# 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. -__rvm_list() { - action="$(echo $rvm_ruby_args | awk '{print $1}')" - - if [[ "known" = "$action" ]] ; then - __rvm_list_known - elif [[ "default" = "$action" ]] ; then - __rvm_list_default - elif [[ -z "$action" ]] || [[ "rubies" = "$action" ]] ; then - __rvm_list_rubies - elif [[ "strings" = "$action" ]] ; then - __rvm_list_strings - else # help - echo -e "Usage: rvm list {known,default,rubies,strings}" - fi -} - -__rvm_list_default() { - strings="$(echo $rvm_ruby_args | awk '{print $2}')" - if [[ "$strings" = "string" ]] ; then - echo $(grep 'MY_RUBY_HOME' $rvm_config_path/default | awk -F"'" '{print $2}' | xargs basename) - else - if [[ -f "$rvm_config_path/default" ]] && [[ -s $rvm_config_path/default ]] ; then - version=$(grep 'MY_RUBY_HOME' $rvm_config_path/default | awk -F"'" '{print $2}' | xargs basename) - if [[ ! -z "$version" ]] ; then - echo -e "\nDefault Ruby (for new shells)\n" - string="[ $(file $rvm_rubies_path/$version/bin/ruby | awk '/x86.64/ {print "x86_64"} /386/ {print "i386"} /ppc/ {print "ppc"}' | tr "\n" ' ')]" - echo -e " $(tput setaf 2)$version$(tput sgr0) $string\n" - fi ; unset version - fi - fi -} - -__rvm_list_known() { - while read -r tag - do - prefix="$(echo ${tag/\//} | sed 's#^v1_##' | awk -F'_' '{print "(ruby-)1."$1"."$2}' | sed 's#p$##')" - echo "${prefix}-t${tag/\//}" - unset prefix tag - done < <(svn list http://svn.ruby-lang.org/repos/ruby/tags/ | awk '/^v1_[8|9]/') - echo -e "(ruby-)1.8.6(-p383)\n(ruby-)1.8.6-head\n(ruby-)1.8.7(-p248)\n(ruby-)1.8.7-head\n(ruby-)1.9.1(-p243)\n(ruby-)1.9.1(-p376)\n(ruby-)1.9.1-head\n(ruby-)1.9.2-preview1" - echo -e "jruby-1.2.0\njruby-1.3.1\njruby(-1.4.0) # the default\njruby-head" - echo -e "rbx(-prc1) # default\nrbx-head" - echo -e "ree-1.8.6\nree(-1.8.7) # the default\nree-1.8.6-head\nree-1.8.7-head" - echo -e "maglev(-22907)\nmaglev-head" - echo -e "mput(-head) # shyouhei head, the default mput" - echo -e "ironruby-0.9.3\nironruby-1.0-rc2\nironruby-head" - if [[ "Darwin" = "$(uname)" ]] ; then - echo -e "macruby(-nightly) # the default macruby\nmacruby-head # Build from the macruby git repository" - fi -} - -__rvm_list_rubies() { - echo - ruby=$(which ruby 2>/dev/null) ; current_ruby="" - if [[ ! -z "$ruby" ]] && [[ ! -z "$(echo $ruby | awk '/rvm/')" ]] ; then - current_ruby="$(echo $ruby | xargs dirname | xargs dirname | xargs basename 2> /dev/null)" - fi - - echo -e "rvm Rubies\n" - for version in $(\ls $rvm_rubies_path/ 2> /dev/null | awk '/[a-z]*-.*/ {print $NF}') ; do - if [[ ! -z "$(echo $version | awk '/^jruby-/')" ]] ; then - string="[ $($rvm_rubies_path/$version/bin/ruby -v | awk '{print $NF}') ]" - elif [[ ! -z "$(echo $version | awk '/^maglev-|^macruby-/')" ]] ; then - string="[ x86_64 ]" - else - string="[ $(file $rvm_rubies_path/$version/bin/ruby | awk '/x86.64/ {print "x86_64"} /386/ {print "i386"} /ppc/ {print "ppc"}' | tr "\n" ' ')]" - fi - if [[ "$version" = "$current_ruby" ]] ; then echo -n "=> " ; else echo -n " " ; fi - echo -e "$(tput setaf 2)$version$(tput sgr0) $string" - done ; unset version - - if [[ -f "$rvm_config_path/default" ]] && [[ -s $rvm_config_path/default ]] ; then - version=$(grep 'MY_RUBY_HOME' $rvm_config_path/default | awk -F"'" '{print $2}' | xargs basename) - if [[ ! -z "$version" ]] ; then - echo -e "\nDefault Ruby (for new shells)\n" - string="[ $(file $rvm_rubies_path/$version/bin/ruby | awk '/x86.64/ {print "x86_64"} /386/ {print "i386"} /ppc/ {print "ppc"}' | tr "\n" ' ')]" - echo -e " $(tput setaf 2)$version$(tput sgr0) $string" - fi ; unset version - fi - - system_ruby="$(rvm system ; which ruby 2>/dev/null)" - if [[ ! -z "$system_ruby" ]] && [[ -x "$system_ruby" ]]; then - echo -e "\nSystem Ruby\n" - system_version=$($system_ruby -v) - string="[ $(file $system_ruby | awk '/x86.64/ {print "x86_64"} /386/ {print "i386"} /ppc/ {print "ppc"}' | tr "\n" ' ')]" - if [[ ! -z "$system_ruby" ]] && [[ "$current_ruby" = "$system_version" ]] ; then echo -n "=> " ; else echo -n " " ; fi - echo -e "$(tput setaf 2)system$(tput sgr0) $string" - else - $rvm_scripts_path/log "info" "No system ruby found." - fi - - unset current_ruby version selected system_ruby system_version string - echo -} - # Initialize rvm, ensuring that the path and directories are as expected. __rvm_initialize() { rvm_ruby_load_path="." @@ -470,13 +389,13 @@ __rvm_initialize() { PATH=$rvm_bin_path:$PATH ; export PATH fi - mkdir -p $rvm_src_path $rvm_bin_path $rvm_archives_path $rvm_gems_path $rvm_tmp_path + mkdir -p $rvm_src_path $rvm_bin_path $rvm_archives_path $rvm_gems_path $rvm_tmp_path $rvm_repo_path } # Update rubygems or binscripts based on CLI selection. __rvm_update() { __rvm_pushpop $rvm_path - if [[ "head" = "$rvm_ruby_revision" ]] || [[ ! -z "$rvm_self_flag" ]] || [[ "update" = "$rvm_action" ]] || [[ ! -z "$rvm_update_flag" ]] ; then + if [[ "$rvm_head_flag" == "1" ]] || [[ ! -z "$rvm_self_flag" ]] || [[ "update" = "$rvm_action" ]] || [[ ! -z "$rvm_update_flag" ]] ; then __rvm_version __rvm_update_rvm fi @@ -493,28 +412,28 @@ __rvm_update_rvm() { mkdir -p "$rvm_src_path" __rvm_pushpop "$rvm_src_path" - if [[ "head" = "$rvm_ruby_revision" ]] || [[ -z "$system_ruby" ]] ; then + if [[ "$rvm_head_flag" == "1" ]] ; then if [[ -d "$rvm_src_path/rvm/.git" ]] ; then builtin cd $rvm_src_path/rvm/ && git pull origin master && ./scripts/install else - builtin cd $rvm_src_path && git clone git://github.com/wayneeseguin/rvm.git && builtin cd rvm/ && ./install + builtin cd $rvm_src_path && git clone http://github.com/wayneeseguin/rvm.git && builtin cd rvm/ && ./scripts/install fi else stable_version=$(curl -s http://rvm.beginrescueend.com/releases/stable-version.txt) __rvm_run "fetch" "$rvm_scripts_path/fetch 'http://rvm.beginrescueend.com/releases/rvm-${stable_version}.tar.gz'" "fetching rvm-${stable_version}.tar.gz" - __rvm_run "extract" "cat $rvm_archives_path/rvm-${stable_version}.tar.gz | gunzip | tar xf - -C $rvm_src_path" "Extracting $rvm_ruby_package_file ..." + __rvm_run "extract" "cat $rvm_archives_path/rvm-${stable_version}.tar.gz | gunzip | tar xf - -C $rvm_src_path" "Extracting rvm-${stable_version}.tar.gz ..." __rvm_run "install" "builtin cd $rvm_src_path/rvm-${stable_version}/ ; ./install" "Installing rvm-${stable_version}..." fi __rvm_pushpop - $rvm_scripts_path/hook "after_update" + rvm_hook="after_update" ; source $rvm_scripts_path/hook } __rvm_reboot() { - $rvm_scripts_path/log "warn" "Do you wish to reset rvm? ('yes', or 'no')" + $rvm_scripts_path/log "warn" "Do you wish to reboot rvm? ('yes', or 'no')" read response if [[ "yes" = "$response" ]] ; then builtin cd $rvm_path @@ -553,10 +472,12 @@ __rvm_pushpop() { # Meant for use before and after an operation that might reset the currently selected ruby. __rvm_state() { if [[ -z "$rvm_state" ]] ; then - if [[ -z "$(which ruby 2>/dev/null | awk /$(basename $rvm_rubies_path)/)" ]] ; then - rvm_state=system - else - rvm_state="$(dirname "$(which ruby 2>/dev/null)" | xargs dirname | xargs basename)" + rvm_state="$(__rvm_environment_identifier)" + rvm_state="${rvm_state:-"system"}" + if [[ -n "$1" ]]; then + rvm_ruby_string="$1" + __rvm_select + __rvm_use fi else rvm_ruby_string="$rvm_state" @@ -569,7 +490,7 @@ __rvm_state() { # Output an inspection of selected 'binary' scripts, based on CLI selection. __rvm_inspect() { for binary in $rvm_ruby_args ; do - actual_file="$(which $binary 2>/dev/null)" + actual_file="$(command -v $binary)" $rvm_scripts_path/log "info" "$actual_file:" if [[ ! -z "$rvm_shebang_flag" ]] ; then cat $actual_file | head -n 1 ; fi if [[ ! -z "$rvm_env_flag" ]] ; then cat $actual_file | awk '/ENV/' ; fi @@ -585,12 +506,12 @@ __rvm_inspect() { __rvm_make_flags() { # This is only an issue with Darwin :/ if [[ "Darwin" = "$(uname)" ]] ; then - # ls /usr/lib/gcc/x86_64-apple-darwin10 + # \ls /usr/lib/gcc/x86_64-apple-darwin10 # Set the build & host type - if [[ "Power Macintosh" = "$(sysctl hw.machine | awk -F: '{print $2}' | sed 's/^ //')" ]] ; then + if [[ "Power Macintosh" = "$(sysctl -n hw.machine)" ]] ; then : # Do nothing ? - elif [[ $(sysctl hw.cpu64bit_capable | awk '{print $2}') = 1 ]] ; then # we could also use: sysctl hw.optional.x86_64 + elif [[ "$(sysctl -n hw.cpu64bit_capable)" = 1 || "$(sysctl -n hw.optional.x86_64)" = 1 ]] ; then # 64 bit capable if [[ "-arch x86_64" = "$rvm_archflags" ]] ; then rvm_ruby_configure_flags="${rvm_ruby_configure_flags} --build=x86_64-apple-darwin$(uname -r) --host=x86_64-apple-darwin$(uname -r)" @@ -600,10 +521,6 @@ __rvm_make_flags() { rvm_archflags="-arch x86_64" rvm_ruby_configure_flags="${rvm_ruby_configure_flags} --build=x86_64-apple-darwin$(uname -r) --host=x86_64-apple-darwin$(uname -r)" fi - else - # 32 bit capable only - if [[ -z "$rvm_archflags" ]] ; then rvm_archflags="-arch i386" ; fi - rvm_ruby_configure_flags="${rvm_ruby_configure_flags} --build=i386-apple-darwin$(uname -r) --host=i386-apple-darwin$(uname -r)" fi if [[ ! -z "$rvm_archflags" ]] ; then @@ -620,28 +537,33 @@ __rvm_make_flags() { # Select a gemset based on CLI set options and environment. # This only sets 'rvm_ruby_gem_home' __rvm_gemset_select() { - if ! which gem > /dev/null 2>&1 ; then return 0 ; fi + command -v gem > /dev/null + if [[ $? -gt 0 ]] ; then return 0 ; fi # Stop if no 'gem' command is available. - rvm_ruby_global_gems_path="$rvm_gems_path/$rvm_ruby_string%global" + rvm_ruby_global_gems_path="$rvm_gems_path/${rvm_ruby_string}${rvm_gemset_separator}global" + + #if [[ -z "$(echo $rvm_ruby_gem_home | grep "$rvm_path")" ]] ; then + # $rvm_scripts_path/log "warn" "Gemsets cannot be used with system ruby installs (yet)." + #fi if [[ -z "$rvm_gemset_name" ]] ; then # No longer defaulting to 'sticky' gem sets. # Set 'rvm_sticky_flag=1' in ~/.rvmrc to enable. if [[ ! -z "$rvm_sticky_flag" ]] ; then if [[ ! -z "$GEM_HOME" ]] ; then - rvm_gemset_name=$(echo $GEM_HOME | xargs basename | awk -F'%' '{print $2}') + rvm_gemset_name=$(echo $GEM_HOME | xargs basename | awk -F${rvm_gemset_separator} '{print $2}') fi if [[ ! -z "$rvm_ruby_gem_home" ]] ; then - rvm_gemset_name=$(echo $rvm_ruby_gem_home | xargs basename | awk -F'%' '{print $2}') + rvm_gemset_name=$(echo $rvm_ruby_gem_home | xargs basename | awk -F${rvm_gemset_separator} '{print $2}') fi fi if [[ ! -z "$rvm_gemset_name" ]] && ! $rvm_scripts_path/match "$rvm_gemset_name" "^[0-9]\.[0-9]" ; then - rvm_ruby_gem_home="$rvm_gems_path/$rvm_ruby_string%$rvm_gemset_name" + rvm_ruby_gem_home="$rvm_gems_path/${rvm_ruby_string}${rvm_gemset_separator}${rvm_gemset_name}" else if [[ ! -z "$rvm_ruby_string" ]] && [[ "$rvm_ruby_interpreter" != "system" ]] ; then rvm_ruby_gem_home="$rvm_gems_path/$rvm_ruby_string" - elif [[ -z "$GEM_HOME" ]] && [[ ! -z "$(which gem 2>/dev/null)" ]] ; then + elif [[ -z "$GEM_HOME" ]] && [[ ! -z "$(command -v gem)" ]] ; then rvm_ruby_gem_home=$(gem env gemdir) elif [[ ! -z "$GEM_HOME" ]] ; then rvm_ruby_gem_home="$GEM_HOME" @@ -651,69 +573,61 @@ __rvm_gemset_select() { fi if [[ -z "$rvm_gemset_name" ]] ; then unset rvm_gemset_name ; fi else - if [[ -z "$rvm_ruby_gem_home" ]] || [[ ! -z "$(echo $rvm_ruby_gem_home | grep '%')" ]] ; then - rvm_ruby_gem_home="$rvm_gems_path/$rvm_ruby_string%$rvm_gemset_name" + gemset=$(echo "$rvm_ruby_gem_home" | awk -F'@' '{print $NF}') + if [[ -z "$rvm_ruby_string" ]] && [[ ! -z "${GEM_HOME/@*/}" ]] ; then + rvm_ruby_string=$(basename ${GEM_HOME/@*/}) + fi + + if [[ ! -z "$rvm_ruby_string" ]] ; then + if [[ -z "$rvm_ruby_gem_home" ]] || [[ ! -z "$gemset" ]] ; then + rvm_ruby_gem_home="$rvm_gems_path/${rvm_ruby_string}${rvm_gemset_separator}${rvm_gemset_name}" + elif [[ ! -z "$gemset" ]] && [[ "$rvm_gemset_name" != "$gemset" ]] ; then + rvm_ruby_gem_home="$rvm_gems_path/${rvm_ruby_string}${rvm_gemset_separator}${rvm_gemset_name}" + fi ; unset gemset + else + $rvm_scripts_path/log "error" "Gemsets can not be used with non rvm controlled rubies (currently)." + return 1 fi fi # If the gemset does not exist, then notify the user as such and abort the action. - if [[ ! -z "$rvm_gemset_name" ]] && [[ ! -d "$rvm_ruby_gem_home" ]] && [[ "$rvm_gemset_create_on_use_flag" -ne 1 ]] && [[ "$rvm_create_flag" -ne 1 ]] && [[ "$rvm_delete_flag" -ne 1 ]] ; then - $rvm_scripts_path/log "error" "Gemset '$rvm_gemset_name' does not exist, rvm gemset create '$rvm_gemset_name' first." - return 1 + if [[ ! -z "$rvm_gemset_name" ]] && [[ ! -d "$rvm_ruby_gem_home" ]] ; then + if [[ "$rvm_gemset_create_on_use_flag" -ne 1 ]] && [[ "$rvm_create_flag" -ne 1 ]] && [[ "$rvm_delete_flag" -ne 1 ]] ; then + $rvm_scripts_path/log "error" "Gemset '$rvm_gemset_name' does not exist, rvm gemset create '$rvm_gemset_name' first." + return 1 + fi elif [[ "$rvm_delete_flag" -eq 1 ]] ; then return 1 fi - rvm_ruby_gem_path="$rvm_ruby_gem_home:$rvm_ruby_global_gems_path" - - # TODO: Remove next section after a several releases. - # Migrate original rvm global gem cache directory to $HOME/.gem/cache - if [[ "$(whoami)" != "root" ]] ; then - if [[ -d "$rvm_path/gems/cache" ]] && [[ ! -L "$rvm_path/gems/cache" ]] ; then - if [[ ! -z "$(ls -A "$rvm_path"/gems/cache/)" ]] ; then - mv $rvm_path/gems/cache/* $HOME/.gem/cache/ - fi - rmdir $rvm_path/gems/cache - fi - - # Some sanity checking. - if [[ ! -d "$rvm_gems_cache_path" ]] ; then - mkdir -p $rvm_gems_cache_path - fi - if [[ "$rvm_gems_cache_path" != "$rvm_gems_path/cache" ]] ; then - rm -f "$rvm_gems_path/cache" - ln -nfs "$rvm_gems_cache_path" "$rvm_gems_path/cache" - fi + if [[ -z "$rvm_ruby_gem_home" ]] && [[ ! -z $rvm_ruby_string ]] ; then + rvm_ruby_gem_home="$rvm_gems_path/$rvm_ruby_string" + rvm_ruby_global_gems_path="$rvm_gems_path/$rvm_ruby_string${rvm_gemset_separator}global" fi - chmod u+w "$rvm_gems_cache_path" - # /TODO - # Careful not to nuke system gems cache. - if [[ ! -z "$rvm_ruby_gem_home" ]] && [[ ! -z "$(echo $rvm_ruby_gem_home | awk '/rvm/')" ]] ; then - # Ensure that the ruby gem home exists. - mkdir -p "$rvm_ruby_gem_home" + rvm_ruby_gem_path="$rvm_ruby_gem_home:$rvm_ruby_global_gems_path" - # If there is a cache *directory* already, - # move all the gems to the global cache directory and remove it. - if [[ -d "$rvm_ruby_gem_home/cache" ]] && [[ ! -L "$rvm_ruby_gem_home/cache" ]] ; then - if [[ ! -z "$(ls -A "$rvm_ruby_gem_home"/cache/)" ]] ; then - mv "$rvm_ruby_gem_home"/cache/* "$HOME"/.gem/cache/ - fi - rmdir "$rvm_ruby_gem_home"/cache + # Ensure that the ruby gem home exists. + mkdir -p "$rvm_ruby_gem_home" + if [[ -n "$rvm_ruby_gem_home" ]] && echo "$rvm_ruby_gem_home" | grep -q 'rvm'; then + if __rvm_using_gemset_globalcache && [[ ! -L "$rvm_ruby_gem_home/cache" ]]; then + mv "$rvm_ruby_gem_home/cache/"*.gem "$rvm_gems_cache_path/" 2>/dev/null + rm -rf "$rvm_ruby_gem_home/cache" + ln -nfs "$rvm_gems_cache_path" "$rvm_ruby_gem_home/cache" fi + fi - # If the ruby's gems cache directory is not a symlink to the global cache, symlink it - if [[ ! -L "$rvm_ruby_gem_home/cache" ]] ; then - ln -nfs "$HOME/.gem/cache" "$rvm_ruby_gem_home/cache" - fi - fi ; export rvm_ruby_gem_path rvm_ruby_gem_home + export rvm_ruby_gem_path rvm_ruby_gem_home } # Use a gemset specified by 'rvm_ruby_gem_home' __rvm_gemset_use() { + #if [[ -z "$(echo $rvm_ruby_gem_home | grep "rvm")" ]] ; then + # $rvm_scripts_path/log "warn" "Gemsets cannot be used with system ruby installs (yet)." + #fi if [[ ! -z "$rvm_ruby_gem_home" ]] ; then if [[ ! -d "$rvm_ruby_gem_home" ]] ; then - if [[ "$rvm_gemset_create_on_use_flag" -eq 1 ]] ; then + if [[ "$rvm_gemset_create_on_use_flag" -eq 1 ]] || [[ "$rvm_create_flag" -eq 1 ]]; then $rvm_scripts_path/gemsets create $rvm_gemset_name else $rvm_scripts_path/log "error" "Gemset '$rvm_gemset_name' does not exist, rvm gemset create '$rvm_gemset_name' first." @@ -724,15 +638,29 @@ __rvm_gemset_use() { if [[ "$rvm_interactive" -eq 1 ]] || [[ "$rvm_verbose_flag" -eq 1 ]] ; then $rvm_scripts_path/log "info" "Now using gemset '${rvm_gemset_name:-default}'" fi - rvm_ruby_gem_home="$(echo $GEM_HOME | sed 's/%.*$//')%$rvm_gemset_name" + + rvm_ruby_gem_home="$(echo $GEM_HOME | sed 's/'${rvm_gemset_separator}'.*$//')${rvm_gemset_separator}${rvm_gemset_name}" GEM_HOME="$rvm_ruby_gem_home" BUNDLE_PATH="$rvm_ruby_gem_home" - GEM_PATH="$rvm_ruby_gem_home/bin:$(echo $GEM_HOME | sed 's/%.*$//')%global/bin" + GEM_PATH="$rvm_ruby_gem_home/bin:$(echo $GEM_HOME | sed 's/'${rvm_gemset_separator}'.*$//')${rvm_gemset_separator}global/bin" export rvm_ruby_gem_home GEM_HOME BUNDLE_PATH GEM_PATH + + __rvm_use # Now ensure the selection takes effect for the environment. fi return 0 } +__rvm_gemset_clear() { + unset rvm_gemset_name ; shift + rvm_ruby_gem_home="$(echo $GEM_HOME | sed "s#${rvm_gemset_separator:-'@'}.*\$##g")" + rvm_ruby_global_gems_path="$(echo $GEM_HOME | sed 's/'${rvm_gemset_separator}'.*$//')${rvm_gemset_separator}global" + GEM_HOME=$rvm_ruby_gem_home + BUNDLE_PATH="$rvm_ruby_gem_home" + GEM_PATH="$rvm_ruby_gem_home/bin:$rvm_ruby_global_gems_path/bin" + export rvm_ruby_gem_home rvm_ruby_global_gems_path GEM_HOME BUNDLE_PATH GEM_PATH + __rvm_use # Now ensure the selection takes effect for the environment. +} + __rvm_mono_env() { export DYLD_LIBRARY_PATH="$rvm_usr_path/lib:$DYLD_LIBRARY_PATH" export C_INCLUDE_PATH="$rvm_usr_path/include:$C_INCLUDE_PATH" @@ -741,3 +669,120 @@ __rvm_mono_env() { export PKG_CONFIG_PATH="$rvm_usr_path/lib/pkgconfig:$PKG_CONFIG_PATH" PATH="$rvm_usr_path/bin:$PATH" } + +__rvm_environment_identifier() { + ruby_string="$(command -v ruby)" + if [ -n "$ruby_string" ] && echo "$ruby_string" | grep -q -F "$rvm_rubies_path"; then + echo "$GEM_HOME" | xargs basename + else + echo "system" + fi + unset ruby_string +} + +__rvm_become() { + [[ -n "$1" ]] && rvm_ruby_string="$1" + { __rvm_ruby_string && __rvm_select && __rvm_use; } > /dev/null 2>&1 +} + +__rvm_ensure_has_enviroment_files() { + local environment_identifier="$(__rvm_environment_identifier)" + file_name="${rvm_environments_path}/$environment_identifier" + + # Ensure system is a blank file. + if [[ "$environment_identifier" == "system" ]]; then + rm -f "$file_name" + mkdir -p "$(dirname "$file_name")" + touch "$file_name" + return + fi + + if [[ ! -s "$file_name" ]] ; then + mkdir -p "${rvm_environments_path}" + echo "export PATH=\"${rvm_ruby_gem_home}/bin:${rvm_ruby_global_gems_path}/bin:${rvm_ruby_home}/bin:${rvm_bin_path}:\$PATH\"" > $file_name + for variable in RUBY_VERSION GEM_HOME GEM_PATH BUNDLE_PATH MY_RUBY_HOME IRBRC rvm_ruby_string rvm_gemset_name MAGLEV_HOME ; do + eval "export $variable" + eval value=\$${variable} + if [[ ! -z "$value" ]] ; then + echo "export ${variable}='$value'" >> $file_name + else + echo "unset ${variable}" >> $file_name + fi + done ; unset variable value + fi ; unset file_name + # Next, ensure we have default wrapper files. Also, prevent it from recursing. + if [[ -z "$rvm_creating_default_wrappers" ]]; then + # We need to generate wrappers for both the default gemset and the global gemset. + for wrapper_identifier in "$environment_identifier" "${environment_identifier}@global" ; do + rvm_creating_default_wrappers=1 + directory_name="$rvm_wrappers_path/$wrapper_identifier" + if [[ ! -L "$directory_name" && ! -d "$directory_name" ]]; then + mkdir -p "$directory_name" + $rvm_scripts_path/wrapper "$wrapper_identifier" &> /dev/null + fi + unset rvm_creating_default_wrappers directory_name + done; unset wrapper_identifier + fi +} + +# Strip whitespace and normalize it all. +__rvm_strip() { + sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/[[:space:]]\{1,\}/ /g' +} + +__rvm_using_gemset_globalcache() { + $rvm_scripts_path/db "$rvm_config_path/user" "use_gemset_globalcache" | grep -q '^true$' +} + +__rvm_current_gemcache_dir() { + if __rvm_using_gemset_globalcache; then + echo "$rvm_gems_cache_path" + else + echo "${rvm_ruby_gem_home:-"$GEM_HOME"}/cache" + fi +} + +__rvm_Answer_to_the_Ultimate_Question_of_Life_the_Universe_and_Everything() { + for index in {1..750} ; do perl -e 'sleep 0.2'; echo -n '.' ; done ; printf "%d" 0x2A ; echo +} + +__rvm_ultimate_question() { + printf "\nI do not know the Ultimate Question, " + printf "\nhowever I can help you build a more " + printf "\npowerful Ruby which can compute the " + printf "\nUltimate Question." +} + +# Checks the rvmrc for the given directory. Note that if +# argument is passed, it will be used instead of pwd. +__rvm_project_rvmrc() { + local cwd + # Get the first argument or the pwd. + cwd="${1:-"$(pwd)"}" + while : ; do + if [[ -z "$cwd" ]] || [[ "$HOME" = "$cwd" ]] || [[ "/" = "$cwd" ]] ; then + if [[ -n "$rvm_rvmrc_cwd" ]] ; then + if [[ -z "$rvm_previous_environment" ]] ; then + rvm default 1>/dev/null 2>&1 + else + rvm "$rvm_previous_environment" 1>/dev/null 2>&1 + fi + unset rvm_rvmrc_cwd rvm_previous_environment + fi + break + else + if [[ -f "$cwd/.rvmrc" ]] ; then + if [[ "$rvm_rvmrc_cwd" != "$cwd" ]] ; then + if [[ -z "$rvm_previous_environment" ]] ; then + rvm_previous_environment="$(__rvm_environment_identifier)" + fi + rvm_rvmrc_cwd="$cwd" + source "$cwd/.rvmrc" + fi + break + else + cwd=$(dirname "$cwd") + fi + fi + done +} diff --git a/scripts/wrapper b/scripts/wrapper new file mode 100755 index 0000000000..7a2ad49dbf --- /dev/null +++ b/scripts/wrapper @@ -0,0 +1,109 @@ +#!/usr/bin/env bash + +default_flag="$rvm_default_flag" +# Prevent it from recursing. +unset rvm_default_flag rvm_wrapper_name + +source "$rvm_scripts_path/base" + +full_binary_name() { + echo "$binary_name" | __rvm_strip +} + +wrap() { + mkdir -p "$(dirname "$file_name")" + rm -f "$file_name" + + echo "#!/usr/bin/env sh" > "$file_name" + echo "if [ -s \"${rvm_environments_path}/${environment_identifier}\" ] ; then" >> "$file_name" + echo " . \"${rvm_environments_path}/${environment_identifier}\"" >> "$file_name" + echo " exec $binary_name \"\$@\"" >> "$file_name" + echo "else" >> $file_name + echo " echo \"ERROR: Missing RVM environment file: '${rvm_environments_path}/${environment_identifier}'\"" >> $file_name + echo " exit 1" >> $file_name + echo "fi" >> $file_name + + if [[ -f $file_name ]] ; then chmod +x $file_name ; fi +} + +symlink_binary() { + # Generate the default wrapper with the given binary name. + # We first check if we can wrap the binary and if we were able to, + # we then symlink it into place. + if wrap_binary && [[ -f "$file_name" ]]; then + rm -f "${rvm_bin_path}/${prefix}_${binary_name}" + ln -fs "$file_name" "${rvm_bin_path}/${prefix}_${binary_name}" + fi +} + +wrap_binary() { + # We wrap when the given binary is in the path or override_check is set to one. + if [[ "$override_check" = "1" ]] || command -v $binary_name > /dev/null; then + wrap + else + $rvm_scripts_path/log "error" "Binary '$binary_name' not found in path." + return 1 + fi +} + +usage() { + printf "Usage: 'rvm wrapper [ruby_string] [wrapper_prefix] [binary[ binary[ ...]]]'\n" + printf " Where binary defaults to ruby, gem, rake, irb, rdoc, ri, testrb\n" + printf " For more information, see 'rvm help wrapper'\n" +} + +# Empty ruby string: show usage and exit. + +if [[ -z "$1" ]]; then + usage + exit 1 +fi + +ruby_string="$1"; shift + +override_check=0 +prefix="$1" +[[ "$#" -gt 0 ]] && shift + +binaries="$(echo "$@" | __rvm_strip)" + +if [[ 'system' == '$ruby_string' ]]; then + $rvm_scripts_path/log "error" "Wrapper can't be called with system rubies - sorry!" + exit 1 +fi + +# Default the list of binaries to those we use regularily. +if [[ -z "$binaries" ]] ; then + binaries="ruby gem irb ri rdoc rake erb testrb" +fi + +# Use the correct ruby. +__rvm_become "$ruby_string" + +__rvm_ensure_has_enviroment_files + +environment_identifier="$(__rvm_environment_identifier)" + +# For each binary, we want to generate the wrapper / symlink +# it to the existing wrapper if needed. +for binary_name in $binaries; do + file_name="${rvm_wrappers_path}/${environment_identifier}/${binary_name}" + if [[ -z "$prefix" ]] ; then + override_check=1 + wrap_binary + # Symlink it into place. + if [[ -f "$file_name" ]]; then + if [[ "$binary_name" == "ruby" ]] ; then + destination="$rvm_bin_path/$environment_identifier" + else + destination="$rvm_bin_path/${binary_name}-${environment_identifier}" + fi + rm -rf "$destination" + ln -nsf "$file_name" "$destination" + fi; unset destination + else + symlink_binary + fi ; unset file_name +done + +exit $? diff --git a/test/btu b/test/btu index c257059bb9..7697e66b0d 100644 --- a/test/btu +++ b/test/btu @@ -25,7 +25,7 @@ btu_mock() { if [[ ! -z "$command" ]] ; then mkdir -p /tmp/btu/$$ echo '!#/bin/bash' > /tmp/btu/$$/$command - echo -e "echo called: \$(basename \$0) \"\$@\"\nexit 0" > /tmp/btu/$$/$command + printf "\necho called: \$(basename \$0) \"\$@\"\nexit 0" > /tmp/btu/$$/$command chmod +x /tmp/btu/$$/$command PATH=/tmp/btu/$$:$PATH ; export PATH fi @@ -37,18 +37,22 @@ btu_init() { } btu_summary() { - echo -e "\n$(scripts/color "cyan")${#__btu_runs[*]}$(scripts/color "none") commands, ${#__btu_assertions[*]} assertions, $(scripts/color "green")${#__btu_passed[*]}$(scripts/color) passed, $(scripts/color "red")${#__btu_failed[*]}$(scripts/color) failed\n" + printf "\n$(scripts/color "cyan")${#__btu_runs[*]}$(scripts/color "none") commands, ${#__btu_assertions[*]} assertions, $(scripts/color "green")${#__btu_passed[*]}$(scripts/color) passed, $(scripts/color "red")${#__btu_failed[*]}$(scripts/color) failed\n" + local failure_count=${#__btu_failed[*]} + [[ "$failure_count" != "0" ]] && failure_count=1 unset __btu_runs __btu_assertions __btu_passed __btu_failed + return $failure_count } -btu_run() { +heat() { __btu_log "run" "$*" btu_push __btu_runs "$*" eval "$*" + result="$?" } assert() { - key=$1 ; first=$2 ; second=$3 + key="$1" ; first="$2" ; second="$3" assertion="__btu_assert_${key} \"$first\" \"$second\"" btu_push __btu_assertions $assertion eval "$assertion" @@ -175,15 +179,16 @@ __btu_assert_no_match() { __btu_assert_file_contains() { regex=$(echo "$1" | sed 's/\//\\\//g') - if [[ ! -z "$(awk "/$regex/" "$2" | cat)" ]] ; then + if [[ ! -z "$(awk "/$regex/" "$2")" ]] ; then __btu_log "pass" "/$regex/ $(scripts/color "green")is in$(scripts/color "none") '$2'" else __btu_log "fail" "/$regex/ $(scripts/color "red")is not in$(scripts/color "none") '$2'" fi ; return $? } + __btu_assert_file_does_not_contain() { regex=$(echo "$1" | sed 's/\//\\\//g') - if [[ ! -z "$(awk "/$regex/" "$2" | cat)" ]] ; then + if [[ -z "$(awk '/'$regex'/' "$2")" ]] ; then __btu_log "pass" "/$regex/ $(scripts/color "green")is not in$(scripts/color "none") '$2'" else __btu_log "fail" "/$regex/ $(scripts/color "red")is in$(scripts/color "none") '$2'" diff --git a/test/rvm/db_test b/test/rvm/db_test new file mode 100755 index 0000000000..12be19e695 --- /dev/null +++ b/test/rvm/db_test @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +source ./test/setup +initialize_rvm + +database_file="/tmp/$$.db" + +heat './scripts/db '$database_file' "akey" "avalue" 2>/dev/null' +assert number_eq 1 $result +# TODO: assert error 'Database file $database_file does not exist.' + +touch $database_file + +heat './scripts/db '$database_file' "akey" "avalue"' +assert file_contains 'akey=avalue' $database_file + +heat 'value=$(./scripts/db '$database_file' "akey")' +assert string_eq "$value" "avalue" + +heat './scripts/db '$database_file' "akey" delete' +assert file_does_not_contain 'akey=avalue' $database_file + +rm -f $database_file # Cleanup, aisle 3! + +if [[ -z "$rvm_teset_suite_flag" ]] ; then btu_summary ; fi + diff --git a/test/rvm/gemdir_test b/test/rvm/gemdir_test index 636f84411e..0e0ce70a8a 100755 --- a/test/rvm/gemdir_test +++ b/test/rvm/gemdir_test @@ -4,26 +4,38 @@ source ./test/setup initialize_rvm -btu_run 'output=$(rvm gemdir)' +heat 'output=$(rvm gemdir)' assert string_eq "$(gem env gemdir)" "$output" -btu_run 'output=$(rvm gemdir system)' +heat 'output=$(rvm gemdir system)' assert match "/Library/Ruby/Gems/1.8" "$output" -btu_run 'output=$(rvm gemdir system user)' +heat 'output=$(rvm gemdir system user)' assert match ".gem/ruby/1.8" "$output" -btu_run 'output=$(rvm gemdir user)' +heat 'output=$(rvm gemdir user)' assert match ".gem/ruby/1.8" "$output" -btu_run 'output=$(rvm jruby gemdir)' +heat 'output=$(rvm jruby gemdir)' assert match ".rvm/gems/jruby/1.4.0" "$output" -btu_run 'output=$(rvm ree gemdir)' +heat 'output=$(rvm ree gemdir)' assert match ".rvm/gems/ree/1.8.7" "$output" -btu_run 'output=$(rvm 1.9.1 gemdir)' +heat 'output=$(rvm 1.9.1 gemdir)' assert match ".rvm/gems/ruby/1.9.1" "$output" +# Gemsets +# Creating +# Using +# Global +# Listing +# Deleting +# Emptying +# Exporting +# Importing +# Copying +# Pristine + if [[ -z "$rvm_teset_suite_flag" ]] ; then btu_summary ; fi diff --git a/test/rvm/gemset_test b/test/rvm/gemset_test index 19f3dc0d8e..2b1d5e6488 100755 --- a/test/rvm/gemset_test +++ b/test/rvm/gemset_test @@ -17,110 +17,110 @@ remove_gemset_files() { rm *.gems ; } test_reset() { unset GEM_HOME ; __rvm_cleanup_variables ; } # -# As a user 'rvm gems tesset' should make my gem env gemdir be exactly the %testset$ directory. +# As a user 'rvm gems tesset' should make my gem env gemdir be exactly the ${rvm_gemset_separator}testset$ directory. # setup_testset -btu_run "rvm gems testset ; gemdir=\$(gem env gemdir)" -assert match "ruby\/1.9.1%testset$" "$gemdir" +heat "rvm gems testset ; gemdir=\$(gem env gemdir)" +assert match "ruby\/1.9.1${rvm_gemset_separator}testset$" "$gemdir" test_reset # # As a user after selecting a gemset named 'testset' 'rvm gems name' should output the string "testset" # -btu_run 'rvm gems testset ; gems=\$(rvm gems name)' +heat 'rvm gems testset ; gems=\$(rvm gems name)' assert string_eq "testset" "$gems" test_reset -btu_run 'rvm gems testset; gems_dir=\$(rvm gems dir)' -assert match "1.9.1%testset$" "$gems_dir" +heat 'rvm gems testset; gems_dir=\$(rvm gems dir)' +assert match "1.9.1${rvm_gemset_separator}testset$" "$gems_dir" test_reset -btu_run "rvm gems testset ; gem install --no-rdoc --no-ri $filename > /dev/null ; rvm gems dump" +heat "rvm gems testset ; gem install --no-rdoc --no-ri $filename > /dev/null ; rvm gems dump" assert file_exists "testset.gems" assert file_contains "^rvm" "testset.gems" test_reset ; rvm gems --force delete "testset" ; remove_gemset_files -btu_run "rvm gems testset ; gem install --no-rdoc --no-ri $filename > /dev/null ; rvm gems dump my_testset.gems" -assert no_directory "$rvm_gems_path/ruby/1.9.1%my_testset" +heat "rvm gems testset ; gem install --no-rdoc --no-ri $filename > /dev/null ; rvm gems dump my_testset.gems" +assert no_directory "$rvm_gems_path/ruby/1.9.1${rvm_gemset_separator}my_testset" assert file_exists "my_testset.gems" assert file_contains "^rvm" "my_testset.gems" test_reset ; rvm gems --force delete "testset" ; rvm gems --force delete "my_testset" ; remove_gemset_files -btu_run "rvm gems testset ; gem install --no-rdoc --no-ri $filename > /dev/null ; rvm gems dump my_testset.gems" -assert no_directory "$rvm_gems_path/ruby/1.9.1%my_testset" +heat "rvm gems testset ; gem install --no-rdoc --no-ri $filename > /dev/null ; rvm gems dump my_testset.gems" +assert no_directory "$rvm_gems_path/ruby/1.9.1${rvm_gemset_separator}my_testset" assert file_exists "my_testset.gems" assert file_does_not_exist "testset.gems" assert file_does_not_contain "^rvm" "my_testset.gems" test_reset ; rvm gems --force delete "testset" ; rvm gems --force delete "my_testset" ; remove_gemset_files -btu_run "rvm gems testset ; gem install --no-rdoc --no-ri $filename > /dev/null ; rvm gems dump my_testset2.gems" +heat "rvm gems testset ; gem install --no-rdoc --no-ri $filename > /dev/null ; rvm gems dump my_testset2.gems" assert file_exists "my_testset2.gems" assert file_contains "^rvm" "my_testset2.gems" test_reset ; rvm gems --force delete "my_testset2"; remove_gemset_files rvm gems testset ; gem_dir="$(gem env gemdir)" ; mkdir -p $gem_dir -btu_run "rvm gems testset ; gem install --no-rdoc --no-ri $filename > /dev/null ; rvm --force gems delete testset" +heat "rvm gems testset ; gem install --no-rdoc --no-ri $filename > /dev/null ; rvm --force gems delete testset" assert no_directory $gem_dir test_reset ; rvm gems --force delete "testset" -btu_run "rvm gems testset4 ; echo '$filename' > testset4.gems ; rvm gems load > /dev/null" +heat "rvm gems testset4 ; echo '$filename' > testset4.gems ; rvm gems load > /dev/null" assert match "rvm" "$(rvm gems testset4 ; gem list | tr "\n" ",")" test_reset ; rvm gems --force delete "testset4" -btu_run "rvm gems testset5 ; echo '$filename' > my_testset5.gems ; rvm gems load my_testset5.gems > /dev/null" -assert no_directory "$rvm_gems_path/ruby/1.9.1%my_testset5" +heat "rvm gems testset5 ; echo '$filename' > my_testset5.gems ; rvm gems load my_testset5.gems > /dev/null" +assert no_directory "$rvm_gems_path/ruby/1.9.1${rvm_gemset_separator}my_testset5" assert match "rvm" "$(rvm gems testset5 ; gem list | tr "\n" ",")" test_reset ; rvm gems --force delete "testset5" ; remove_gemset_files -btu_run "rvm gems testset6 ; rvm gems testset7" +heat "rvm gems testset6 ; rvm gems testset7" assert match "testset6" "$(rvm gems list | tr "\n" ", ")" assert match "testset7" "$(rvm gems list | tr "\n" ", ")" test_reset ; rvm gems --force delete "testset6" ; rvm gems --force delete "testset7" -rvm_ruby_string='1.9.1%testset8' ; valid_string="ruby-1.9.1-p243" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" -assert match "ruby\/1.9.1%testset8$" "$rvm_ruby_gem_home" +rvm_ruby_string='1.9.1${rvm_gemset_separator}testset8' ; valid_string="ruby-1.9.1-p243" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" +assert match "ruby\/1.9.1${rvm_gemset_separator}testset8$" "$rvm_ruby_gem_home" test_reset ; rvm gems --force delete "testset8" -rvm_ruby_string='ruby-1.9.1%testset9' ; valid_string="ruby-1.9.1-p243" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" -assert match "ruby\/1.9.1%testset9$" "$rvm_ruby_gem_home" +rvm_ruby_string='ruby-1.9.1${rvm_gemset_separator}testset9' ; valid_string="ruby-1.9.1-p243" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" +assert match "ruby\/1.9.1${rvm_gemset_separator}testset9$" "$rvm_ruby_gem_home" test_reset ; rvm gems --force delete "testset9" -rvm_ruby_string='ruby-1.9.1-p243%testset10' ; valid_string="ruby-1.9.1-p243" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" -assert match "ruby\/1.9.1%testset10$" "$rvm_ruby_gem_home" +rvm_ruby_string='ruby-1.9.1-p243${rvm_gemset_separator}testset10' ; valid_string="ruby-1.9.1-p243" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" +assert match "ruby\/1.9.1${rvm_gemset_separator}testset10$" "$rvm_ruby_gem_home" test_reset ; rvm gems --force delete "testset10" setup_testset -btu_run "rvm 1.9.1%testset11 ; gemdir=\$(gem env gemdir)" -assert match "ruby\/1.9.1%testset11$" "$gemdir" +heat "rvm 1.9.1${rvm_gemset_separator}testset11 ; gemdir=\$(gem env gemdir)" +assert match "ruby\/1.9.1${rvm_gemset_separator}testset11$" "$gemdir" test_reset ; rvm gems --force delete "testset11" rvm 1.9.1 ; rvm gems testset12 ; gem install --no-rdoc --no-ri $filename > /dev/null rvm ree ; rvm gems testset13 ; gem install --no-rdoc --no-ri $filename > /dev/null -btu_run "output=\"\$(rvm 1.9.1%testset12,ree%testset13 gem list)\"" +heat "output=\"\$(rvm 1.9.1${rvm_gemset_separator}testset12,ree${rvm_gemset_separator}testset13 gem list)\"" assert match "ruby-1\.9\.1-p243.*rvm" "$(echo "$output" | tr "\n" ", ")" assert match "ree-1\..*rvm" "$(echo "$output" | tr "\n" ", ")" test_reset ; rvm gems --force delete testset12 ; rvm gems --force delete testset13 -btu_run "rvm gems testset14; output=\"\$(rvm 1.9.1,ree gem env gemdir)\"" -assert match "ruby/1.9.1%testset14" "$(echo "$output" | tr "\n" ", ")" -assert match "ree/1.8.7%testset14" "$(echo "$output" | tr "\n" ", ")" +heat "rvm gems testset14; output=\"\$(rvm 1.9.1,ree gem env gemdir)\"" +assert match "ruby/1.9.1${rvm_gemset_separator}testset14" "$(echo "$output" | tr "\n" ", ")" +assert match "ree/1.8.7${rvm_gemset_separator}testset14" "$(echo "$output" | tr "\n" ", ")" test_reset ; rvm 1.9.1,ree gems --force delete testset14 -btu_run "rvm 1.9.1%testset15 ; rvm gems clear ; gemdir=\$(gem env gemdir)" -assert no_match "%testset15$" "$gemdir" +heat "rvm 1.9.1${rvm_gemset_separator}testset15 ; rvm gems clear ; gemdir=\$(gem env gemdir)" +assert no_match "${rvm_gemset_separator}testset15$" "$gemdir" test_reset ; rvm gems --force delete testset15 -btu_run "rvm 1.9.1%testset16 ; new_path=\$PATH" -assert match "%testset16" "$new_path" +heat "rvm 1.9.1${rvm_gemset_separator}testset16 ; new_path=\$PATH" +assert match "${rvm_gemset_separator}testset16" "$new_path" test_reset ; rvm gems --force delete testset16 -btu_run "rvm 1.9.1%testset17 ; rvm gems clear ; new_path=\$PATH" -assert no_match "%testset17" "$new_path" +heat "rvm 1.9.1${rvm_gemset_separator}testset17 ; rvm gems clear ; new_path=\$PATH" +assert no_match "${rvm_gemset_separator}testset17" "$new_path" test_reset ; rvm gems --force delete testset17 # TODO: Honor full path to a gem file. rvm 1.9.1 ; rvm gems testset18 ; echo "$(pwd)/$(\ls rvm-*.gem | head -n 1)" > testset18.gems -btu_run "rvm 1.9.1%testset18 ; gem_list=\$(gem list)" +heat "rvm 1.9.1${rvm_gemset_separator}testset18 ; gem_list=\$(gem list)" assert no_match "rvm" "$gem_list" test_reset ; rvm gems --force delete testset18 diff --git a/test/rvm/rvm-prompt_test b/test/rvm/rvm-prompt_test index 8a9432633d..2d4c1758c7 100755 --- a/test/rvm/rvm-prompt_test +++ b/test/rvm/rvm-prompt_test @@ -4,35 +4,44 @@ source ./test/setup initialize_rvm -btu_run "prompt=\$(rvm 1.9.1 ; scripts/rvm-prompt)" -assert string_eq "[ruby-1.9.1-p243]" "$prompt" +heat "prompt=\$(rvm 1.9.1 ; binscripts/rvm-prompt)" +assert string_eq "ruby-1.9.1-p378" "$prompt" -btu_run "prompt=\$(rvm 1.9.1-head ; scripts/rvm-prompt)" -assert string_eq "[ruby-1.9.1-head]" "$prompt" +heat "prompt=\$(rvm 1.9.2-preview3 ; binscripts/rvm-prompt)" +assert string_eq "ruby-1.9.2-preview3" "$prompt" -btu_run "prompt=\$(rvm 1.8.6 ; scripts/rvm-prompt)" -assert string_eq "[ruby-1.8.6-p383]" "$prompt" +heat "prompt=\$(rvm 1.8.6 ; binscripts/rvm-prompt)" +assert string_eq "ruby-1.8.6-p399" "$prompt" -btu_run "prompt=\$(rvm ree ; scripts/rvm-prompt)" -assert string_eq "[ree-1.8.7-2009.10]" "$prompt" +heat "prompt=\$(rvm ree ; binscripts/rvm-prompt)" +assert string_eq "ree-1.8.7-2010.02" "$prompt" -btu_run "prompt=\$(rvm ree ; ./scripts/rvm-prompt i)" -assert "string_eq" "[ree]" "$prompt" +heat "prompt=\$(rvm ree ; binscripts/rvm-prompt i)" +assert string_eq "ree" "$prompt" -btu_run "prompt=\$(rvm ree ; ./scripts/rvm-prompt i v)" -assert "string_eq" "[ree-1.8.7]" "$prompt" +heat "prompt=\$(rvm ree ; binscripts/rvm-prompt i v)" +assert string_eq "ree-1.8.7" "$prompt" -btu_run "prompt=\$(rvm ree ; ./scripts/rvm-prompt v)" -assert "string_eq" "[1.8.7]" "$prompt" +heat "prompt=\$(rvm ree ; binscripts/rvm-prompt v)" +assert string_eq "1.8.7" "$prompt" -btu_run "prompt=\$(rvm ree ; ./scripts/rvm-prompt v p)" -assert "string_eq" "[1.8.7-2009.10]" "$prompt" +heat "prompt=\$(rvm ree ; binscripts/rvm-prompt v p)" +assert string_eq "1.8.7-2010.02" "$prompt" -btu_run "prompt=\$(rvm ree-head ; scripts/rvm-prompt)" -assert string_eq "[ree-1.8.7-head]" "$prompt" +heat "prompt=\$(rvm 1.8.7-head ; binscripts/rvm-prompt)" +assert string_eq "ruby-1.8.7-head" "$prompt" -btu_run "prompt=\$(rvm 1.9.1 ; scripts/rvm-prompt p v i)" -assert string_eq "[p243-1.9.1-ruby]" "$prompt" +heat "prompt=\$(rvm 1.9.2 ; binscripts/rvm-prompt s p v i)" +assert string_eq "preview3-1.9.2-ruby" "$prompt" + +heat "prompt=\$(rvm system ; binscripts/rvm-prompt)" +assert string_eq "" "$prompt" + +heat "prompt=\$(rvm system ; binscripts/rvm-prompt s p v i)" +assert string_eq "system" "$prompt" + +heat "prompt=\$(rvm ree ; binscripts/rvm-prompt u v g)" +assert string_eq "✈-1.8.7" "$prompt" if [[ -z "$rvm_teset_suite_flag" ]] ; then btu_summary ; fi diff --git a/test/rvm/selector_test b/test/rvm/selector_test index 22007c407b..ca045e4414 100755 --- a/test/rvm/selector_test +++ b/test/rvm/selector_test @@ -20,32 +20,32 @@ validate_select() { } for valid_string in $(echo $rubies) ; do - btu_run "rvm_ruby_string='$valid_string' ; __rvm_select" + heat "rvm_ruby_string='$valid_string' ; __rvm_select" validate_select done -rvm_ruby_string="1.8.5" ; valid_string="ruby-1.8.5-p231" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="1.8.5-tv1_8_5" ; valid_string="ruby-1.8.5-tv1_8_5" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="ruby-1.8.5" ; valid_string="ruby-1.8.5-p231" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="1.8.6" ; valid_string="ruby-1.8.6-p383" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="ruby-1.8.6" ; valid_string="ruby-1.8.6-p383" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="1.8.7" ; valid_string="ruby-1.8.7-p174" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="ruby-1.8.7" ; valid_string="ruby-1.8.7-p174" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="1.9.1" ; valid_string="ruby-1.9.1-p243" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="ruby-1.9.1" ; valid_string="ruby-1.9.1-p243" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="ree-1.8.6" ; valid_string="ree-1.8.6-20090610" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="ree" ; valid_string="ree-1.8.7-2009.10" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="ree-1.8.7" ; valid_string="ree-1.8.7-2009.10" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="ree-head" ; valid_string="ree-1.8.7-head" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="jruby-1.4.0" ; valid_string="jruby-1.4.0RC3" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="jruby-1.3.1" ; valid_string="jruby-1.3.1" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="jruby" ; valid_string="jruby-1.3.1" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select -rvm_ruby_string="mput" ; valid_string="mput-head" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select - -valid_string="ruby-1.8.6-p160" ; btu_run "rvm 1.8.7 -l 160 ; version=\$(ruby -v)" +rvm_ruby_string="1.8.5" ; valid_string="ruby-1.8.5-p231" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="1.8.5-tv1_8_5" ; valid_string="ruby-1.8.5-tv1_8_5" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="ruby-1.8.5" ; valid_string="ruby-1.8.5-p231" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="1.8.6" ; valid_string="ruby-1.8.6-p383" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="ruby-1.8.6" ; valid_string="ruby-1.8.6-p383" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="1.8.7" ; valid_string="ruby-1.8.7-p174" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="ruby-1.8.7" ; valid_string="ruby-1.8.7-p174" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="1.9.1" ; valid_string="ruby-1.9.1-p243" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="ruby-1.9.1" ; valid_string="ruby-1.9.1-p243" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="ree-1.8.6" ; valid_string="ree-1.8.6-20090610" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="ree" ; valid_string="ree-1.8.7-2009.10" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="ree-1.8.7" ; valid_string="ree-1.8.7-2009.10" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="ree-head" ; valid_string="ree-1.8.7-head" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="jruby-1.4.0" ; valid_string="jruby-1.4.0RC3" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="jruby-1.3.1" ; valid_string="jruby-1.3.1" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="jruby" ; valid_string="jruby-1.3.1" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string="mput" ; valid_string="mput-head" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select + +valid_string="ruby-1.8.6-p160" ; heat "rvm 1.8.7 -l 160 ; version=\$(ruby -v)" assert "match" '^ruby 1.8.7 \(2009-04-08 patchlevel 160\)' "$version" ; unset version -rvm_ruby_string='1.9.1-r25443' ; valid_string="ruby-1.9.1-r25443" ; btu_run "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select +rvm_ruby_string='1.9.1-r25443' ; valid_string="ruby-1.9.1-r25443" ; heat "rvm_ruby_string=$rvm_ruby_string ; __rvm_select" ; validate_select if [[ -z $rvm_teset_suite_flag ]] ; then btu_summary ; fi diff --git a/test/rvm/use_test b/test/rvm/use_test index 8b1cb54949..c7fa62b1f4 100755 --- a/test/rvm/use_test +++ b/test/rvm/use_test @@ -7,7 +7,7 @@ initialize_rvm # rvm_ruby_string=$ruby ; __rvm_select ; __rvm_use # for binary in ruby rake gem irb ; do # value=$(__btu_db "test/rubies/$ruby" $binary) -# assert_match $value "$(which $binary)" +# assert_match $value "$(command -v $binary)" # done # unset $rvm_ruby_selected_flag #done diff --git a/test/rvm/utility_test b/test/rvm/utility_test index 1199ad8472..efa7314ddc 100755 --- a/test/rvm/utility_test +++ b/test/rvm/utility_test @@ -3,40 +3,40 @@ source ./test/setup initialize_rvm -unset result ; btu_run 'match "a" "a" ; result=$?' +heat './scripts/match "a" "a"' assert number_eq 0 $result -unset result ; btu_run 'match "snark" "a" ; result=$?' +heat './scripts/match "snark" "a"' assert number_eq 0 $result -unset result ; btu_run 'match "snark" "^s" ; result=$?' +heat './scripts/match "snark" "^s"' assert number_eq 0 $result -unset result ; btu_run 'match "snark" "k$" ; result=$?' +heat './scripts/match "snark" "k$"' assert number_eq 0 $result -unset result ; btu_run 'match "snark" "s$" ; result=$?' +heat './scripts/match "snark" "s$"' assert number_eq 1 $result -unset result ; btu_run 'match "snark" "^k" ; result=$?' +heat './scripts/match "snark" "^k"' assert number_eq 1 $result -unset result ; btu_run 'match "1.9.1" "^[0-9]\.[0-9]" ; result=$?' +heat './scripts/match "1.9.1" "^[0-9]\.[0-9]"' assert number_eq 0 $result -unset result ; btu_run 'match "snark.rb" "\.rb$" ; result=$?' +heat './scripts/match "snark.rb" "\.rb$"' assert number_eq 0 $result -unset result ; btu_run 'match "snark.gems" "\.gems$" ; result=$?' +heat './scripts/match "snark.gems" "\.gems$"' assert number_eq 0 $result -unset result ; btu_run 'match "snark.gem" "\.gem$" ; result=$?' +heat './scripts/match "snark.gem" "\.gem$"' assert number_eq 0 $result -unset result ; btu_run 'match "1.9.1%snark" "^.+%.+$" ; result=$?' +heat './scripts/match "1.9.1${rvm_gemset_separator}snark" "^.+${rvm_gemset_separator}.+$"' assert number_eq 0 $result -unset result ; btu_run 'match "1.9.1" "^.+%.+$" ; result=$?' +heat './scripts/match "1.9.1" "^.+${rvm_gemset_separator}.+$"' assert number_eq 1 $result if [[ -z "$rvm_teset_suite_flag" ]] ; then btu_summary ; fi diff --git a/test/setup b/test/setup index b3b9e8cafa..51cdd8770f 100644 --- a/test/setup +++ b/test/setup @@ -2,7 +2,7 @@ if [[ -z "$test_setup_flag" ]] ; then rvm_path=~/.rvm-test ; export rvm_path - ./install + ./install >/dev/null source scripts/rvm rubies=$(\ls test/rubies/) @@ -10,7 +10,6 @@ if [[ -z "$test_setup_flag" ]] ; then __rvm_cleanup_variables __rvm_load_rvmrc __rvm_initialize - __rvm_load_defaults } # Load the Bash Test::Unit Framework diff --git a/test/suite b/test/suite index f2aedaef23..da6d636978 100755 --- a/test/suite +++ b/test/suite @@ -1,9 +1,9 @@ #!/usr/bin/env bash source ./test/setup -rvm_teset_suite_flag=1 +rvm_test_suite_flag=1 for file in test/rvm/*_test ; do source $file done btu_summary - +exit $?