Rake で設定ファイルを一括管理

設定ファイルをまとめて管理する」にインスパイアされて、自分の環境でもやってみた。
ただ、今更、Makefile を書くのもイヤだったので Rake で書いてみた。


Rakefile はこんな感じ

#
# Rakefile for Config Files
#

require 'rake'
require 'date'
require 'fileutils'

task :default => [:list]

NOW = DateTime.now.strftime("%Y-%m-%d-%H%M")

desc "list configuration files"
task :list do
   puts "src\t\tdest\t\t\t\tupdatable?"

   configs_each do |conf|
      puts conf
   end
end

desc "show diff between two files"
task :diff do
   configs_each do |conf|
      puts conf.diff if conf.updatable?
   end
end

desc "update config files"
task :update do
   count = 0
   configs_each do |conf|
      next unless conf.updatable?
      next unless confirm_update? conf
      backup(conf)
      update(conf)

      puts "update #{conf.dest_name} done."
      count += 1
   end

   puts "update #{count} files"
end

def configs_each(&block)
   Dir.glob("*/**").each do |f|
      next if File.directory?(f) or f.include?("sample") or f.include?("backup")
      conf = ConfigFile.new(f)
      yield conf
   end
end

def confirm_update?(conf)
   while true
      puts conf.diff
      print "update #{conf.dest_name}? (Y/N) :: "
      s = STDIN.gets.chomp.upcase
      return true if s == "Y"
      return false if s == "N"
   end
end

def backup(config)
   FileUtils.cp("#{config.dest_name}", "backup/#{config.basename}.#{NOW}")
end

def update(config)
   FileUtils.cp("#{config.file}", "#{config.dest_name}")
end


class ConfigFile
   attr_accessor :file, :dirname, :basename, :dest_name
   
   def initialize(file)
      @file = file
      @dirname = File.dirname(file)
      @basename = File.basename(file)
      
      @dest_name = "/"
      @dest_name << @dirname.split(".").each{|s| s.sub!(/^dot/,".")}.join("/")
      @dest_name << "/#{@basename.sub(/^dot/,'')}"
   end

   def diff
      `diff -u #{@dest_name} #{@file} `
   end
   
   def updatable?
      return false unless File.exists?(dest_name);
      a = (File.new(file).mtime.to_i > File.new(dest_name).mtime.to_i)
      b = diff.chomp.length != 0
      return (a and b)
   end

   def to_s
      "#{basename}\t#{dest_name}\t\t#{updatable?}"
   end
end

こんな感じのディレクトリ構成で設定ファイルを配置して

Configs
-- Rakefile
-- Users.xxxx
-- dot.emacs.el
-- dot.mew.el
`-- dot.zshrc
-- Users.xxxx.dotmlterm
`-- key
-- backup
`-- sample

以下のタスクを実行すればいい。

% rake list      # 管理している設定ファイルの一覧を表示
% rake diff      # 変更箇所を表示
% rake update    # 設定ファイルを更新する

また、コピー先には空でも構わないのでファイルが存在しないと更新しないようにした。

一応、手元の環境(Mac OSX 10.4)では動作してます。