File: adapter.rb

package info (click to toggle)
vagrant 2.2.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 8,072 kB
  • sloc: ruby: 80,731; sh: 369; makefile: 9; lisp: 1
file content (144 lines) | stat: -rw-r--r-- 3,072 bytes parent folder | download | duplicates (6)
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
140
141
142
143
144
require "pathname"

module VagrantPlugins
  module FTPPush
    class Adapter
      attr_reader :host
      attr_reader :port
      attr_reader :username
      attr_reader :password
      attr_reader :options
      attr_reader :server

      def initialize(host, username, password, options = {})
        @host, @port = parse_host(host)
        @username = username
        @password = password
        @options  = options
        @server   = nil
      end

      # Parse the host into it's url and port parts.
      # @return [Array]
      def parse_host(host)
        if host.include?(":")
          split = host.split(":", 2)
          [split[0], split[1].to_i]
        else
          [host, default_port]
        end
      end

      def default_port
        raise NotImplementedError
      end

      def connect(&block)
        raise NotImplementedError
      end

      def upload(local, remote)
        raise NotImplementedError
      end
    end

    #
    # The FTP Adapter
    #
    class FTPAdapter < Adapter
      def initialize(*)
        require "net/ftp"
        super
      end

      def default_port
        21
      end

      def connect(&block)
        @server = Net::FTP.new
        @server.passive = options.fetch(:passive, true)
        @server.connect(host, port)
        @server.login(username, password)

        begin
          yield self
        ensure
          @server.close
        end
      end

      def upload(local, remote)
        parent   = File.dirname(remote)
        fullpath = Pathname.new(File.expand_path(parent, pwd))

        # Create the parent directories if they does not exist (naive mkdir -p)
        fullpath.descend do |path|
          if !directory_exists?(path.to_s)
            @server.mkdir(path.to_s)
          end
        end

        # Upload the file
        @server.putbinaryfile(local, remote)
      end

      def directory_exists?(path)
        begin
          @server.chdir(path)
          return true
        rescue Net::FTPPermError
          return false
        end
      end

      private

      def pwd
        @pwd ||= @server.pwd
      end
    end

    #
    # The SFTP Adapter
    #
    class SFTPAdapter < Adapter
      def initialize(*)
        require "net/sftp"
        super
        @dirs = {}
      end

      def default_port
        22
      end

      def connect(&block)
        Net::SFTP.start(@host, @username, password: @password, port: @port) do |server|
          @server = server
          yield self
        end
      end

      def upload(local, remote)
        dir = File.dirname(remote)

        fullpath = Pathname.new(dir)
        fullpath.descend do |path|
          if @dirs[path.to_s].nil?
            begin
              @server.mkdir!(path.to_s)

              # Cache visited directories in a list to avoid duplicate requests
              @dirs[path.to_s] = true
            rescue Net::SFTP::StatusException => e
              # Directory exists, skip...
            end
          end
        end

        @server.upload!(local, remote)
      end
    end
  end
end