class RamDev

Attributes

diskname[R]
mountpoint[R]
ramdisk[R]

Public Class Methods

new(sufix = "_ramdev") click to toggle source

path to rc file, and 10 mb default size.

# File lib/ramdev.rb, line 11
def initialize(sufix = "_ramdev")
  @backupSuffix = sufix
  @store = PStore.new("/tmp/ramdev.pstore")
end

Public Instance Methods

build(rcpath, size = nil) click to toggle source
# File lib/ramdev.rb, line 85
def build(rcpath, size = nil)
  @size = size
  @size ||= memory / 2

  load_runcom(rcpath)
  ramdisk = Ramdisk.new(mountpoint)

  human_num = "#{@size / 1048576}".reverse.gsub(/...(?=.)/,'\&,').reverse
  puts "Allocating ramdisk size: #{human_num} MB "

  if( !ramdisk.allocate(@size) )
    puts "Allocation failed. Size: #{human_num} MB"
    exit
  end
  if( !ramdisk.format(diskname, :hfs) )
    puts "Failed to format disk."
    exit
  end
  if( !ramdisk.mount )
    puts "Failed to mount at #{mountpoint}"
    ramdisk.deallocate
    exit
  end


  if !valid_paths?
    puts "paths are not valid!".color(:red)
    raise(:hell)
  end
  copy_folders

  puts "RAM disk mounted at #{mountpoint}"

  #FIX: Not compatible with Windows:

  fork do
    puts "ramdev_sync pid #{Process.pid}"
    File.open("/tmp/ramdev_sync.pid", "w") {|f| f.write("#{Process.pid}\n")}

    @store.transaction do |s|
      s["pid"] = Process.pid
    end

    trap("QUIT") do
      puts "Interrupted by signal, ramdev_sync will stop now."
      exit
    end

    watcher = RamDevSync.new(File.open(rcpath))
    watcher.listen
    puts "ramdev_sync listening..."
    sleep
  end

end
copy_folders() click to toggle source
# File lib/ramdev.rb, line 190
def copy_folders
  @paths.each do |p|
    src   = p["source"].gsub(/\/+$/,"")
    next if src.nil? || src.length < 1
    des   = p["destination"].gsub(/\/+$/,"").gsub(/^\/+/,"")
    name  = src.match(/([^\/\\]+)$/)[1]
    if des.length > 0
      des = mountpoint+"/#{des}"
      des = des.gsub(/\/{2,}/,"/")
    else
      des = mountpoint
    end
    des = File.absolute_path(des)
    print "Copying #{src}...\n"
    FileUtils.mkdir_p(des) unless File.exist?(des)
    IO.popen("rsync --progress -ra #{src} #{des}") do |rsync_io|
      until rsync_io.eof?
        line = rsync_io.readline
        line = line.gsub("\n","")
        next unless line =~ /to-check/
        m = line.match(/to-check=([0-9]+)\/([0-9]+)/)
        scale = (m[1].to_f / m[2].to_f)
        prog = "#{[9613].pack('U*')}" * ( (1.0 - scale) * 30.0).round

        prog += " " * (scale * 30.0).round
        print "#{prog}| #{des}/#{name}  "
        print "\r"
      end
    end
    print "\n"

    FileUtils.move(src, src+@backupSuffix)

    puts "Linking: #{name}"

    File.symlink("#{des}/#{name}", src)
  end
end
fix(rcpath) click to toggle source
# File lib/ramdev.rb, line 16
def fix(rcpath)
  load_runcom(rcpath)

  watcher = RamDevSync.new(File.open(rcpath))

  if watcher.running?
    puts `ps #{watcher.pid}`
    puts "It appears ramdev is still running at pid: #{watcher.pid}.".color(:yellow)
    puts "Try 'ramdev down' first to fix any file linking problem."
    puts "Otherwise kill the process first before running 'ramdev fix'."
    return
  end

  @paths.each do |p|
    src   = p["source"].gsub(/\/+$/,"")
    if( File.exists?(src+@backupSuffix) )
      if(!File.exists?(src) || File.symlink?(src))
        FileUtils.safe_unlink(src) if File.symlink?(src)

        puts "Moving backup: ".color(:green) + "#{src+@backupSuffix} to #{src}"
        FileUtils.move(src+@backupSuffix, src)
      else
        puts "skipping file: ".color(:yellow) + ("#{src}")
      end
    end
  end

end
load_runcom(rcfile) click to toggle source
# File lib/ramdev.rb, line 141
def load_runcom(rcfile)

  return if @loaded == true
  rc = YAML.load(File.open(rcfile))
  if rc.nil?
    @mountpoint = "/ramdev"
    @diskname   = "ramdev"
    @paths      ||= []
    @paths.push({ source: Dir.pwd, destination: "" })
  else
    @mountpoint = rc["ramdisk"]["mountpoint"]
    @diskname  = rc["ramdisk"]["name"]
      # TODO: Get size of paths and create default ramdisk size based it (2x)
    @paths     = rc["ramdisk"]["paths"]
    @size      ||= rc["ramdisk"]["size"] if rc["ramdisk"]["size"]
    @loaded    = true
  end

end
memory() click to toggle source
# File lib/ramdev.rb, line 72
def memory
  if @memory.nil?
    r = `/usr/sbin/system_profiler SPHardwareDataType`.split("\n").collect { |s| s == "" ? nil : s.strip }.compact
    r = r.collect { |s| s.split(":").collect { |ss| ss.strip }}
    memstring = ""
    r.each do |i|
      memstring = i[1] if i[0] == "Memory"
    end
    @memory = memstring.match(/([0-9]+) GB/)[1].to_i * 1073741824
  end
  @memory
end
restore_folders() click to toggle source
# File lib/ramdev.rb, line 172
def restore_folders
  @paths.each do |p|
    src   = p["source"].gsub(/\/+$/,"")

    if !File.exists? src+@backupSuffix || !File.symlink?(src)
      puts "Referenced files don't appear to be linked properly. "
      return false
    end
  end

  @paths.each do |p|
    src   = p["source"].gsub(/\/+$/,"")
    FileUtils.safe_unlink src
    FileUtils.move(src+@backupSuffix, src)
  end
  true
end
unbuild(rcpath, force = false) click to toggle source
# File lib/ramdev.rb, line 45
def unbuild(rcpath, force = false)
  #TODO force sync
  load_runcom(rcpath)

  if !force && !restore_folders
    puts "Ramdisk shutdown was halted because there was a problem restoring folders."
    puts "Eject the ramdisk manually once you've sorted out any issues."
    return
  end
  ramdisk = Ramdisk.new(mountpoint)

  pid = @store.transaction do |s|
    s["pid"]
  end

  Process.kill("QUIT", pid) if pid

  @store.transaction do |s|
    s["pid"] = nil
  end

  ramdisk.unmount
  ramdisk.deallocate

  "RAM disk removed at #{mountpoint}"
end
valid_paths?() click to toggle source
# File lib/ramdev.rb, line 161
def valid_paths?
  @paths.each do |p|
    src   = p["source"].gsub(/\/+$/,"")
    if File.exist?("#{src}#{@backupSuffix}")
      puts "A backup already exists for: '#{src}' at: '#{src}#{@backupSuffix}'"
      return false
    end
  end
  return true
end