1# = Tools for FTP uploading.
2#
3# This file is still under development and is not released for general
4# use.
5
6require 'date'
7require 'net/ftp'
8require 'rake/file_list'
9
10module Rake # :nodoc:
11
12  ####################################################################
13  # <b>Note:</b> <em> Not released for general use.</em>
14  class FtpFile
15    attr_reader :name, :size, :owner, :group, :time
16
17    def self.date
18      @date_class ||= Date
19    end
20
21    def self.time
22      @time_class ||= Time
23    end
24
25    def initialize(path, entry)
26      @path = path
27      @mode, _, @owner, @group, size, d1, d2, d3, @name = entry.split(' ')
28      @size = size.to_i
29      @time = determine_time(d1, d2, d3)
30    end
31
32    def path
33      File.join(@path, @name)
34    end
35
36    def directory?
37      @mode[0] == ?d
38    end
39
40    def mode
41      parse_mode(@mode)
42    end
43
44    def symlink?
45      @mode[0] == ?l
46    end
47
48    private # --------------------------------------------------------
49
50    def parse_mode(m)
51      result = 0
52      (1..9).each do |i|
53        result = 2*result + ((m[i]==?-) ? 0 : 1)
54      end
55      result
56    end
57
58    def determine_time(d1, d2, d3)
59      now = self.class.time.now
60      if /:/ =~ d3
61        result = Time.parse("#{d1} #{d2} #{now.year} #{d3}")
62        if result > now
63          result = Time.parse("#{d1} #{d2} #{now.year-1} #{d3}")
64        end
65      else
66        result = Time.parse("#{d1} #{d2} #{d3}")
67      end
68      result
69#       elements = ParseDate.parsedate("#{d1} #{d2} #{d3}")
70#       if elements[0].nil?
71#         today = self.class.date.today
72#         if elements[1] > today.month
73#           elements[0] = today.year - 1
74#         else
75#           elements[0] = today.year
76#         end
77#       end
78#       elements = elements.collect { |el| el.nil? ? 0 : el }
79#       Time.mktime(*elements[0,7])
80    end
81  end
82
83  ####################################################################
84  # Manage the uploading of files to an FTP account.
85  class FtpUploader
86
87    # Log uploads to standard output when true.
88    attr_accessor :verbose
89
90    class << FtpUploader
91      # Create an uploader and pass it to the given block as +up+.
92      # When the block is complete, close the uploader.
93      def connect(path, host, account, password)
94        up = self.new(path, host, account, password)
95        begin
96          yield(up)
97        ensure
98          up.close
99        end
100      end
101    end
102
103    # Create an FTP uploader targeting the directory +path+ on +host+
104    # using the given account and password.  +path+ will be the root
105    # path of the uploader.
106    def initialize(path, host, account, password)
107      @created = Hash.new
108      @path = path
109      @ftp = Net::FTP.new(host, account, password)
110      makedirs(@path)
111      @ftp.chdir(@path)
112    end
113
114    # Create the directory +path+ in the uploader root path.
115    def makedirs(path)
116      route = []
117      File.split(path).each do |dir|
118        route << dir
119        current_dir = File.join(route)
120        if @created[current_dir].nil?
121          @created[current_dir] = true
122          $stderr.puts "Creating Directory  #{current_dir}" if @verbose
123          @ftp.mkdir(current_dir) rescue nil
124        end
125      end
126    end
127
128    # Upload all files matching +wildcard+ to the uploader's root
129    # path.
130    def upload_files(wildcard)
131      FileList.glob(wildcard).each do |fn|
132        upload(fn)
133      end
134    end
135
136    # Close the uploader.
137    def close
138      @ftp.close
139    end
140
141    private # --------------------------------------------------------
142
143    # Upload a single file to the uploader's root path.
144    def upload(file)
145      $stderr.puts "Uploading #{file}" if @verbose
146      dir = File.dirname(file)
147      makedirs(dir)
148      @ftp.putbinaryfile(file, file) unless File.directory?(file)
149    end
150  end
151end
152