Script to update RVM-based ruby install and gems - ruby

A couple searches didn't turn up an obvious way to update my RVM-based ruby and gems so I whipped up the following script. The desire is to get a list of currently installed gems, update to the new ruby, pull those gems forward, then clean out the old versions of everything. I'm posting it here for feedback, since I don't see an easy way to test it and I'm barely competent at ruby and mostly clueless about RVM.
#!/usr/bin/env ruby
module RubyUpdate
def self.cmd(str, cmd)
puts str
retval = %x(#{cmd})
throw(SystemCallError, cmd) unless $? == 0
return retval
end
def self.update
gems = self.cmd %Q(Getting list of installed gems...), %Q(gem list | cut -d ' ' -f 1)
self.cmd %Q(Updating ruby...), %Q(\\curl -L https://get.rvm.io | bash -s stable --ruby)
self.cmd %Q(Reloading...), %Q(rvm reload)
self.cmd %Q(Updating gems..), %Q(gem update #{gems.gsub("\n", " ")})
self.cmd %Q(Cleaning up gems...), %Q(gem cleanup)
self.cmd %Q(Reloading...), %Q(rvm reload)
self.cmd %Q(Cleaning up ruby...), %Q(rvm cleanup all)
end
end
begin
RubyUpdate::update
puts "Update successful!"
rescue SystemCallError => e
puts "Update failed!"
puts e
end

you should use:
rvm get stable
rvm upgrade current ruby

Related

How to change rvm gemset over ssh on os x server

ok
I don't know how to change rvm version over ssh under os x server.
What I do:
Login on server over ssh
run script (below) and catch error
Error: 'rvm is not a funciton, many-many-words'
What I have as script:
use File::Spec;
my $server_directory = File::Spec->catfile($ENV{HOME},'MyProject');
my $exec_file = File::Spec->catfile($server_directory,'run_script.rb');
my $run_ruby_script = qq'bundle exec ruby $exec_file'.' '.join(' ',#ARGV);
# reload bash profile
print qx(source $ENV{HOME}/.bash_profile);
print qx(source $ENV{HOME}/.bashrc);
# reload ruby
print qx(source $ENV{HOME}/.rvm/scripts/rvm);
my $ruby_setup = qq([[ -s "$ENV{HOME}/.rvm/scripts/rvm" ]] && source "$ENV{HOME}/.rvm/scripts/rvm");
print $ruby_setup. "\n";
# change directory
chdir($server_directory);
# configure gemset name
my $version = qx(cat .ruby-version);
chomp($version);
my $gemset = qx(cat .ruby-gemset);
chomp($gemset);
my $change_rvm_gemset = qq(rvm use $version\#$gemset);
print qx($ruby_setup && $change_rvm_gemset);
print qx(rvm current);
Ok, after all.
def exec_via_bash(line)
puts %Q(#{line})
exec = 'bash -c "#{line}"'
puts `#{exec}`
end
def RubySetup
# reload bash profile
homedir = ENV['HOME']
exec_via_bash %Q(source #{homedir}/.bash_profile);
exec_via_bash %Q(source #{homedir}/.bashrc);
# reload ruby
exec_via_bash %Q(source #{homedir}/.rvm/scripts/rvm);
ruby_setup = %Q([[ -s "#{homedir}/.rvm/scripts/rvm" ]] && source "#{homedir}/.rvm/scripts/rvm")
puts ruby_setup
ruby_setup
end
if ARGV.empty?
puts "there is not enough arguments passed. maybe you forget ruby file to exec?"
exit(1)
end
ruby_script_path = ARGV.shift;
exec_file_absolute_path = File.expand_path(ruby_script_path)
unless File.exists? exec_file_absolute_path
puts "file #{exec_file_absolute_path} doesn't exists!"
exit(1)
end
exec_file_directory = File.dirname(exec_file_absolute_path)
exec_bundle = %Q'bundle exec ruby #{exec_file_absolute_path}' + ' ' + ARGV.join(' ')
# change directory
Dir.chdir(exec_file_directory);
# print %x(ls);
# configure gemset name
version = %x(cat .ruby-version).strip;
gemset = %x(cat .ruby-gemset).strip;
change_rvm_gemset = %Q(rvm use #{version}\##{gemset});
ruby_setup = RubySetup()
exec_bash_login_line = [ruby_setup, change_rvm_gemset, exec_bundle].join ' && ';
puts 'exec bash login line: ' + exec_bash_login_line
forced = %Q(bash --login -c '#{exec_bash_login_line}');
puts forced, "\n";
puts %x(#{forced});
ok, this script is not a kind of beauty, but it works well.
Example of usage?
ruby script.rb ~/bla/bla/bla/run_your_program.rb --first_argument --second_argument a,b,c --etc
As I said before:
I've already on the server via ssh.
So, I need to run scripts via launchd.
And I should do it with
# part of launchd worker
<string>bash</string>
<string>-c</string>
<string>ruby ~/PathToCharmScript.rb -r a</string>
P.S:
Please, help me with improvements of this script for others!
Here is a gist: wow_this_works

Ruby One liner | test remote host port

I'm trying below Perl command in Ruby
Perl
perl -MIO::Socket::INET -e 'until(new IO::Socket::INET("localhost:80")) { print "Waiting for network..\n"; sleep 1}'
How do I same thing in ruby ?
I have tried :
require 'socket'
until !( TCPSocket.new("localhost",80).close ) do
puts "Wait..."
sleep 1
end
I'm looking for one liner in Ruby.
The main difference is that Ruby will raise an error if it cannot establish the IO, so you need to rescue the error condition. It changes the flow somewhat, but is still very do-able:
loop { break if (TCPSocket.open("localhost",80) rescue nil); puts "Wait...."; sleep 1 }
As seen from other answer, it is possible to make a more literal conversion from the Perl version. Just use the Ruby expression (TCPSocket.open("localhost",80) rescue nil) to replace Perl's new IO::Socket::INET("localhost:80") so that Ruby's raise an error behaviour better matches Perl's return undef when cannot create the object.
This is similar:
require 'socket'
(puts "Waiting..."; sleep 1) until (TCPSocket.open("localhost",3000) rescue nil)
Full command line:
ruby -r socket -e '(puts "Waiting..."; sleep 1) until (TCPSocket.open("localhost",3000) rescue nil)'

Running command line commands from Thor executable

In my executable Ruby file I have the following:
#!/usr/bin/env ruby
require 'thor'
include Thor::Actions
class UI < Thor
# def self.source_root
# File.dirname(__FILE__)
# end
desc "makecal", "Generates postscript calendar to your desktop"
def makecal
# puts `ls ~`
puts run('ls ~')
# puts run "pcalmakecal -B -b all -d Helvetica/8 -t Helvetica/16 -S #{Time.now.month} #{Time.now.year} > ~/Desktop/#{Time.now.month}-#{Time.now.year}"
end
end
UI.start
In the terminal when I run the file as is I get an empty line as Thor's run command is returning a NilClass.
However, when I un-comment the puts `ls ~` and comment out Thor's run method I get an output of my home directory as expected.
I'm having trouble figuring out why I can't get Thor's run method to work like Ruby's ticks.
Any ideas where I may have went wrong?
Thanks for looking
I didn't put the include statement inside my class and that messed things up. The code should be:
#!/usr/bin/env ruby
require 'makecal'
class UI < Thor
include Thor::Actions
# def self.source_root
# File.dirname(__FILE__)
# end
#
desc "makecal", "Generates postscript calendar to your desktop"
def makecal
# puts `ls ~`
puts run('ls ~')
# puts run "pcal -B -b all -d Helvetica/8 -t Helvetica/16 -S #{Time.now.month} #{Time.now.year} > ~/Desktop/#{Time.now.month}-#{Time.now.year}"
end
end
UI.start
Thor's documentation on this method is actually wrong and incomplete. It documents that it returns the "contents of the command" (which I assume means the standard output), but it, by defualt, does nothing.
But, you can, apparently, use the :capture option to get what you want:
unless options[:pretend]
config[:capture] ? `#{command}` : system("#{command}")
end
So, try doing
puts run("ls ~", :capture => true)
And see if that does it.

one god for different rubies with rvm

I have two apps on my machine.
Each app (server) has it's own gemset and works on a different ruby version.
I will manage those apps with god which is installed in it's own gemset.
My god config file config.god looks like this:
God.watch do |w|
current_path = "/home/vagrant/server-1"
w.name = "server 1"
w.start = "ruby #{current_path}/simple-server.rb"
w.keepalive
end
God.watch do |w|
current_path = "/home/vagrant/server-2"
w.name = "server 2"
w.start = "ruby #{current_path}/simple-server.rb"
w.keepalive
end
My servers are simply writing the ruby version to a file (/home/vagrant/server-2/simple-server.rb):
require "date"
loop do
# simple console output
puts "Hello on #{RUBY_VERSION}, #{RUBY_PATCHLEVEL}, #{RUBY_PLATFORM}, #{RUBY_RELEASE_DATE}"
# Specify the name of the log file
log_file = File.join File.expand_path( File.dirname(__FILE__) ), "testfile.txt"
# Write the log into the file
File.open( log_file, 'a') do |f|
date = DateTime.now
date = date.strftime("%H:%M:%S")
f.puts "#{date} on #{RUBY_VERSION}, #{RUBY_PATCHLEVEL}, #{RUBY_PLATFORM}, #{RUBY_RELEASE_DATE}"
end
sleep 2
end
I run god with god -c config.god.
The problem is that my apps are not running with the ruby versions which is specified in the .rvmrc.
I have also tried:
~/.rvm/bin/wrapped_god -d config.god -D
rvmsudo ~/.rvm/bin/wrapped_god -d config.god -D
rvmsudo god -d config.god -D
Is there a solution for this case?
EDIT 2012.08.27:
I have changed my god config as follows:
w.start="~/.rvm/bin/rvm in #{current_path} do ruby simple-server.rb"
And it worked.
try:
start="~/.rvm/bin/rvm in #{current_path} do ruby simple-server.rb"

what is a portable way in Ruby to check where STDIN will block if you attempt to read from it?

I would like to find out if there is a portable way to check in a Ruby script whether it will block if it attempts to read from STDIN. The following is an approach that works for Unix (and Cygwin) but not native Win32. (It is based on a Perl approach I learned long ago.)
$ cat read-stdin.rb
#! /usr/bin/ruby
# test of reading from STDIN
require 'fcntl'
# Trace info on input objects
$stdout.sync=TRUE if $DEBUG # make sure standard output and error synchronized
$stderr.print "ARGV=#{ARGV}\n" if $DEBUG
$stderr.print "ARGF=#{ARGF}\n" if $DEBUG
# See if input available, showing usage statement if not
blocking_stdin = FALSE
if (defined? Fcntl::F_GETFL) then
$stderr.print "F_GETFL=#{Fcntl::F_GETFL} O_RDWR=#{Fcntl::O_RDWR}\n" if $DEBUG
flags = STDIN.fcntl(Fcntl::F_GETFL, 0)
$stderr.print "flags=#{flags}\n" if $DEBUG
blocking_stdin = TRUE if ((flags & Fcntl::O_RDWR) == Fcntl::O_RDWR)
$stderr.print "blocking_stdin=#{blocking_stdin}\n" if $DEBUG
end
if (blocking_stdin && (ARGV.length == 0)) then
$stderr.print "usage: #{$0} [-]\n"
Process.exit
end
# Read input and output it
$stderr.print "Input:\n" if $DEBUG
input_text = ARGF.read()
$stderr.print "Output:\n" if $DEBUG
print "#{input_text}\n"
Here is the interaction without debugging:
$ grep -v DEBUG read-stdin.rb >| /tmp/simple-read-stdin.rb
$ echo hey | ruby /tmp/simple-read-stdin.rb
hey
$ ruby /tmp/simple-read-stdin.rb
usage: /tmp/simple-read-stdin.rb [-]
Here is the interaction with debugging:
$ echo hey | ruby -d read-stdin.rb
ARGV=
ARGF=ARGF
F_GETFL=3 O_RDWR=2
flags=65536
blocking_stdin=false
Input:
Output:
hey
$ ruby -d read-stdin.rb
ARGV=
ARGF=ARGF
F_GETFL=3 O_RDWR=2
flags=98306
blocking_stdin=true
usage: read-stdin.rb [-]
I don't know if it is universally portable and I also don't know if it is considered a good idea (blocking isn't such a bad concept) but there is a non-blocking read method in IO. You can use it like this:
chunk = nil
begin
chunk = STDIN.read_nonblock(4096)
rescue Errno::EAGAIN
# Handle the case if it would block
chunk = 'nothing there...'
end
Though, I think it's quite disappointing it doesn't work without specifying a buffer size like IO#read does it, but working around this by using a loop should be quite easy.

Resources