Create an Adapter to bridge the APIs between SFTP and FTP libraries

This commit is contained in:
Seth Vargo 2014-11-11 18:36:30 -05:00
parent eb5cecc782
commit 80851a887f
2 changed files with 218 additions and 0 deletions

View File

@ -0,0 +1,107 @@
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
20
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)
# Create the parent directory if it does not exist
if !@server.list("/").any? { |f| f.start_with?(parent) }
@server.mkdir(parent)
end
# Upload the file
@server.putbinaryfile(local, remote)
end
end
#
# The SFTP Adapter
#
class SFTPAdapter < Adapter
def initialize(*)
require "net/sftp"
super
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)
@server.upload!(local, remote, mkdir: true)
end
end
end
end

View File

@ -0,0 +1,111 @@
require_relative "../../../base"
require "fake_ftp"
require Vagrant.source_root.join("plugins/pushes/ftp/adapter")
describe VagrantPlugins::FTPPush::Adapter do
include_context "unit"
subject do
described_class.new("127.0.0.1:2345", "sethvargo", "bacon",
foo: "bar",
)
end
describe "#initialize" do
it "sets the instance variables" do
expect(subject.host).to eq("127.0.0.1")
expect(subject.port).to eq(2345)
expect(subject.username).to eq("sethvargo")
expect(subject.password).to eq("bacon")
expect(subject.options).to eq(foo: "bar")
expect(subject.server).to be(nil)
end
end
describe "#parse_host" do
it "has a default value" do
allow(subject).to receive(:default_port)
.and_return(5555)
result = subject.parse_host("127.0.0.1")
expect(result[0]).to eq("127.0.0.1")
expect(result[1]).to eq(5555)
end
end
end
describe VagrantPlugins::FTPPush::FTPAdapter do
include_context "unit"
before(:all) do
@server = FakeFtp::Server.new(21212, 21213)
@server.start
end
after(:all) { @server.stop }
let(:server) { @server }
before { server.reset }
subject do
described_class.new("127.0.0.1:#{server.port}", "sethvargo", "bacon")
end
describe "#default_port" do
it "is 20" do
expect(subject.default_port).to eq(20)
end
end
describe "#upload" do
before do
@dir = Dir.mktmpdir
FileUtils.touch("#{@dir}/file")
end
after do
FileUtils.rm_rf(@dir)
end
it "uploads the file" do
subject.connect do |ftp|
ftp.upload("#{@dir}/file", "/file")
end
expect(server.files).to include("file")
end
it "uploads in passive mode" do
subject.options[:passive] = true
subject.connect do |ftp|
ftp.upload("#{@dir}/file", "/file")
end
expect(server.file("file")).to be_passive
end
end
end
describe VagrantPlugins::FTPPush::SFTPAdapter do
include_context "unit"
subject do
described_class.new("127.0.0.1:2345", "sethvargo", "bacon",
foo: "bar",
)
end
describe "#default_port" do
it "is 22" do
expect(subject.default_port).to eq(22)
end
end
describe "#upload" do
it "uploads the file" do
pending "a way to mock an SFTP server"
end
end
end