monolithic kernel

Jekyllでgzipを生成してrsyncでデプロイする

August 10, 2014

    以前、Jekyllを便利に使うためのRakefileと称して、Jekyllで生成したHTMLなどのgzipファイルを生成してrsyncでデプロイするコードを紹介しました。このコードで確かにデプロイできることはできるのですが、何も変更されていないファイルも含めて毎回転送されてしまうという問題があったため、対策しました。

    まずは完成品をどうぞ。

    require 'bundler'
    Bundler.require
    
    task :new, :title do |t, args|
      title = args.title or exit
      config = Jekyll.configuration({})
    
      open(File.join(config['source'], '_posts', "#{Time.now.strftime('%Y-%m-%d')}-#{title.to_url}.markdown"), 'w') do |f|
        f << <<-EOS
    ---
    title: #{title}
    date: #{Time.now.strftime('%Y-%m-%d %H:%M')}
    published: false
    ---
    EOS
      end
    end
    
    task :build do
      config = Jekyll.configuration({})
      Jekyll::Commands::Build.process(config)
      Parallel.each(Dir.glob(File.join(config['destination'], '**', '*.{css,html,js,xml}'))) do |f|
        system "gzip --rsyncable --keep --no-name #{f}"
      end
    end
    
    task :rsync do
      config = Jekyll.configuration({})
      system "rsync -avzr --compress --checksum --delete #{config['destination']}/ #{config['rsync']['destination']}"
    end
    
    task :deploy => [ :build, :rsync ] do
    end

    前回のコードの最大の問題は、Jekyllでビルドするとすべてのファイルが再生成されてタイムスタンプが変化することを考慮していない点です。これにより、ファイルの内容が変わっていないにも関わらず、ファイルが変更されたと見なされていました。今回のコードでは、--checksumオプションを追加することで、ファイルの内容によって変更をチェックするようにしています。

    しかし、これだけでは十分ではありません。gzip圧縮したファイルは、--checksumオプションを追加しても毎回転送されてしまいます。これは、gzipファイルに圧縮前のファイルのタイムスタンプの情報が圧縮後のファイルに格納されていることに起因します。圧縮時に--no-nameオプションを追加することで、圧縮前のファイルのタイムスタンプ (とファイル名) が含められることを回避できます。

    なお、上の例では--rsyncableオプションを追加してrsyncでの変更の有無の確認を高速に行えるgzipファイルを生成しています。このオプションはGNUのgzipにしか含まれていないようなので、OS Xなどの環境ではオプションを削除するか、GNUのgzipをインストールしてください。