require 'net/sftp' # See Bloggit::Publisher module Bloggit # = Publisher class Publisher attr_reader :site, :verbose, :settings def initialize(site, verbose=false) @site = site @verbose = verbose @settings = site.settings.publish end def upload puts_if_verbose "Connecting to #{settings['host']}..." Net::SFTP.start(settings['host'], settings['user'], settings['pass'], :timeout=>settings.fetch('timeout', 30)) do |sftp| puts_if_verbose "Fetching checksums..." local_checksums = YAML::load(File.open( local_path("checksum.yml") )) remote_checksums = {} begin checksums_src = '' sftp.open_handle( server_path('checksum.yml')) do |handle| checksums_src = sftp.read(handle) end remote_checksums = YAML::load(checksums_src) unless checksums_src.nil? or checksums_src=='' rescue Net::SFTP::Operations::StatusException=>se # server's checksum.yml is missing end puts_if_verbose "Comparing checksum data..." to_upload, to_remove = Bloggit::Checksum.diff(local_checksums, remote_checksums) if to_upload.length > 0 or to_remove.length > 0 puts_if_verbose "Differences found:" to_upload.each {|f| puts_if_verbose " - (Upload) #{f}" } to_remove.each {|f| puts_if_verbose " - (Delete) #{f}"} puts_if_verbose "Beginning sync..." to_upload.each do |filename| begin puts_if_verbose " - #{remote_path(filename)}" dir_name = File.dirname(filename) dir_segs = dir_name.split('/') #puts "Checking path: #{dir_segs.join( '/' )}" prog_path = [] dir_segs.each do |partial_dir| begin prog_path << partial_dir sftp.mkdir( remote_path( prog_path ), :permissions=>0755 ) puts_if_verbose " + #{remote_path( prog_path )}" rescue Net::SFTP::Operations::StatusException=>se # don't worry about it end end sftp.put_file local_path(filename), remote_path(filename) sftp.open_handle( remote_path(filename) ) do |handle| sftp.fsetstat( handle, :permissions=>0644 ) end rescue Net::SFTP::Operations::StatusException=>se puts_if_verbose " ! Error uploading '#{filename}': #{se}" puts_if_verbose; puts_if_verbose "Halted execution of upload." exit(1) end end to_remove.each do |filename| begin sftp.remove remote_path(filename) puts_if_verbose " x #{remote_path(filename)}" rescue puts_if_verbose " ! Error removing '#{filename}': #{$!}" end end begin sftp.put_file local_path('checksum.yml'), remote_path('checksum.yml') sftp.open_handle( remote_path('checksum.yml') ) do |handle| sftp.fsetstat( handle, :permissions=>0644 ) end rescue puts_if_verbose " ! Error uploading 'checksum.yml': #{$!}" end summary = "#{to_upload.length} file(s) uploaded" summary += ", #{to_remove.length} files(s) deleted" if to_remove.length > 0 puts summary else puts "No changes made. The server is up to date!" end puts "Done." end end def server_path(path) [settings['path'], path].flatten.join('/') end alias_method :remote_path, :server_path def local_path(path) File.join(site.base_path, 'cache', path) end def puts_if_verbose(msg='') puts(msg) if @verbose end end end