Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env ruby
- require 'net/ftp'
- require 'fileutils'
- require 'abbrev'
- $stdout.sync = true
- Thread.abort_on_exception = true
- class Float
- def mformat
- tmp = to_s.split('.')
- [tmp.first, tmp.last[0..2]].join('.')
- end
- end
- class FTPSync
- def initialize server, user = 'anonymous', pass = 'anoymous'
- Net::FTP.open(server, user, pass) do |@ftp|
- walk '/'
- end
- end
- def walk path = '/'
- puts @ftp.pwd
- fetch_listing(path).each do |node|
- begin
- walk(File.join(node.path, node.name)) if node.directory?
- download(node) if node.file?
- rescue Net::FTPPermError => ex
- puts "#{ex} for walking #{path}"
- rescue Net::FTPTempError => ex
- puts "#{ex} retry..."
- retry
- rescue Object => ex
- puts ex
- puts ex.backtrace
- end
- end
- @ftp.sendcmd('cdup')
- end
- def fetch_listing path
- @ftp.sendcmd("cwd #{path}")
- list = @ftp.list('*')
- list.map do |line|
- FTPNode.new(line, path)
- end
- end
- def download node
- mode = node.mode
- unless mode == :ignore
- unless node.downloaded?
- puts "download #{node.filename} (#{node.size} bytes | #{node.in_mb}MB) to #{node.local_file}"
- puts @ftp.send("get#{mode}file", node.name, node.local_file)
- end
- end
- end
- end
- class FTPNode
- BINARY_EXTS = %w[ gz bz bz2 iso img png jpg gif exe torrent Z svg ]
- TEXT_EXTS = %w[ txt md5sum README MD5SUMS c ]
- def initialize line, path
- @line = line
- @path = path
- end
- def local_path
- local_path = File.expand_path(File.join('./', path))
- end
- def local_file
- local_file = File.join(local_path, name)
- end
- def local_size
- prepare_local
- File.size(local_file)
- end
- def prepare_local
- unless File.exist?(local_file)
- FileUtils.mkdir_p(local_path)
- FileUtils.touch(local_file)
- end
- end
- def downloaded?
- local_size == size
- end
- def path
- @path
- end
- def filename
- [@path, name].join('/').squeeze('/')
- end
- def name
- @name ||=
- @line.split.last
- end
- def mode
- @mode ||=
- if kind == :file
- case ext
- when *BINARY_EXTS
- :binary
- when *TEXT_EXTS
- :text
- when ''
- :text
- else
- ask_mode
- end
- else
- nil
- end
- end
- def ext
- @ext ||=
- File.extname(name).gsub('.', '')
- end
- def ask_mode
- puts "I couldn't determine the mode to use for #{name}"
- puts "Please choose between (b)inary and (t)ext"
- got = gets.strip
- chosen = %w[binary text].abbrev[got]
- if chosen == 'binary'
- BINARY_MODES << ext
- elsif chosen == 'text'
- TEXT_MODES << ext
- else
- puts "no valid answer, try again :)"
- ask_mode
- end
- chosen.to_sym
- end
- def size
- @size ||=
- @line.split[4].to_i
- end
- def in_mb
- @in_mb ||=
- (size / 1024.0 / 1024.0).mformat
- end
- def kind
- @kind ||=
- case @line[0,1]
- when 'd' : :directory
- when 'l' : :link
- when '-' : :file
- end
- end
- def directory?
- kind == :directory
- end
- def file?
- kind == :file
- end
- def link?
- kind == :link
- end
- end
- FTPSync.new('ftp.archlinux.org', 'anonymous', 'anonymous')
- =begin
- Net::FTP.open('ftp.archlinux.org', 'anonymous', 'anonymous') do |ftp|
- trap('SIGINT'){ ftp.sendcmd('QUIT'); exit }
- walker = lambda do |path|
- puts "walking #{path}"
- puts ftp.sendcmd("cwd #{path}")
- puts ftp.pwd
- ftp.list('*').each do |line|
- begin
- splat = line.split
- node = splat.last
- kind = line[0,1]
- if kind == 'd' # directory
- walker[node]
- elsif kind == 'l' # link
- walker[node]
- else # file
- mode =
- case File.extname(node)
- when '.gz', '.iso', '.img', '.png', '.jpg', '.gif'
- :binary
- when '.torrent'
- :ignore
- else
- :text
- end
- local_path = File.join('./', ftp.pwd)
- local_file = File.join(local_path, File.basename(node))
- remote_size = splat[4].to_f
- r_mb = (remote_size / 1024 / 1024).mformat
- FileUtils.mkdir_p(local_path)
- FileUtils.touch(local_file) unless File.exists?(local_file)
- local_size = File.size(local_file).to_f
- if local_size == remote_size
- puts "got #{node} already"
- elsif mode == :ignore
- puts "ignoring #{node}"
- else
- puts "downloading #{node} (#{remote_size} bytes) in #{mode} Mode"
- width = `stty size`.split.last.to_i - 50
- t = Thread.new do
- this = Thread.current
- progress = 0.0
- until local_size >= remote_size
- local_size = File.size(local_file).to_f
- l_mb = ( local_size / 1024 / 1024).mformat
- percentage = ((local_size / remote_size) * 100).mformat
- progress = ( local_size / remote_size) * width
- bar = "["
- ("=" * progress)
- ("." * (width - progress))
- "]"
- "[#{l_mb.ljust(r_mb.size)}/#{r_mb}MB | #{percentage}%]"
- print bar
- sleep 0.1
- print "\b" * bar.size
- end
- end
- ftp.send("get#{mode}file", node, local_file)
- t.join
- puts
- end
- end
- rescue Net::FTPPermError => ex
- puts "#{ex} for walking #{path}"
- rescue Net::FTPTempError => ex
- puts "#{ex} retry..."
- retry
- rescue Object => ex
- puts ex
- puts ex.backtrace
- end
- end
- puts ftp.sendcmd('cdup')
- end
- walker['/']
- end
- =end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement