You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildr.apache.org by as...@apache.org on 2008/05/03 02:07:41 UTC
svn commit: r652955 - in /incubator/buildr/trunk: CHANGELOG buildr.gemspec
lib/buildr/core/common.rb lib/buildr/core/transports.rb
spec/transport_spec.rb
Author: assaf
Date: Fri May 2 17:07:41 2008
New Revision: 652955
URL: http://svn.apache.org/viewvc?rev=652955&view=rev
Log:
Added: Reading files from SFTP server.
Changed: Upgraded to Net::SSH 2.0 and Net::SFTP 2.0.
Modified:
incubator/buildr/trunk/CHANGELOG
incubator/buildr/trunk/buildr.gemspec
incubator/buildr/trunk/lib/buildr/core/common.rb
incubator/buildr/trunk/lib/buildr/core/transports.rb
incubator/buildr/trunk/spec/transport_spec.rb
Modified: incubator/buildr/trunk/CHANGELOG
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/CHANGELOG?rev=652955&r1=652954&r2=652955&view=diff
==============================================================================
--- incubator/buildr/trunk/CHANGELOG (original)
+++ incubator/buildr/trunk/CHANGELOG Fri May 2 17:07:41 2008
@@ -1,4 +1,6 @@
1.3.1 (Pending)
+* Added: reading files from SFTP server.
+* Changed: Upgraded to Net::SSH 2.0 and Net::SFTP 2.0.
1.3.0 (2008-04-25)
* Added: Testing with EasyB (Nicolas Modrzyk).
Modified: incubator/buildr/trunk/buildr.gemspec
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/buildr.gemspec?rev=652955&r1=652954&r2=652955&view=diff
==============================================================================
--- incubator/buildr/trunk/buildr.gemspec (original)
+++ incubator/buildr/trunk/buildr.gemspec Fri May 2 17:07:41 2008
@@ -38,8 +38,8 @@
# Tested against these dependencies.
spec.add_dependency 'rake', '~> 0.8'
spec.add_dependency 'builder', '~> 2.1'
- spec.add_dependency 'net-ssh', '~> 1.1'
- spec.add_dependency 'net-sftp', '~> 1.1'
+ spec.add_dependency 'net-ssh', '~> 2.0'
+ spec.add_dependency 'net-sftp', '~> 2.0'
spec.add_dependency 'rubyzip', '~> 0.9'
spec.add_dependency 'highline', '~> 1.4'
spec.add_dependency 'Antwrap', '~> 0.7'
Modified: incubator/buildr/trunk/lib/buildr/core/common.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/buildr/core/common.rb?rev=652955&r1=652954&r2=652955&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/buildr/core/common.rb (original)
+++ incubator/buildr/trunk/lib/buildr/core/common.rb Fri May 2 17:07:41 2008
@@ -18,7 +18,6 @@
require 'tempfile'
require 'open-uri'
$LOADED_FEATURES << 'rubygems/open-uri.rb' # avoid loading rubygems' open-uri
-require 'uri/open-sftp'
require 'buildr/core/util'
require 'buildr/core/transports'
Modified: incubator/buildr/trunk/lib/buildr/core/transports.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/lib/buildr/core/transports.rb?rev=652955&r1=652954&r2=652955&view=diff
==============================================================================
--- incubator/buildr/trunk/lib/buildr/core/transports.rb (original)
+++ incubator/buildr/trunk/lib/buildr/core/transports.rb Fri May 2 17:07:41 2008
@@ -20,7 +20,6 @@
require 'net/ssh'
require 'net/sftp'
require 'uri'
-require 'uri/sftp'
require 'digest/md5'
require 'digest/sha1'
require 'tempfile'
@@ -342,7 +341,10 @@
end
- class SFTP #:nodoc:
+ class SFTP < Generic #:nodoc:
+
+ DEFAULT_PORT = 22
+ COMPONENT = [ :scheme, :userinfo, :host, :port, :path ].freeze
class << self
# Caching of passwords, so we only need to ask once.
@@ -351,16 +353,40 @@
end
end
- protected
+ def initialize(*arg)
+ super
+ end
- def write_internal(options, &block) #:nodoc:
+ def read(options = {}, &block)
# SSH options are based on the username/password from the URI.
- ssh_options = { :port=>port, :username=>user, :password=>password }.merge(options[:ssh_options] || {})
+ ssh_options = { :port=>port, :password=>password }.merge(options[:ssh_options] || {})
ssh_options[:password] ||= SFTP.passwords[host]
begin
puts "Connecting to #{host}" if Buildr.application.options.trace
- session = Net::SSH.start(host, ssh_options)
- SFTP.passwords[host] = ssh_options[:password]
+ result = nil
+ Net::SFTP.start(host, user, ssh_options) do |sftp|
+ SFTP.passwords[host] = ssh_options[:password]
+ puts 'connected' if Buildr.application.options.trace
+
+ with_progress_bar options[:progress] && options[:size], path.split('/'), options[:size] || 0 do |progress|
+ puts "Downloading to #{path}" if Buildr.application.options.trace
+ sftp.file.open(path, 'r') do |file|
+ if block
+ while chunk = file.read(32 * 4096)
+ block.call chunk
+ progress << chunk
+ end
+ else
+ result = ''
+ while chunk = file.read(32 * 4096)
+ result << chunk
+ progress << chunk
+ end
+ end
+ end
+ end
+ end
+ return result
rescue Net::SSH::AuthenticationFailed=>ex
# Only if running with console, prompt for password.
if !ssh_options[:password] && $stdout.isatty
@@ -370,39 +396,55 @@
end
raise
end
+ end
- session.sftp.connect do |sftp|
- puts 'connected' if Buildr.application.options.trace
+ protected
- # To create a path, we need to create all its parent. We use realpath to determine if
- # the path already exists, otherwise mkdir fails.
- puts "Creating path #{path}" if Buildr.application.options.trace
- File.dirname(path).split('/').inject('') do |base, part|
- combined = base + part
- sftp.realpath combined rescue sftp.mkdir combined, {}
- "#{combined}/"
- end
+ def write_internal(options, &block) #:nodoc:
+ # SSH options are based on the username/password from the URI.
+ ssh_options = { :port=>port, :password=>password }.merge(options[:ssh_options] || {})
+ ssh_options[:password] ||= SFTP.passwords[host]
+ begin
+ puts "Connecting to #{host}" if Buildr.application.options.trace
+ Net::SFTP.start(host, user, ssh_options) do |sftp|
+ SFTP.passwords[host] = ssh_options[:password]
+ puts 'connected' if Buildr.application.options.trace
+
+ # To create a path, we need to create all its parent. We use realpath to determine if
+ # the path already exists, otherwise mkdir fails.
+ puts "Creating path #{path}" if Buildr.application.options.trace
+ File.dirname(path).split('/').inject('') do |base, part|
+ combined = base + part
+ sftp.realpath combined rescue sftp.mkdir combined, {}
+ "#{combined}/"
+ end
- with_progress_bar options[:progress] && options[:size], path.split('/'), options[:size] || 0 do |progress|
- puts "Uploading to #{path}" if Buildr.application.options.trace
- sftp.open_handle(path, 'w') do |handle|
- # Writing in chunks gives us the benefit of a progress bar,
- # but also require that we maintain a position in the file,
- # since write() with two arguments always writes at position 0.
- pos = 0
- while chunk = yield(32 * 4096)
- sftp.write(handle, chunk, pos)
- pos += chunk.size
- progress << chunk
+ with_progress_bar options[:progress] && options[:size], path.split('/'), options[:size] || 0 do |progress|
+ puts "Uploading to #{path}" if Buildr.application.options.trace
+ sftp.file.open(path, 'w') do |file|
+ while chunk = yield(32 * 4096)
+ file.write chunk
+ progress << chunk
+ end
+ sftp.setstat(path, :permissions => options[:permissions]) if options[:permissions]
end
- sftp.setstat(path, :permissions => options[:permissions]) if options[:permissions]
end
end
+ rescue Net::SSH::AuthenticationFailed=>ex
+ # Only if running with console, prompt for password.
+ if !ssh_options[:password] && $stdout.isatty
+ password = ask("Password for #{host}:") { |q| q.echo = '*' }
+ ssh_options[:password] = password
+ retry
+ end
+ raise
end
end
end
+ @@schemes['SFTP'] = SFTP
+
# File URL. Keep in mind that file URLs take the form of <code>file://host/path</code>, although the host
# is not used, so typically all you will see are three backslashes. This methods accept common variants,
Modified: incubator/buildr/trunk/spec/transport_spec.rb
URL: http://svn.apache.org/viewvc/incubator/buildr/trunk/spec/transport_spec.rb?rev=652955&r1=652954&r2=652955&view=diff
==============================================================================
--- incubator/buildr/trunk/spec/transport_spec.rb (original)
+++ incubator/buildr/trunk/spec/transport_spec.rb Fri May 2 17:07:41 2008
@@ -298,3 +298,106 @@
URI("http://john:secret@#{@host_domain}").read
end
end
+
+
+describe URI::HTTP, '#write' do
+end
+
+
+describe URI::SFTP, '#write' do
+ before do
+ @uri = URI('sftp://john:secret@localhost/path/readme')
+ @content = 'Readme. Please!'
+
+ @ssh_session = mock('Net::SSH::Session')
+ @sftp_session = mock('Net::SFTP::Session')
+ @file_factory = mock('Net::SFTP::Operations::FileFactory')
+ Net::SSH.stub!(:start).with('localhost', 'john', :password=>'secret', :port=>22) do
+ Net::SFTP::Session.should_receive(:new).with(@ssh_session).and_yield(@sftp_session).and_return(@sftp_session)
+ @sftp_session.should_receive(:connect!).and_return(@sftp_session)
+ @sftp_session.should_receive(:loop)
+ @sftp_session.stub!(:mkdir)
+ @sftp_session.should_receive(:file).with.and_return(@file_factory)
+ @file_factory.stub!(:open)
+ @ssh_session.should_receive(:close)
+ @ssh_session
+ end
+ end
+
+ it 'should open connection to SFTP server' do
+ @uri.write @content
+ end
+
+ it 'should create path recursively on SFTP server' do
+ @sftp_session.should_receive(:mkdir).ordered.with('', {})
+ @sftp_session.should_receive(:mkdir).ordered.with('/path', {})
+ @uri.write @content
+ end
+
+ it 'should only create paths that don\'t exist' do
+ @sftp_session.should_receive(:realpath).any_number_of_times
+ @sftp_session.should_not_receive(:mkdir)
+ @uri.write @content
+ end
+
+ it 'should open file for writing' do
+ @file_factory.should_receive(:open).with('/path/readme', 'w')
+ @uri.write @content
+ end
+
+ it 'should write contents to file' do
+ file = mock('Net::SFTP::Operations::File')
+ file.should_receive(:write).with(@content)
+ @file_factory.should_receive(:open).with('/path/readme', 'w').and_yield(file)
+ @uri.write @content
+ end
+
+end
+
+
+describe URI::SFTP, '#read' do
+ before do
+ @uri = URI('sftp://john:secret@localhost/path/readme')
+ @content = 'Readme. Please!'
+
+ @ssh_session = mock('Net::SSH::Session')
+ @sftp_session = mock('Net::SFTP::Session')
+ @file_factory = mock('Net::SFTP::Operations::FileFactory')
+ Net::SSH.stub!(:start).with('localhost', 'john', :password=>'secret', :port=>22) do
+ Net::SFTP::Session.should_receive(:new).with(@ssh_session).and_yield(@sftp_session).and_return(@sftp_session)
+ @sftp_session.should_receive(:connect!).and_return(@sftp_session)
+ @sftp_session.should_receive(:loop)
+ @sftp_session.should_receive(:file).with.and_return(@file_factory)
+ @file_factory.stub!(:open)
+ @ssh_session.should_receive(:close)
+ @ssh_session
+ end
+ end
+
+ it 'should open connection to SFTP server' do
+ @uri.read
+ end
+
+ it 'should open file for reading' do
+ @file_factory.should_receive(:open).with('/path/readme', 'r')
+ @uri.read
+ end
+
+ it 'should read contents of file and return it' do
+ file = mock('Net::SFTP::Operations::File')
+ file.should_receive(:read).with(an_instance_of(Numeric)).once.and_return(@content, nil)
+ @file_factory.should_receive(:open).with('/path/readme', 'r').and_yield(file)
+ @uri.read.should eql(@content)
+ end
+
+ it 'should read contents of file and pass it to block' do
+ file = mock('Net::SFTP::Operations::File')
+ file.should_receive(:read).with(an_instance_of(Numeric)).once.and_return(@content, nil)
+ @file_factory.should_receive(:open).with('/path/readme', 'r').and_yield(file)
+ content = ''
+ @uri.read do |chunk|
+ content << chunk
+ end
+ content.should eql(@content)
+ end
+end