Created
January 23, 2013 07:32
-
-
Save majioa/4602862 to your computer and use it in GitHub Desktop.
Simple FTP mirroring tool in Ruby
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/ruby | |
require 'net/ftp' | |
require 'net/http' | |
require 'fileutils' | |
class String | |
def to_l(srcl,dstl) | |
val = gsub(/(["'\&\(\)])/) { "\\" + $1 } | |
`echo #{val} |iconv -f #{srcl} -t #{dstl}`.sub(/\n/,"") | |
end | |
end | |
class Logger | |
def initialize(verbose,file) | |
@verbose = verbose | |
@log = File.open(file,'a') if file | |
end | |
def verbose(msg, level = 0) | |
if @verbose >= level | |
puts msg | |
if @log | |
@log.write(msg + "\n") | |
@log.flush | |
end | |
end | |
end | |
def error(msg) | |
verbose('Exiting: ' + msg) | |
exit | |
end | |
end | |
class Net::FTP | |
attr_writer :log, :simulate | |
def mirror(folder) | |
@log.verbose("Curdir #{FileUtils.pwd}\nRemdir #{pwd}",2) | |
name = folder.to_l("cp1251","utf-8") | |
unless @simulate then | |
begin | |
FileUtils.cd(name) | |
rescue Errno::ENOENT | |
FileUtils.makedirs(name) | |
retry | |
end | |
end | |
@log.verbose("Folder #{name}",1) | |
chdir(folder) | |
list.each {|line| | |
@log.verbose("Line #{line}",3) | |
line =~ /^([d-])[rwx-]{1,9} +\d+ \w+ +\w+ +(\d+) (\w{3} +/ | |
/\d{1,2} +[\d:]+) (.*)$/ | |
next if $4 == "." or $4 == ".." | |
if $1 == "d" then | |
@log.verbose("Down to folder #{$4}",2) | |
mirror($4) | |
else | |
file = $4.to_l("cp1251","utf-8") | |
@log.verbose("File sizes: local = #{File.size?(file)}, " | |
"remote = #{$2.to_i} ",2) | |
if !@simulate and File.size?(file) == $2.to_i then | |
@log.verbose("File #{file} is exist and the same " | |
"as the remote: not downloading",1) | |
next; | |
end | |
@log.verbose("Downloading file #{file}",1) | |
begin | |
getbinaryfile($4, $4.to_l("cp1251","utf-8"), 1024) | |
unless @simulate | |
rescue Errno::EEXIST | |
next | |
end | |
end | |
} | |
FileUtils.cd("..") | |
chdir("..") | |
end | |
end | |
class App | |
def initialize | |
log = '/local/var/log/mirrorer.log' | |
@log = Logger.new(3,log) | |
p = `ps aux` | |
c = 0 | |
val = $0.gsub(/.*\//,"") | |
while p =~ /ruby.*#{val}/o | |
c = c + 1 | |
p = p.sub(/#{val}/o, "") | |
end | |
@log.error("Duplex run") if c > 1 | |
end | |
end | |
class Mirrorer < App | |
def initialize(*args) | |
super | |
sites = '/local/etc/sites' | |
#init vars | |
@simulate = nil | |
@simulate = true | |
@root_folder = "/local/share/mirrors" | |
begin | |
@sites = IO.read(sites); | |
rescue Errno::ENOENT | |
@log.error("File #{sites} doesn't exist. Nothing to mirror") | |
end | |
#change to specified path | |
retries = 0 | |
begin | |
FileUtils.cd(@root_folder) | |
rescue Errno::ENOENT | |
begin | |
FileUtils.mkdir(@root_folder) | |
rescue Errno::EACCES | |
@log.error("Can't create the specfied mirror root folder" | |
" '#{@root_folder}'") | |
end | |
retry | |
end | |
end | |
def mirror | |
@sites.each { |line| | |
FileUtils.cd(@root_folder) | |
next if line =~ /#.*/ | |
@log.verbose("Reading the new line",2) | |
if line =~ /^(.*) +(.*?)$/ then | |
site = $1 | |
folder_path = $2 | |
else | |
site = line | |
end | |
@log.error "Wrong site name, please check" | |
if (site.gsub(/%(..)/) {|s| | |
$1.hex.chr } !~ /^ *(ftp|http):\/\/(?:(.*?)\/)? | |
(?:(.*)\/)*(?:(.*)\/?)?$/) | |
ftp_addr = $2 | |
folder_path = $2 + '/' + $3.to_s.to_l("cp1251","utf-8") if !folder_path | |
remote_dir = $3 | |
folder = $4 | |
@log.verbose("Connecting to site #{ftp_addr}",0) | |
@log.verbose("Site = #{ftp_addr.to_l("cp1251","utf-8")}, " | |
"folder = #{folder_path}, folder = " | |
"#{folder.to_l("cp1251","utf-8")}",2) | |
@log.verbose("#{ftp_addr}, #{folder_path}, #{remote_dir}, " | |
"#{folder}",2) | |
begin | |
ftp = Net::FTP.new ftp_addr.gsub(/\//,"") | |
rescue Errno::ECONNREFUSED | |
@log.error "Connection to the server #{ftp_addr.gsub(/\//,"")}" | |
" is refused" | |
end | |
ftp.log = @log | |
ftp.simulate = @simulate | |
begin | |
ftp.login | |
rescue Net::FTPTempError | |
@log.verbose('421 Too many users - please try again later',0) | |
next | |
end | |
begin | |
FileUtils.cd folder_path | |
rescue Errno::ENOENT | |
begin | |
FileUtils.makedirs folder_path | |
rescue Errno::ENOACC | |
@log.error "Can't create target directories" | |
end | |
retry | |
end | |
ftp.chdir(remote_dir) if remote_dir | |
ftp.mirror(folder) | |
ftp.close | |
} | |
end | |
end | |
mirrorer = Mirrorer.new | |
mirrorer.mirror |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment