rvm install via capistrano is flooding output - bash

I'm running a shell script via capistrano to install rvm and ruby. When running
rvm install ruby-${RUBY_VERSION} 2>&1 > ../log/ruby_install.log
in my script, all output seems to be going to the log file, except for the scrollbar output. that output is being sent back to capistrano and it's flooding the output, and looks horrible.
Is there any way I can hide the progress during the command?
I tried running
alias curl="curl --silent"
before the command, but it doesn't work at all, so I guess the install is happening via some other means.

Try:
gem install rvm-capistrano -v ">=1.3.0.rc11"
It contains code to make curl silent

The answer from #mpapis lead me to the following solution:
# Rename .curlrc if present
if [[ -f $HOME/.curlrc ]]; then
echo "Backing up .curlrc"
mv $HOME/.curlrc $HOME/.curlrc~
fi
# Create a temporary .curlrc configuration file, this prevents curl from flooding the Capistrano output
{
echo "insecure"
echo "silent" # Hide verbose output, it floods the capistrano output
echo "show-error"
} > $HOME/.curlrc
I added the above snippet to my bash script, and at the end, I just restored .curlrc to it's previous state:
rm $HOME/.curlrc
if [[ -f $HOME/.curlrc~ ]]; then
mv $HOME/.curlrc~ $HOME/.curlrc
fi
This is modified from rvm-capistrano, check it out on the original Github Repository.

Related

How to check if a gem installed on a machine in bash script?

I want to be able to run a system command from script
bundle exec rubocop
but only if bundle and rubocop gems installed and exist on a machine. If the checks for the existence of these gems fail, ignore the command and exit.
How is it possible to setup these checks before running the command? Maybe I should use bundle --version and see if the command crashes or not? Thank you in advance.
You can grep your installed gems like this
#!/bin/bash
if ! gem list --local | grep -q 'bundler'; then
echo 'Please install bundler first'
exit 1
fi
if ! gem list --local | grep -q 'rubocop'; then
echo 'Please install rubocop first'
exit 1
fi
bundle exec rubocop
An alternative approach to the one(s) suggested before: testing not if the gems are installed, but if the appropriate commands are available (which is not necessarily the same):
#!/bin/bash
if type bundle >/dev/null 2>&1; then
if type rubocop >/dev/null 2>&1; then
bundle exec rubocop
else
echo "Rubocop seems to be not available"
exit 1
fi
else
echo "Bundler seems to be not available"
exit 1
fi
(this script could be better, for example, to report all the missing commands instead of just the 1st encountered, but it's just a quick sketch to illustrate the idea)

Running programs only if they are installed, and ignoring them otherwise

When writing shell scripts, is the an idiom or swift way to run a program only if it is installed, and if it is not, just let it be (or handle the error in some other way apart from installing it)?
More specifically, I have a lot of servers which I access over ssh, and whenever I get a new server, I simply copy all my rc-files to it. The .zshrc starts tmux unless it is already running. Some of the servers (not all) do not have tmux installed. I do not want to install it because of disk space limitations, I do not want to have different rc-files for different servers, and I do not want my rc-files to be interrupted when executing them.
I have seen solutions involving apt-cache policy <package-name>, so I guess I could use that and pipe it to something like grep -e 'Installed: (none)', but that would assume that the server is running Debian or Ubuntu, which I can not do, and it would only work for packages that were installed with apt, not things I have installed in other ways.
command -v <command> is the common (and POSIX) way to check if a command could be executed (is executable and on the $PATH).
E.g:
command -v tmux >/dev/null &&
tmux a -t name
(>/dev/null since, if the command exists, its path will be printed to STDOUT.)
It could be nice to put it in a reusable function:
maybe() {
! command -v "${1}" >/dev/null ||
"$#"
}
Then one could use:
maybe tmux a -t name
And if tmux is available then tmux a -t name will be run, otherwise it’ll be silently ignored.
Or, if you want some feedback when a command is not available:
maybe() {
if command -v "${1}" >/dev/null
then
"$#"
else
printf 'Command "%s" not available, skipping\n' "${1}" >&2
fi
}
This might help-
1) Assuming tmux is available in PATH (as it must be executable)
isAvailable=$(type -P tmux)
if [[ -x $isAvailable ]]; then
...
2) Verify file is present on a specific path (Copying all rc-files)
export FILEPATH="..."
if[[ -f $FILEPATH ]]; then

Installing Jekyll without root

I want to set up a jekyll blog on a shared server. When I try to install Jekyll I get "You don't have write permissions". How do I fix this without root or sudo?
More detail:
I have space on a shared server and don't have root access. I couldn't install Ruby, though the hosting company installed it upon my request.
When I try to install Jekyll I use
user#hosting.org [~]# gem install jekyll
and this is the response I get:
ERROR: While executing gem ... (Gem::FilePermissionError)
You don't have write permissions into the /usr/lib/ruby/gems/1.8 directory.
I have seen different suggestions for changing the GEMPATH which I have tried including
export GEM_PATH=/home/user/something
But even after doing so
gem env
still results in
GEM PATHS:
- /usr/lib/ruby/gems/1.8
- /home/user/.gem/ruby/1.8
Any tips? Is it possible to install jekyll without root or sudo priviliges or am I just making some rookie PATH error?
I didn't find the answer for a while. on the #jekyll IRC a user pointed me at the Arch wiki and I discovered that the thing is to force the install as a single user:
gem install jekyll --user-install
This worked for me in MAC
1.Place the gems in user's home folder.Add below commands in .bashrc or .zshrc
export GEM_HOME=$HOME/gems
export PATH=$HOME/gems/bin:$PATH
2.Use installation command
gem install jekyll bundler
3.Verify Installation
jekyll -v
Use the documentation for detailed reference
https://jekyllrb.com/docs/troubleshooting/#no-sudo
The reason for that is the default Ruby that gets shipped with Mac (I am assuming this, but this is true for some distributions of Linux as well) installs gems to a user folder that needs permissions to modify the contents. This is not a Ruby error to be precise.
That said, since Ruby 1.8.7 is not supported any more, you'd be better off avoiding using it and using one of the alternative ruby version managing tools like chruby or rvm or rbenv. (I'd vote for chruby btw). The documentation is pretty dense for all those. The authors are quite helpful in resolving issues if you do end up having one or more.
... am I just making some rookie PATH error?
Yes, I think so... I'm not sure why you're assigning GEM_PATH, I haven't needed to, and think ya perhaps wanted GEM_HOME instead. Though things may have changed since then and the current now that this'll be posted at.
TLDR
I usually write something such as...
## Ruby exports for user level gem & bundle installs
export GEM_HOME="${HOME}/.gem"
export PATH="${GEM_HOME}/bin:${PATH}"
... to somewhere like ~/.bash_aliases for each user that'll be authenticating to a server.
Then within any git-shell-commands script, for an authenticated user that makes use of Gems, source the above settings prior.
I want to set up a jekyll blog on a shared server. When I try to install Jekyll I get "You don't have write permissions". How do I fix this without root or sudo?
Might be worth checking out a project I've published a little while ago. It's been written and tested on Linux systems with Bash versions >= 4 if you sort out Mac feel free to make a PR. Otherwise, for shared servers, the least amount of fuss may be had by sticking with Xenial, from Ubuntu, or the freshest Raspberry flavored Debian.
Here's some snippets that should aid in automating an answer to your question...
/usr/local/etc/Jekyll_Admin/shared_functions/user_mods/jekyll_gem_bash_aliases.sh
#!/usr/bin/env bash
jekyll_gem_bash_aliases(){ ## jekyll_gem_bash_aliases <user>
local _user="${1:?No user name provided}"
local _home="$(awk -F':' -v _user="${_user}" '$0 ~ "^" _user ":" {print $6}' /etc/passwd)"
if [ -f "${_home}/.bash_aliases" ]; then
printf '%s/.bash_aliases already exists\n' "${_home}" >&2
return 1
fi
## Save new user path variable for Ruby executables
su --shell "$(which bash)" --command 'touch ${HOME}/.bash_aliases' --login "${_user}"
tee -a "${_home}/.bash_aliases" 1>/dev/null <<'EOF'
## Ruby exports for user level gem & bundle installs
export GEM_HOME="${HOME}/.gem"
export PATH="${GEM_HOME}/bin:${PATH}"
EOF
su --shell "$(which bash)" --command 'chmod u+x ${HOME}/.bash_aliases' --login "${_user}"
printf '## %s finished\n' "${FUNCNAME[0]}"
}
The above is used by one of three scripts that make use of sudo level permissions, specifically jekyll_usermod.sh... but don't get too caught-up with grokking all the contortions that I'm asking of Bash, because the moral of the above function's story is that it writes something like...
## Ruby exports for user level gem & bundle installs
export GEM_HOME="${HOME}/.gem"
export PATH="${GEM_HOME}/bin:${PATH}"
... to somewhere like /srv/bill/.bash_aliases which'll get sourced in git-shell-commands scripts and/or other shared functions for account setup like the following...
/usr/local/etc/Jekyll_Admin/shared_functions/user_mods/jekyll_user_install.sh
#!/usr/bin/env bash
jekyll_user_install(){ ## jekyll_user_install <user>
local _user="${1:?No user name provided}"
su --shell "$(which bash)" --login "${_user}" <<'EOF'
source "${HOME}/.bash_aliases"
mkdir -vp "${HOME}"/{git,www}
## Initialize Jekyll repo for user account
_old_PWD="${PWD}"
mkdir -vp "${HOME}/git/${USER}"
cd "${HOME}/git/${USER}"
git init .
git checkout -b gh-pages
_ruby_version="$(ruby --version)"
printf 'Ruby Version: %s\n' "${_ruby_version}"
_ruby_version="$(awk '{print $2}' <<<"${_ruby_version%.*}")"
_ruby_version_main="${_ruby_version%.*}"
_ruby_version_sub="${_ruby_version#*.}"
if [[ "${_ruby_version_main}" -ge '2' ]] && [[ "${_ruby_version_sub}" -ge '1' ]]; then
gem install bundler -v '< 2'
gem install jekyll -v '3.8.5'
bundle init
bundle install --path "${HOME}/.bundle/install"
bundle add jekyll-github-metadata github-pages
bundle exec jekyll new --force --skip-bundle "${HOME}/git/${USER}"
bundle install
else
echo 'Please see to installing Ruby verion >= 2.4' >&2
echo 'Hints may be found at, https://jekyllrb.com/docs/installation/' >&2
fi
git config receive.denyCurrentBranch updateInstead
cat >> "${HOME}/git/${USER}/.gitignore" <<EOL
# Ignore files and folders generated by Bundler
Bundler
vendor
.bundle
Gemfile.lock
EOL
git add --all
git -c user.name="${USER}" -c user.email="${USER}#${HOSTNAME}" commit -m "Added files from Bundler & Jekyll to git tracking"
cd "${_old_PWD}"
EOF
local _exit_status="${?}"
printf '## %s finished\n' "${FUNCNAME[0]}"
return "${_exit_status}"
}
Note, .bash_aliases is arbitrary as far as file naming, well so long as one is consistent, it could even be more explicit via something like .gems_aliases; end-users need not know what happens behind the curtains to make this magic happen in other words.
... which'll hopefully show one clear method of causing gem install someThing and related commands to search the user's installed packages first. Though in case another example is needed...
~/git-shell-commands/jekyll-init
#!/usr/bin/env bash
__SOURCE__="${BASH_SOURCE[0]}"
while [[ -h "${__SOURCE__}" ]]; do
__SOURCE__="$(find "${__SOURCE__}" -type l -ls | sed -n 's#^.* -> \(.*\)#\1#p')"
done
__DIR__="$(cd -P "$(dirname "${__SOURCE__}")" && pwd)"
__NAME__="${__SOURCE__##*/}"
__AUTHOR__='S0AndS0'
__DESCRIPTION__='Initializes new Git repository with a gh-pages branch'
## Provides 'failure'
# source "${__DIR__}/shared_functions/failure"
# trap 'failure "LINENO" "BASH_LINENO" "${BASH_COMMAND}" "${?}"' ERR
## Provides: argument_parser <arg-array-reference> <acceptable-arg-reference>
source "${__DIR__}/shared_functions/arg_parser"
## Provides: git_add_commit <string>
source "${__DIR__}/shared_functions/git_shortcuts"
## Provides: __license__ <description> <author>
source "${__DIR__}/shared_functions/license"
usage(){
_message="${1}"
_repo_name="${_repo_name:-repository-name}"
cat <<EOF
## Usage
# ssh ${USER}#host-or-ip ${__NAME__} ${_git_args[#]:-$_repo_name}
#
# ${__DESCRIPTION__}
#
# --quite
# Git initializes quietly
#
# --shared
# Allow git push for group $(groups | awk '{print $1}')
#
# --template=<path>
# Template git repository that git init should pull from
#
# ${_repo_name}
# Name of repository to internalize or add Jekyll gh-pages branch to
#
## For detailed documentation of the above options.
## See: git help init
#
# --clean
# Remove non-git related files and directories from gh-pages branch prior to
# initializing Jekyll related files. This allows for files from previous branch
# to remain separate from files being tracked on the gh-pages branch.
#
# -l --license
# Shows script or project license then exits
#
# -h --help help
# Displays this message and exits
#
## The following options maybe used to modify the generated _config.yml file
#
# --title ${_title}
# --email ${_email}
# --twitter-username ${_twitter_username}
# --github-username ${_github_username}
EOF
if [ -n "${_message}" ] && [[ "${_message}" != '0' ]]; then
printf 'Error - %s\n' "${_message}" >&2
fi
}
_args=("${#:?# No arguments provided try: ${__NAME__} help}")
_valid_args=('--help|-h|help:bool'
'--license|-l|license:bool'
'--quiet:bool'
'--clean:bool'
'--shared:bool'
'--template:path'
'--title:print'
'--email:print'
'--twitter-username:posix'
'--github-username:posix'
'--repo-name:posix-nil')
argument_parser '_args' '_valid_args'
_exit_status="$?"
_git_args=()
if ((_quiet)); then _git_args+=('--quiet'); fi
if ((_shared)); then _git_args+=('--shared'); fi
if [ -n "${_template}" ]; then _git_args+=("--template='${_template}'"); fi
if [ -n "${_repo_name}" ]; then _git_args+=("${_repo_name}"); fi
## Set defaults for some variables if not already set
_github_username="${_github_username:-$USER}"
if [ -z "${_title}" ]; then
for _word in ${_repo_name//[-_]/ }; do
if [[ "${#_word}" -ge '4' ]]; then
_temp_title+=("${_word^}")
else
_temp_title+=("${_word}")
fi
done
_title="${_temp_title[#]}"
fi
_bundle_path="${HOME}/.bundle/install"
if ((_help)) || ((_exit_status)); then
usage "${_exit_status}"
exit "${_exit_status}"
elif ((_license)); then
__license__ "${__DESCRIPTION__}" "${__AUTHOR__}"
exit 0
fi
if [ -z "${_repo_name}" ]; then
usage 'missing repository name argument!'
exit "1"
fi
_git_path="${HOME}/git/${_repo_name:?No repository name provided}"
_old_PWD="${PWD}"
if [ -d "${_git_path}" ]; then cd "${_git_path}"; fi
_git_dir="$(git rev-parse --git-dir 2>/dev/null)"
if [[ "${_git_path}/${_git_dir}" == "${_git_path}/.git" ]]; then
printf '# Skipping git init, path already tracked by git: %s\n' "${_git_preexisting_dir}"
elif [[ "${_git_path}/${_git_dir}" == "${_git_path}/." ]]; then
echo '# Bare git repository detected, cannot install Jekyll to that right now'
exit 1
else
if [ -e "${HOME}/git-shell-commands/git-init" ]; then
"${HOME}/git-shell-commands/git-init" ${_git_args[#]}
else
cd "${HOME}/git" || exit 1
git init ${_git_args[#]}
fi
fi
cd "${_git_path}" || exit 1
_git_branches="$(git branch --list)"
_orig_branch="$(awk '/\*/{print $2}' <<<"${_git_branches}")"
_pages_branch="$(awk '/gh-pages/{print $2}' <<<"${_git_branches}")"
if [ -n "${_pages_branch}" ]; then
printf '# There is already a pages branch %s for repository %s\n' "${_pages_branch}" "${_repo_name}"
exit 1
fi
git_add_commit "Added files on ${_orig_branch} prior to installing Bundler & Jekyll to gh-pages branch"
git checkout -b gh-pages
if [[ "$(git config receive.denyCurrentBranch)" != 'updateInstead' ]]; then
git config receive.denyCurrentBranch updateInstead
fi
if ((_clean)); then
for _path in ${_git_path}/*; do
case "${_path}" in
*'.git') [[ -d "${_path}" ]] && continue ;;
*'.gitignore') [[ -f "${_path}" ]] && continue ;;
esac
git rm -rf "${_path}"
done
git_add_commit 'Cleaned gh-pages branch of files from parent branch'
fi
modify_config_yml(){
if ! [ -f "${_git_path}/_config.yml" ]; then
printf 'Error - no Jekyll config file found under %s\n' "${_git_path}" >&2
return 1
fi
if [ -n "${_title}" ]; then
sed -i "/title:/ { s#:[a-zA-Z 0-9]*#: ${_title}#; }" "${_git_path}/_config.yml"
fi
if [ -n "${_email}" ]; then
sed -i "/email:/ { s#:[a-zA-Z 0-9]*#: ${_email}#; }" "${_git_path}/_config.yml"
fi
if [ -n "${_twitter_username}" ]; then
sed -i "/_twitter_username:/ { s#:[a-zA-Z 0-9]*#: ${_twitter_username}#; }" "${_git_path}/_config.yml"
fi
if [ -n "${_github_username}" ]; then
sed -i "/github_username:/ { s#:[a-zA-Z 0-9]*#: ${_github_username}#; }" "${_git_path}/_config.yml"
fi
if [[ "${_repo_name}" != "${_github_username}" ]]; then
tee -a "${_git_path}/_config_baseurl.yml" 1>/dev/null <<EOF
# Use base URL to simulate GitHub pages behaviour
baseurl: "${_repo_name}"
EOF
fi
}
source "${HOME}/.bash_aliases"
bundle init || exit "${?}"
bundle install --path "${_bundle_path}"
bundle add jekyll
bundle exec jekyll new --force --skip-bundle "${_git_path}"
modify_config_yml
bundle install
cat >> "${_git_path}/.gitignore" <<EOF
# Ignore files and folders generated by Bundler
Bundler
vendor
.bundle
Gemfile.lock
EOF
git_add_commit 'Added files from Bundler & Jekyll to git tracking'
[[ "${_old_PWD}" == "${_git_path}" ]] || cd "${_old_PWD}"
printf '# Clone %s via: git clone %s#domain_or_ip:%s\n' "${_repo_name}" "${USER}" "${_git_path//${HOME}\//}"
printf '# %s finished\n' "${__NAME__}"
... which also shows how to bundle install someThing to somewhere.
Good luck with the publishing and perhaps comment if ya get stuck.

TextMate doesn't work with .rvmrc anymore after collegue changed it

Some while ago, our .rvmrc file looked like this (pretty default):
#!/usr/bin/env bash
# This is an RVM Project .rvmrc file, used to automatically load the ruby
# development environment upon cd'ing into the directory
# First we specify our desired <ruby>[#<gemset>], the #gemset name is optional,
# Only full ruby name is supported here, for short names use:
# echo "rvm use 1.9.3" > .rvmrc
#environment_id="ruby-1.9.3-p0#iq"
environment_id="ruby-1.9.3-p0"
# Uncomment the following lines if you want to verify rvm version per project
# rvmrc_rvm_version="1.14.1 (master)" # 1.10.1 seams as a safe start
# eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
# echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
# return 1
# }
# First we attempt to load the desired environment directly from the environment
# file. This is very fast and efficient compared to running through the entire
# CLI and selector. If you want feedback on which environment was used then
# insert the word 'use' after --create as this triggers verbose mode.
if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
then
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
[[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
\. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
else
# If the environment file has not yet been created, use the RVM CLI to select.
rvm --create "$environment_id" || {
echo "Failed to create RVM environment '${environment_id}'."
return 1
}
fi
# If you use bundler, this might be useful to you:
# if [[ -s Gemfile ]] && {
# ! builtin command -v bundle >/dev/null ||
# builtin command -v bundle | GREP_OPTIONS= \grep $rvm_path/bin/bundle >/dev/null
# }
# then
# printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n"
# gem install bundler
# fi
# if [[ -s Gemfile ]] && builtin command -v bundle >/dev/null
# then
# bundle install | GREP_OPTIONS= \grep -vE '^Using|Your bundle is complete'
# fi
To be used with RubyMine, a collegue changed it to the following
rvm ruby-1.9.3-p0 --create
The bad is, that my TextMate now automatically switches to Ruby 1.8.7 when executing a file from within the folder, so it doesn't work with this anymore (but before, it did by setting the TM_RUBY variable to /Users/josh/.rvm/bin/rvm-auto-ruby). As I'm the only TextMate user, I'm on my own now to figure out what's wrong. Anybody has an idea?
When I remove the .rvmrc file, then it loads the default RVM ruby version - if it's there, it loads the system ruby (1.8.7).
I also tried the wrapper approach, described on the rvm page, but this also loads the system ruby (1.8.7).
Thanks for any help! Josh
check the docs at RVM Site Texmate integration

Why does it take a long time to change directories after installing RVM

I just installed RVM and it seems the cd command is taking an extra couple of seconds, why is this happening? Is there any way to fix this?
This has been resolved in 0.1.39 and later versions of RVM. The behavior now only sources the .rvmrc file when you enter a projects directory tree for the first time. Subsequent cd's within that directory tree do not source the .rvmrc file. If you find yourself constantly jumping into and out of your projects directory tree, I would recommend using multiple terminals :)
One side benefit of this is you can now put more time-consuming actions, such as ensuring all your gems in your gemset are up to date, in .rvmrc to keep your project current without costing you time each time you cd.
To get the latest version of rvm, run:
rvm update --head
Once that is installed, all new shells will have the improved behaviour -- for existing shells that you don't want to close, you can run 'rvm reload' to provide the new behaviour.
Cheers,
-Dennis
This happens because it sources a file that intercepts the cd operation.
prompt:$ cat ~/.rvm/scripts/cd
#!/usr/bin/env bash
# Source a .rvmrc file in a directory after changing to it, if it exists.
cd() {
builtin cd "$#"
if [[ "$rvm_project_rvmrc" != 0 ]] ; then
local cwd ; cwd=$(pwd)
while : ; do
if [[ -z "$cwd" ]] || [[ "$HOME" = "$cwd" ]] || [[ "/" = "$cwd" ]] ; then
if [[ "$rvm_project_rvmrc_default" != 0 ]] ; 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
fi
}
This file checks for a .rvmrc file in the directory you are changing to, and set up an environment. That way you can have dir A run under ruby 1.8 and dir B run under ruby 1.9.
If you are happy to do away with this convenience you can comment out this file and be done with slow directory switching.
Alternatively you could contribute a patch that performs some caching so this is fast.

Resources