RVM/rbenv 项目目录下的.rvmrc 文件

actberw · 2012年12月11日 · 最后由 sforce100 回复于 2013年03月07日 · 3657 次阅读

如果在项目目录下有.rvmrc 文件,内容为:rvm use ruby-1.9.3-p194@gemsetname 在 cd 到项目目录时自动执行相关的 hook,请问下这个是怎么实现的?

应该是被这个脚本 Hack 了

$ cat ~/.rvm/scripts/cd


#!/usr/bin/env bash

# Source a .rvmrc file in a directory after changing to it, if it exists.  To
# disable this feature, set rvm_project_rvmrc=0 in /etc/rvmrc or $HOME/.rvmrc
if (( ${rvm_project_rvmrc:-1} > 0 ))
then
  __rvm_setup_cd()
  {
    # try to use smartcd function, fallback to builtin
    typeset __cd_prefix __command
    if typeset -f smartcd >/dev/null 2>/dev/null
    then __cd_prefix="smartcd"
    else __cd_prefix="builtin"
    fi

    __rvm_after_cd()
    {
      typeset rvm_hook
      rvm_hook="after_cd"
      if [[ -n "${rvm_scripts_path:-}" || -n "${rvm_path:-}" ]]
      then source "${rvm_scripts_path:-$rvm_path/scripts}/hook"
      fi
    }

    __rvm_setup_cd_function()
    {
      typeset __cd_prefix __command
      __cd_prefix=$1
      __command=$2
      eval "
${__command}(){
  if ${__cd_prefix} ${__command} \"\$@\"
  then
    [[ -n \"\${rvm_current_rvmrc:-""}\" && \"\$*\" == \".\" ]] && rvm_current_rvmrc=\"\" || true
    __rvm_do_with_env_before
    __rvm_project_rvmrc
    __rvm_after_cd
    __rvm_do_with_env_after
    return 0
  else
    return \$?
  fi
}"
    }

    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
        export -a chpwd_functions
        chpwd_functions=( "${chpwd_functions[@]}" __rvm_do_with_env_before __rvm_project_rvmrc __rvm_after_cd __rvm_do_with_env_after )
      else
        for __command in cd popd pushd
        do __rvm_setup_cd_function "${__cd_prefix}" "${__command}"
        done
      fi
    else
      for __command in cd popd pushd
      do __rvm_setup_cd_function "${__cd_prefix}" "${__command}"
      done
    fi
  }
  __rvm_setup_cd
  # This functionality is opt-in by setting rvm_cd_complete_flag=1 in ~/.rvmrc
  # Generic bash cd completion seems to work great for most, so this is only
  # for those that have some issues with that.
  if (( ${rvm_cd_complete_flag:-0} == 1 ))
  then
    # If $CDPATH is set, bash should tab-complete based on directories in those paths,
    # but with the cd function above, the built-in tab-complete ignores $CDPATH. This
    # function returns that functionality.
    _rvm_cd_complete ()
    {
      typeset directory current matches item index sep
      sep="${IFS}"
      export IFS
      IFS=$'\n'
      COMPREPLY=()
      current="${COMP_WORDS[COMP_CWORD]}"
      if [[ -n "$CDPATH" && ${current:0:1} != "/" ]] ; then
        index=0
        # The change to IFS above means that the \tr below should replace ':'
        # with a newline rather than a space. A space would be ignored, breaking
        # TAB completion based on CDPATH again
        for directory in $(printf "%b" "$CDPATH" | \tr -s ':' '\n') ; do
          for item in $( compgen -d "$directory/$current" ) ; do
            COMPREPLY[index++]=${item#$directory/}
          done
        done
      else
        COMPREPLY=( $(compgen -d ${current}) )
      fi
      IFS="${sep}";
    }
    complete -o bashdefault -o default -o filenames -o dirnames -o nospace -F _rvm_cd_complete cd
  fi
fi

#1 楼 @huacnlee 意思是对 shell cd 命令做了包装,增加了 hook,实际调用的是这个包装后的 cd 命令?

你可以看下 diaspora 这个开源项目,cd 进去的时候会切换到指定的 ruby@gemset ,实现也是比较简单的,你可以看下它是如何实现的。在 script/env 目录下面可以指定 ruby 和 gemset 的。

我也中招了

需要 登录 后方可回复, 如果你还没有账号请 注册新账号