summaryrefslogtreecommitdiff
path: root/lib/rake/contrib/ftptools.rb
blob: 0dd50fdc8d4b5cf4846b60669185e20fc6d3f586 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# = Tools for FTP uploading.
#
# This file is still under development and is not released for general
# use.

require 'date'
require 'net/ftp'
require 'rake/file_list'

module Rake # :nodoc:

  ####################################################################
  # <b>Note:</b> <em> Not released for general use.</em>
  class FtpFile
    attr_reader :name, :size, :owner, :group, :time

    def self.date
      @date_class ||= Date
    end

    def self.time
      @time_class ||= Time
    end

    def initialize(path, entry)
      @path = path
      @mode, _, @owner, @group, size, d1, d2, d3, @name = entry.split(' ')
      @size = size.to_i
      @time = determine_time(d1, d2, d3)
    end

    def path
      File.join(@path, @name)
    end

    def directory?
      @mode[0] == ?d
    end

    def mode
      parse_mode(@mode)
    end

    def symlink?
      @mode[0] == ?l
    end

    private # --------------------------------------------------------

    def parse_mode(m)
      result = 0
      (1..9).each do |i|
        result = 2 * result + ((m[i] == ?-) ? 0 : 1)
      end
      result
    end

    def determine_time(d1, d2, d3)
      now = self.class.time.now
      if /:/ !~ d3
        result = Time.parse("#{d1} #{d2} #{d3}")
      else
        result = Time.parse("#{d1} #{d2} #{now.year} #{d3}")
        result = Time.parse("#{d1} #{d2} #{now.year - 1} #{d3}") if
          result > now
      end
      result
    end
  end

  ####################################################################
  # Manage the uploading of files to an FTP account.
  class FtpUploader

    # Log uploads to standard output when true.
    attr_accessor :verbose

    class << FtpUploader
      # Create an uploader and pass it to the given block as +up+.
      # When the block is complete, close the uploader.
      def connect(path, host, account, password)
        up = self.new(path, host, account, password)
        begin
          yield(up)
        ensure
          up.close
        end
      end
    end

    # Create an FTP uploader targeting the directory +path+ on +host+
    # using the given account and password.  +path+ will be the root
    # path of the uploader.
    def initialize(path, host, account, password)
      @created = Hash.new
      @path = path
      @ftp = Net::FTP.new(host, account, password)
      makedirs(@path)
      @ftp.chdir(@path)
    end

    # Create the directory +path+ in the uploader root path.
    def makedirs(path)
      route = []
      File.split(path).each do |dir|
        route << dir
        current_dir = File.join(route)
        if @created[current_dir].nil?
          @created[current_dir] = true
          $stderr.puts "Creating Directory  #{current_dir}" if @verbose
          @ftp.mkdir(current_dir) rescue nil
        end
      end
    end

    # Upload all files matching +wildcard+ to the uploader's root
    # path.
    def upload_files(wildcard)
      FileList.glob(wildcard).each do |fn|
        upload(fn)
      end
    end

    # Close the uploader.
    def close
      @ftp.close
    end

    private # --------------------------------------------------------

    # Upload a single file to the uploader's root path.
    def upload(file)
      $stderr.puts "Uploading #{file}" if @verbose
      dir = File.dirname(file)
      makedirs(dir)
      @ftp.putbinaryfile(file, file) unless File.directory?(file)
    end
  end
end