Narkisr - blog

Narkisr.com where code writes itself.


20
Aug 10

Automation, automation, automation! [0..2]{automation}!

There are always tasks that look too small to worry about, copying a file pasting that line, the comforting sound of repetition.
Uh? as devs we are better than that, we can program complex logic in commercial settings there is no reason not to apply our knowledge to every day tasks, let the machines do what they do best, repeat!
For example the enjoyable task of copying the contents of cd's (remember those?) onto your hard drive, the drill is quite simple you pop in a cd, head on to the file manager gui select all files, enter copy and move into the destination folder, oh and don't forget to create a unique folder for each copied cd, now repeat that 50x times, can we do better?

PREFIX = '/home/ronen/temp/'
last_cd_in = lambda{ %x(dmesg | grep ISOFS).split("\n").last }

def mounted_at
	res = nil
        res_ok = lambda{res && res.split(' ')[1]}
	10.times {
		puts 'another attempt'
	       	res = `cat /proc/mounts | grep sr0`; break if res_ok.call
		sleep 1
       	}
        notify 'failed to find mount point' and exit 1 if !res_ok.call	
	res.split(' ')[1].gsub('040',' ') 
end

def notify (msg) 
	`notify-send '#{msg}' -t 10`
end

def sh(cmd)
	res = `#{cmd}`
	notify("#{cmd} failed") and exit(1) if $?.to_i != 0 
	res
end

last = nil

eject_action = lambda {
	sh 'eject'
	last = last_cd_in.call
	puts 'place the cd in, press enter when your done'
	gets
}

eject_action.call

while(true)
	sh 'eject -t'
	begin
		curr = last_cd_in.call
	end while last==curr
	dest ="#{PREFIX}#{%x(uuid)}"
	sh "mkdir #{dest}"
	if !system("cp -rv #{mounted_at()}/* #{dest}")
		notify 'Failed to copy cd, please check media!'
	end
	eject_action.call
end

This script enables the following functionality:

  • Cdrom tray is popped out and the user is prompted to enter a new one in.
  • A unique destination folder is created (using uuid).
  • The contents is copied to the destination.
  • The cd is popped out ready for another round.

As for the implementation its Ruby mixed with good old unix tools like cp, mkdir eject and some /proc trickery to keep track of new mounted cd path, I find this combination a win win, we use Ruby instead of bash and use standard unix tools set instead of writing them ourself, Ruby has excellent unix process management API's (as any one who used Java for that can approve).
Notify-send is a nice decor (Ubuntu notification system) that growls at us when things go wrong (keeping us free to roam into more interesting domains).

Another annoying task is waiting for tests to end in Intellij, this is not using our time, wouldn't it be great to be notified when tests fail? (not supported OOTB):
require 'rubygems'
require 'open4'

def numeric?(object)
	true if Float(object) rescue false
end


while (true)
        pid=`jps -v | grep AppMain | awk '{print $1}'`
	if numeric?(pid)
		puts "JUnit found at PID #{pid}"
		opid, stdin, stdout, stderr = Open4::popen4("strace -p #{pid}")
		Process::waitpid2 opid
		lines = stderr.readlines
		if lines.last.include?  '255'
			`notify-send 'tests failed!' -u critical`
		else
			`notify-send 'all tests passed!' -u critical`
		end
	end
	sleep 2.5
end
Same idea again, using Linux tool box with Ruby to automate our task, this script polls all Java processes for AppMain (Intellij main class runner), once found strace is attached to it in order to grab the exit code and notify-send the matching return status, the theme is repeating levrage the operating system and Ruby in order to turn a mundane task into an enjoyable one!


This website content by Ronen Narkis is licensed under a Creative Commons Attribution 2.5 Israel License, based on a work at narkisr.com, Permissions beyond the scope of this license may be available at narkisr.com.