Created
May 28, 2011 21:35
-
-
Save rab/997254 to your computer and use it in GitHub Desktop.
Ruby script to xfer a set of directories to an sftp location
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby -w | |
# Expected to be found at ~/code/ruby/xferlist.rb | |
# Move all files newer than the 'sentinel' to the web site | |
# skip all .doc files (MS-Word) | |
# skip all files containing a tilde (~) (local backup or archival copies) | |
# skip anything in 'old-notices' | |
# | |
# Deals with spaces in file/directory names by using the '?' shell wildcard | |
require 'optparse' | |
require 'ostruct' | |
require 'rubygems' | |
require 'net/sftp' | |
require 'fileutils' | |
options = OpenStruct.new(:user => ENV['USER'] || ENV['LOGNAME'], | |
:exclusions => [ /\A\./, /~/, /\.cache\z/, | |
/\.psd\z/, /\.docx?\z/, /\.xls\z/, /\.pages\z/, | |
/old-notices/, | |
], | |
:dryrun => false, | |
:debug => false) | |
OptionParser.new do |opts| | |
opts.banner = "Usage: #{$0} [options] connection-spec [simple-dir [...]]" | |
opts.separator " where a connection-spec is for sftp like user@host:directory" | |
opts.on("-d", '--debug', | |
"Include debugging comments in the output") do |val| | |
puts "debug: #{val}" | |
options.debug = true | |
end | |
opts.on("-n", '--dry-run', | |
"Don't change the sentinel or run the commands through sftp") do |val| | |
puts "dryrun: #{val}" if options.debug | |
options.dryrun = val | |
options.debug = true | |
end | |
opts.on("--dir FROM,TO", String, | |
"A list of directory pairs local,remote[,local2,remote2,...]", | |
"in which to look for new files to transfer. This option", | |
"may be repeated.") do |val| | |
val.scan %r{([^,]+),([^,]+)} do |f,t| | |
puts "dir: #{f} => #{t}" if options.debug | |
(options.dirs ||= []) << [f,t] | |
end | |
end | |
opts.on("-x", '--exclude', | |
"") do |val| | |
end | |
opts.on_tail("-h", "--help", "Show this message") do | |
puts opts | |
exit | |
end | |
end.parse! | |
target = ARGV.shift | |
puts "sftp #{target}" if options.dryrun | |
user, host, start_dir = target.match(/\A(?:([^@]+)@)?([^:]+)(?::(.*))?\z/).captures | |
ARGV.each {|dir| (options.dirs ||= []) << [dir,dir] } | |
class ProgressHandler | |
def initialize(debug) | |
@debug = debug | |
end | |
def on_open(uploader, file) | |
puts "#{uploader.object_id.to_s(16)}: starting upload: #{file.local} -> #{file.remote} (#{file.size} bytes)" | |
end | |
def on_put(uploader, file, offset, data) | |
puts "#{uploader.object_id.to_s(16)}: writing #{data.length} bytes to #{file.remote} starting at #{offset}" if @debug | |
end | |
def on_close(uploader, file) | |
puts "#{uploader.object_id.to_s(16)}: finished with #{file.remote}" | |
end | |
def on_mkdir(uploader, path) | |
puts "#{uploader.object_id.to_s(16)}: creating directory #{path}" | |
end | |
def on_finish(uploader) | |
puts "#{uploader.object_id.to_s(16)}: all done!" if @debug | |
end | |
end | |
puts "Starts in #{Dir.pwd}" if options.debug | |
sentinel = File.mtime('sentinel') rescue Time.at(0) | |
uploads = [] | |
Net::SFTP.start(host, user) do |sftp| | |
(options.dirs || [['.','.']]).each do |from,to| | |
Dir.glob("#{from}/**/*") do |localfile| | |
next if sentinel > File.mtime(localfile) | |
next if File.directory?(localfile) # I really should handle directory creation! | |
next if options.exclusions.any? {|exclude| localfile =~ exclude } | |
localfile, remotefile = localfile, localfile.sub(/\A#{from}/, to) | |
remotefile = File.join(start_dir, remotefile) if start_dir | |
puts "upload #{localfile} => #{remotefile}" if options.debug | |
uploads << sftp.upload(localfile, remotefile, | |
:progress => ProgressHandler.new(options.debug)) unless options.dryrun | |
end | |
end | |
uploads.each { |u| u.wait } | |
end | |
unless options.dryrun | |
File.rename 'sentinel', 'sentinel.prev' if File.exist? 'sentinel' | |
FileUtils.touch 'sentinel' | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment