12 class ParserError < RuntimeError; end
21 # The raw list entry string.
25 alias_method :to_s, :raw
27 # The items basename (filename).
32 # Looks like a directory, try CWD.
37 # Looks like a file, try RETR.
42 # Looks like a symbolic link.
44 !!(@symlink ||= false)
56 def inherited(klass) #:nodoc:
61 @@parsers.reverse.each do |parser|
63 return parser.new(raw)
74 # Stolen straight from the ASF's commons Java FTP LIST parser library.
75 # http://svn.apache.org/repos/asf/commons/proper/net/trunk/src/java/org/apache/commons/net/ftp/
78 (((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\+?\s+
81 (?:(\S+(?:\s\S+)*)\s+)?
83 ((?:\d+[-/]\d+[-/]\d+)|(?:\S+\s+\S+))\s+
88 # Parse a Unix like FTP LIST entries.
91 match = REGEXP.match(raw.strip) or raise ParserError
94 when /d/ then @dir = true
95 when /l/ then @symlink = true
96 when /[f-]/ then @file = true
97 when /[bc]/ then # Do nothing with devices for now.
98 else ParserError 'Unknown LIST entry type.'
101 # TODO: Permissions, users, groups, date/time.
102 @filesize = match[18].to_i
103 @mtime = Time.parse("#{match[19]} #{match[20]}")
105 @basename = match[21].strip
107 # filenames with spaces will end up in the last match
108 @basename += match[22] unless match[22].nil?
110 # strip the symlink stuff we don't care about
111 @basename.sub!(/\s+\->.+$/, '') if @symlink
119 SECONDS_PER_DAY = 60 * 60 * 24
120 time -= 120 * SECONDS_PER_DAY
122 ftp = Net::FTP.new('ftp.mozilla.org')
124 ftp.chdir('pub/firefox/releases/10.0.12esr/linux-i686/xpi')
129 entry = Net::FTP::List.parse(f)
130 next unless (entry.mtime > time and entry.file?)
131 lst.insert(0, entry.basename)
136 puts "Downloading #{file}"
137 ftp.getbinaryfile(file)