ftputils 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +12 -0
- data/VERSION +1 -1
- data/ftputils.gemspec +67 -0
- data/lib/ftputils.rb +120 -86
- data/lib/ftputils/ftpconnection.rb +25 -19
- data/spec/ftpconnection_spec.rb +12 -0
- data/spec/ftputils_spec.rb +175 -1
- data/spec/spec_helper.rb +0 -6
- metadata +7 -6
- data/.gitignore +0 -21
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
= Change Log
|
2
|
+
|
3
|
+
== 0.2.1
|
4
|
+
|
5
|
+
* Add timeouts to FTPUtils and FTPConnection methods. Defaults to 5 minutes,
|
6
|
+
but can be set with FTPUtils.timeout_period=(seconds).
|
7
|
+
|
8
|
+
== 0.2.0
|
9
|
+
|
10
|
+
* Major internal refactoring, pulling FTPConnection out of FTPURI
|
11
|
+
* Add FTPFile, which implements a subset of the File API for FTP URIs
|
12
|
+
* Add FTPUtils.ls
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/ftputils.gemspec
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{ftputils}
|
8
|
+
s.version = "0.2.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Bruz Marzolf"]
|
12
|
+
s.date = %q{2011-06-20}
|
13
|
+
s.description = %q{Implements a subset of the methods in FileUtils for FTP URIs, falling back on FileUtils when a path doesn't look like FTP}
|
14
|
+
s.email = %q{bmarzolf@systemsbiology.org}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"CHANGELOG.rdoc",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"ftputils.gemspec",
|
27
|
+
"lib/ftputils.rb",
|
28
|
+
"lib/ftputils/ext/class.rb",
|
29
|
+
"lib/ftputils/ftpconnection.rb",
|
30
|
+
"lib/ftputils/ftpfile.rb",
|
31
|
+
"lib/ftputils/ftpuri.rb",
|
32
|
+
"spec/ftpconnection_spec.rb",
|
33
|
+
"spec/ftpfile_spec.rb",
|
34
|
+
"spec/ftpuri_spec.rb",
|
35
|
+
"spec/ftputils_spec.rb",
|
36
|
+
"spec/spec.opts",
|
37
|
+
"spec/spec_helper.rb"
|
38
|
+
]
|
39
|
+
s.homepage = %q{http://github.com/bmarzolf/ftputils}
|
40
|
+
s.require_paths = ["lib"]
|
41
|
+
s.rubygems_version = %q{1.3.6}
|
42
|
+
s.summary = %q{Like FileUtils for FTP}
|
43
|
+
s.test_files = [
|
44
|
+
"spec/ftpconnection_spec.rb",
|
45
|
+
"spec/ftpfile_spec.rb",
|
46
|
+
"spec/ftpuri_spec.rb",
|
47
|
+
"spec/ftputils_spec.rb",
|
48
|
+
"spec/spec_helper.rb"
|
49
|
+
]
|
50
|
+
|
51
|
+
if s.respond_to? :specification_version then
|
52
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
53
|
+
s.specification_version = 3
|
54
|
+
|
55
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
56
|
+
s.add_runtime_dependency(%q<ftpfxp>, [">= 0.0.4"])
|
57
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
58
|
+
else
|
59
|
+
s.add_dependency(%q<ftpfxp>, [">= 0.0.4"])
|
60
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
61
|
+
end
|
62
|
+
else
|
63
|
+
s.add_dependency(%q<ftpfxp>, [">= 0.0.4"])
|
64
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
data/lib/ftputils.rb
CHANGED
@@ -7,61 +7,79 @@ end
|
|
7
7
|
|
8
8
|
require 'fileutils'
|
9
9
|
require 'open-uri'
|
10
|
+
require 'timeout'
|
10
11
|
|
11
12
|
class FTPUtils
|
12
13
|
|
14
|
+
@@timeout_period = 300
|
15
|
+
|
16
|
+
def self.timeout_period
|
17
|
+
# default to a 5 minute timeout
|
18
|
+
@@timeout_period || 300
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.timeout_period=(seconds)
|
22
|
+
@@timeout_period = seconds
|
23
|
+
end
|
24
|
+
|
13
25
|
def self.cp(src, dest, options = {})
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
26
|
+
timeout(timeout_period) do
|
27
|
+
# handle all combinations of copying to/from FTP and local files
|
28
|
+
case [ftp_url?(src), ftp_url?(dest)]
|
29
|
+
when [true, true]
|
30
|
+
raise "src should be a filename, not a directory" if FTPFile.directory?(src)
|
18
31
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
32
|
+
dest_path = FTPFile.dirname(dest) + "/" + ( FTPFile.basename(dest) || FTPFile.basename(src) )
|
33
|
+
FTPConnection.connect(src).fxpto(FTPConnection.connect(dest), dest_path, FTPFile.relative_path(src))
|
34
|
+
when [true, false]
|
35
|
+
raise "src should be a filename, not a directory" if FTPFile.directory?(src)
|
23
36
|
|
24
|
-
|
37
|
+
filename = FTPFile.basename(src)
|
25
38
|
|
26
|
-
|
27
|
-
|
28
|
-
|
39
|
+
if File.directory? dest
|
40
|
+
dest += "/#{filename}"
|
41
|
+
end
|
29
42
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
43
|
+
connection = FTPConnection.connect(src)
|
44
|
+
connection.chdir FTPFile.dirname(src)
|
45
|
+
connection.getbinaryfile filename, dest, 1024
|
46
|
+
when [false, true]
|
47
|
+
raise "src should be a filename, not a directory" if File.directory? src
|
35
48
|
|
36
|
-
|
49
|
+
dest_path = FTPFile.relative_path(dest)
|
37
50
|
|
38
|
-
|
39
|
-
|
40
|
-
|
51
|
+
if FTPFile.directory?(dest)
|
52
|
+
dest_path += "/#{File.basename(src)}"
|
53
|
+
end
|
41
54
|
|
42
|
-
|
43
|
-
|
55
|
+
connection = FTPConnection.connect(dest)
|
56
|
+
connection.chdir FTPFile.dirname(dest)
|
44
57
|
|
45
|
-
begin
|
46
58
|
connection.putbinaryfile src, dest_path, 1024
|
47
|
-
|
48
|
-
|
59
|
+
when [false, false]
|
60
|
+
FileUtils.cp src, dest, options
|
49
61
|
end
|
50
|
-
when [false, false]
|
51
|
-
FileUtils.cp src, dest, options
|
52
62
|
end
|
63
|
+
rescue Net::FTPPermError
|
64
|
+
raise "Unable to copy #{src} to #{dest}, possibly due to FTP server permissions"
|
65
|
+
rescue Timeout::Error
|
66
|
+
raise "Copying #{src} to #{dest} timed out after #{timeout_period} seconds"
|
53
67
|
end
|
54
68
|
|
55
69
|
def self.rm(path)
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
70
|
+
timeout(timeout_period) do
|
71
|
+
if ftp_url?(path)
|
72
|
+
raise "Can't use FTPUtils.rm on directories. Instead use FTPUtils.rm_r" if FTPFile.directory?(path)
|
73
|
+
|
74
|
+
connection = FTPConnection.connect(path)
|
75
|
+
connection.chdir FTPFile.dirname(path)
|
76
|
+
connection.delete FTPFile.basename(path)
|
77
|
+
else
|
78
|
+
FileUtils.rm path
|
79
|
+
end
|
64
80
|
end
|
81
|
+
rescue Timeout::Error
|
82
|
+
raise "Removing #{path} timed out after #{timeout_period} seconds"
|
65
83
|
end
|
66
84
|
|
67
85
|
def self.mv(src, dest, options = {})
|
@@ -70,78 +88,94 @@ class FTPUtils
|
|
70
88
|
end
|
71
89
|
|
72
90
|
def self.rm_r(path)
|
73
|
-
|
74
|
-
if
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
91
|
+
timeout(timeout_period) do
|
92
|
+
if ftp_url?(path)
|
93
|
+
if FTPFile.directory?(path)
|
94
|
+
connection = FTPConnection.connect(path)
|
95
|
+
connection.chdir FTPFile.relative_path(path)
|
96
|
+
|
97
|
+
files = connection.nlst
|
98
|
+
files.each {|file| rm_r "#{path}/#{file}"}
|
99
|
+
|
100
|
+
connection.rmdir FTPFile.relative_path(path)
|
101
|
+
else
|
102
|
+
rm(path)
|
103
|
+
end
|
82
104
|
else
|
83
|
-
|
105
|
+
FileUtils.rm_r path
|
84
106
|
end
|
85
|
-
else
|
86
|
-
FileUtils.rm_r path
|
87
107
|
end
|
108
|
+
rescue Timeout::Error
|
109
|
+
raise "Removing #{path} timed out after #{timeout_period} seconds"
|
88
110
|
end
|
89
111
|
|
90
112
|
def self.mkdir_p(path)
|
91
|
-
|
92
|
-
|
113
|
+
timeout(timeout_period) do
|
114
|
+
if ftp_url?(path)
|
115
|
+
connection = FTPConnection.connect(path)
|
93
116
|
|
94
|
-
|
95
|
-
|
96
|
-
|
117
|
+
subdirs = FTPFile.relative_path(path).split(/\//)
|
118
|
+
subdirs.each do |subdir|
|
119
|
+
next if subdir == ""
|
97
120
|
|
98
|
-
|
99
|
-
|
121
|
+
connection.mkdir subdir
|
122
|
+
connection.chdir subdir
|
123
|
+
end
|
124
|
+
else
|
125
|
+
FileUtils.mkdir_p path
|
100
126
|
end
|
101
|
-
else
|
102
|
-
FileUtils.mkdir_p path
|
103
127
|
end
|
128
|
+
rescue Timeout::Error
|
129
|
+
raise "Creating #{path} timed out after #{timeout_period} seconds"
|
104
130
|
end
|
105
131
|
|
106
132
|
def self.cp_r(src, dest, options = {})
|
107
|
-
|
108
|
-
|
109
|
-
if
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
133
|
+
timeout(timeout_period) do
|
134
|
+
# handle all combinations of copying to/from FTP and local files
|
135
|
+
if ftp_url?(src)
|
136
|
+
if FTPFile.directory?(src)
|
137
|
+
mkdir_p dest
|
138
|
+
|
139
|
+
connection = FTPConnection.connect(src)
|
140
|
+
files = connection.nlst
|
141
|
+
files.each {|file| cp_r "#{src}/#{file}", "#{dest}/#{file}", options}
|
142
|
+
else
|
143
|
+
cp(src, dest, options)
|
144
|
+
end
|
145
|
+
elsif ftp_url?(dest)
|
146
|
+
if FTPFile.directory?(dest)
|
147
|
+
mkdir_p dest
|
148
|
+
|
149
|
+
files = Dir.entries(src)
|
150
|
+
files.each {|file| cp_r "#{src}/#{file}", "#{dest}/#{file}", options}
|
151
|
+
else
|
152
|
+
cp(src, dest, options)
|
153
|
+
end
|
124
154
|
else
|
125
|
-
|
155
|
+
FileUtils.cp_r src, dest
|
126
156
|
end
|
127
|
-
else
|
128
|
-
FileUtils.cp_r src, dest
|
129
157
|
end
|
158
|
+
rescue Timeout::Error
|
159
|
+
raise "Copying #{src} to #{dest} timed out after #{timeout_period} seconds"
|
130
160
|
end
|
131
161
|
|
132
162
|
def self.ls(path)
|
133
|
-
|
134
|
-
if
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
163
|
+
timeout(timeout_period) do
|
164
|
+
if ftp_url?(path)
|
165
|
+
if FTPFile.directory?(path)
|
166
|
+
connection = FTPConnection.connect(path)
|
167
|
+
connection.chdir FTPFile.relative_path(path)
|
168
|
+
|
169
|
+
return connection.nlst
|
170
|
+
else
|
171
|
+
nil
|
172
|
+
end
|
139
173
|
else
|
140
|
-
|
174
|
+
Dir.entries path
|
141
175
|
end
|
142
|
-
else
|
143
|
-
Dir.entries path
|
144
176
|
end
|
177
|
+
rescue Timeout::Error
|
178
|
+
raise "Listing #{path} timed out after #{timeout_period} seconds"
|
145
179
|
end
|
146
180
|
|
147
181
|
private
|
@@ -1,29 +1,35 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
|
1
3
|
class FTPUtils
|
2
4
|
class FTPConnection
|
3
5
|
cattr_accessor :connections
|
4
6
|
|
5
7
|
def self.connect(uri)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
8
|
+
timeout(FTPUtils.timeout_period) do
|
9
|
+
if uri.match(/^ftp:\/\/(.*?):(.*?)@(.*?)(\/.*)*$/)
|
10
|
+
username = $1
|
11
|
+
password = $2
|
12
|
+
host = $3
|
13
|
+
|
14
|
+
connection = self.establish_connection(host, username, password)
|
15
|
+
|
16
|
+
# need to reset to the top directory since connections are cached and
|
17
|
+
# could have been left elsewhere. this also provides a way to see if the
|
18
|
+
# connection has expired and needs to be reloaded
|
19
|
+
begin
|
20
|
+
connection.chdir "/"
|
21
|
+
rescue Net::FTPTempError
|
22
|
+
connection = self.establish_connection(host, username, password, true)
|
23
|
+
retry
|
24
|
+
end
|
25
|
+
|
26
|
+
return connection
|
27
|
+
else
|
28
|
+
raise "Invalid FTP URL provided: #{uri}"
|
21
29
|
end
|
22
|
-
|
23
|
-
return connection
|
24
|
-
else
|
25
|
-
raise "Invalid FTP URL provided: #{uri}"
|
26
30
|
end
|
31
|
+
rescue Timeout::Error
|
32
|
+
raise "Connecting to #{uri} timed out after #{FTPUtils.timeout_period} seconds"
|
27
33
|
end
|
28
34
|
|
29
35
|
def self.clear_connection_cache
|
data/spec/ftpconnection_spec.rb
CHANGED
@@ -52,5 +52,17 @@ describe FTPUtils::FTPConnection do
|
|
52
52
|
FTPUtils::FTPConnection.connect("ftp://admin:test@myhost/path/to/file.txt")
|
53
53
|
end.should raise_error(Net::FTPPermError)
|
54
54
|
end
|
55
|
+
|
56
|
+
it "should raise an error if connecting takes too long" do
|
57
|
+
FTPUtils.timeout_period = 0.1
|
58
|
+
|
59
|
+
Net::FTPFXP.should_receive(:new) do
|
60
|
+
sleep 1
|
61
|
+
end
|
62
|
+
|
63
|
+
lambda do
|
64
|
+
FTPUtils::FTPConnection.connect("ftp://admin:test@myhost/path/to/file.txt")
|
65
|
+
end.should raise_error("Connecting to ftp://admin:test@myhost/path/to/file.txt timed out after 0.1 seconds")
|
66
|
+
end
|
55
67
|
end
|
56
68
|
end
|
data/spec/ftputils_spec.rb
CHANGED
@@ -76,6 +76,33 @@ describe "FTPUtils" do
|
|
76
76
|
FTPUtils.cp "ftp://admin:test@host1/subdir1", "ftp://admin:test@host2/subdir2"
|
77
77
|
end.should raise_error("src should be a filename, not a directory")
|
78
78
|
end
|
79
|
+
|
80
|
+
it "should time out a transfer that takes too long" do
|
81
|
+
FTPUtils.timeout_period = 0.1
|
82
|
+
|
83
|
+
FTPUtils::FTPFile.should_receive(:directory?).with("ftp://admin:test@host1/file1.txt").
|
84
|
+
and_return(false)
|
85
|
+
FTPUtils::FTPFile.should_receive(:dirname).with("ftp://admin:test@host2/file2.txt").
|
86
|
+
and_return("/")
|
87
|
+
FTPUtils::FTPFile.should_receive(:basename).with("ftp://admin:test@host2/file2.txt").
|
88
|
+
and_return("file2.txt")
|
89
|
+
|
90
|
+
mock_src_connection = mock(FTPUtils::FTPConnection)
|
91
|
+
FTPUtils::FTPConnection.should_receive(:connect).with("ftp://admin:test@host1/file1.txt").
|
92
|
+
and_return(mock_src_connection)
|
93
|
+
mock_dest_connection = mock(FTPUtils::FTPConnection)
|
94
|
+
FTPUtils::FTPConnection.should_receive(:connect).with("ftp://admin:test@host2/file2.txt").
|
95
|
+
and_return(mock_dest_connection)
|
96
|
+
FTPUtils::FTPFile.should_receive(:relative_path).with("ftp://admin:test@host1/file1.txt").
|
97
|
+
and_return("/file1.txt")
|
98
|
+
mock_src_connection.should_receive(:fxpto).with(mock_dest_connection, "//file2.txt", "/file1.txt") do
|
99
|
+
sleep 1
|
100
|
+
end
|
101
|
+
|
102
|
+
lambda do
|
103
|
+
FTPUtils.cp "ftp://admin:test@host1/file1.txt", "ftp://admin:test@host2/file2.txt"
|
104
|
+
end.should raise_error("Copying ftp://admin:test@host1/file1.txt to ftp://admin:test@host2/file2.txt timed out after 0.1 seconds")
|
105
|
+
end
|
79
106
|
end
|
80
107
|
|
81
108
|
describe "from FTP to the local filesystem" do
|
@@ -119,6 +146,32 @@ describe "FTPUtils" do
|
|
119
146
|
FTPUtils.cp "ftp://admin:test@host1/subdir1/file1.txt", "/home/me"
|
120
147
|
end
|
121
148
|
|
149
|
+
it "should time out a transfer that takes too long" do
|
150
|
+
FTPUtils.timeout_period = 0.1
|
151
|
+
|
152
|
+
FTPUtils::FTPFile.should_receive(:directory?).with("ftp://admin:test@host1/subdir1/file1.txt").
|
153
|
+
and_return(false)
|
154
|
+
|
155
|
+
FTPUtils::FTPFile.should_receive(:basename).with("ftp://admin:test@host1/subdir1/file1.txt").
|
156
|
+
and_return("file1.txt")
|
157
|
+
|
158
|
+
File.should_receive(:directory?).with("/home/me/file2.txt").and_return(false)
|
159
|
+
|
160
|
+
mock_src_connection = mock(FTPUtils::FTPConnection)
|
161
|
+
FTPUtils::FTPConnection.should_receive(:connect).with("ftp://admin:test@host1/subdir1/file1.txt").
|
162
|
+
and_return(mock_src_connection)
|
163
|
+
FTPUtils::FTPFile.should_receive(:dirname).with("ftp://admin:test@host1/subdir1/file1.txt").
|
164
|
+
and_return("/subdir1")
|
165
|
+
mock_src_connection.should_receive(:chdir).with("/subdir1")
|
166
|
+
mock_src_connection.should_receive(:getbinaryfile).with("file1.txt", "/home/me/file2.txt", 1024) do
|
167
|
+
sleep 1
|
168
|
+
end
|
169
|
+
|
170
|
+
lambda do
|
171
|
+
FTPUtils.cp "ftp://admin:test@host1/subdir1/file1.txt", "/home/me/file2.txt"
|
172
|
+
end.should raise_error("Copying ftp://admin:test@host1/subdir1/file1.txt to /home/me/file2.txt timed out after 0.1 seconds")
|
173
|
+
end
|
174
|
+
|
122
175
|
it "should raise an error if the source URI is a directory" do
|
123
176
|
FTPUtils::FTPFile.should_receive(:directory?).with("ftp://admin:test@host1/subdir1").
|
124
177
|
and_return(true)
|
@@ -179,7 +232,29 @@ describe "FTPUtils" do
|
|
179
232
|
|
180
233
|
lambda do
|
181
234
|
FTPUtils.cp "/home/me/file1.txt", "ftp://admin:test@host2/file2.txt"
|
182
|
-
end.should raise_error("Unable to copy /home/me/file1.txt to /file2.txt, possibly due to FTP server permissions")
|
235
|
+
end.should raise_error("Unable to copy /home/me/file1.txt to ftp://admin:test@host2/file2.txt, possibly due to FTP server permissions")
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should time out a transfer that takes too long" do
|
239
|
+
FTPUtils.timeout_period = 0.1
|
240
|
+
|
241
|
+
File.should_receive(:directory?).with("/home/me/file1.txt").and_return(false)
|
242
|
+
FTPUtils::FTPFile.should_receive(:relative_path).with("ftp://admin:test@host2/file2.txt").
|
243
|
+
and_return("/file2.txt")
|
244
|
+
FTPUtils::FTPFile.should_receive(:directory?).with("ftp://admin:test@host2/file2.txt").
|
245
|
+
and_return(false)
|
246
|
+
mock_dest_connection = mock(FTPUtils::FTPConnection)
|
247
|
+
FTPUtils::FTPConnection.should_receive(:connect).with("ftp://admin:test@host2/file2.txt").
|
248
|
+
and_return(mock_dest_connection)
|
249
|
+
FTPUtils::FTPFile.should_receive(:dirname).with("ftp://admin:test@host2/file2.txt").and_return("/")
|
250
|
+
mock_dest_connection.should_receive(:chdir).with("/")
|
251
|
+
mock_dest_connection.should_receive(:putbinaryfile).with("/home/me/file1.txt", "/file2.txt", 1024) do
|
252
|
+
sleep 1
|
253
|
+
end
|
254
|
+
|
255
|
+
lambda do
|
256
|
+
FTPUtils.cp "/home/me/file1.txt", "ftp://admin:test@host2/file2.txt"
|
257
|
+
end.should raise_error("Copying /home/me/file1.txt to ftp://admin:test@host2/file2.txt timed out after 0.1 seconds")
|
183
258
|
end
|
184
259
|
|
185
260
|
it "should raise an error if the source file is a directory" do
|
@@ -228,6 +303,25 @@ describe "FTPUtils" do
|
|
228
303
|
|
229
304
|
FTPUtils.rm "file.txt"
|
230
305
|
end
|
306
|
+
|
307
|
+
it "should time out a removal that takes too long" do
|
308
|
+
FTPUtils.timeout_period = 0.1
|
309
|
+
|
310
|
+
FTPUtils::FTPFile.should_receive(:directory?).with("ftp://admin:test@host1/subdir1/file.txt").
|
311
|
+
and_return(false)
|
312
|
+
mock_connection = mock(FTPUtils::FTPConnection)
|
313
|
+
FTPUtils::FTPConnection.should_receive(:connect).with("ftp://admin:test@host1/subdir1/file.txt").
|
314
|
+
and_return(mock_connection)
|
315
|
+
FTPUtils::FTPFile.should_receive(:dirname).with("ftp://admin:test@host1/subdir1/file.txt").and_return("/subdir1")
|
316
|
+
mock_connection.should_receive(:chdir).with("/subdir1")
|
317
|
+
mock_connection.should_receive(:delete).with("file.txt") do
|
318
|
+
sleep 1
|
319
|
+
end
|
320
|
+
|
321
|
+
lambda do
|
322
|
+
FTPUtils.rm "ftp://admin:test@host1/subdir1/file.txt"
|
323
|
+
end.should raise_error("Removing ftp://admin:test@host1/subdir1/file.txt timed out after 0.1 seconds")
|
324
|
+
end
|
231
325
|
end
|
232
326
|
|
233
327
|
describe "removing recursively" do
|
@@ -275,6 +369,43 @@ describe "FTPUtils" do
|
|
275
369
|
|
276
370
|
FTPUtils.rm_r "dir"
|
277
371
|
end
|
372
|
+
|
373
|
+
it "should time out a removal that takes too long" do
|
374
|
+
FTPUtils.timeout_period = 0.1
|
375
|
+
|
376
|
+
FTPUtils::FTPFile.should_receive(:directory?).with("ftp://admin:test@host1/subdir1").
|
377
|
+
and_return(true)
|
378
|
+
mock_connection = mock(FTPUtils::FTPConnection)
|
379
|
+
FTPUtils::FTPConnection.should_receive(:connect).with("ftp://admin:test@host1/subdir1").
|
380
|
+
and_return(mock_connection)
|
381
|
+
mock_connection.should_receive(:chdir).with("/subdir1")
|
382
|
+
mock_connection.should_receive(:nlst).and_return( ["subdir2", "file.txt"] )
|
383
|
+
|
384
|
+
FTPUtils::FTPFile.should_receive(:directory?).with("ftp://admin:test@host1/subdir1/subdir2").
|
385
|
+
and_return(true)
|
386
|
+
mock_subdir_connection = mock(FTPUtils::FTPConnection)
|
387
|
+
FTPUtils::FTPConnection.should_receive(:connect).with("ftp://admin:test@host1/subdir1/subdir2").
|
388
|
+
and_return(mock_subdir_connection)
|
389
|
+
mock_subdir_connection.should_receive(:chdir).with("/subdir1/subdir2")
|
390
|
+
mock_subdir_connection.should_receive(:nlst).and_return( [] )
|
391
|
+
FTPUtils::FTPFile.should_receive(:relative_path).with("ftp://admin:test@host1/subdir1/subdir2").twice.
|
392
|
+
and_return("/subdir1/subdir2")
|
393
|
+
mock_subdir_connection.should_receive(:rmdir).with("/subdir1/subdir2")
|
394
|
+
|
395
|
+
FTPUtils::FTPFile.should_receive(:directory?).with("ftp://admin:test@host1/subdir1/file.txt").
|
396
|
+
and_return(false)
|
397
|
+
FTPUtils.should_receive(:rm).with("ftp://admin:test@host1/subdir1/file.txt")
|
398
|
+
|
399
|
+
FTPUtils::FTPFile.should_receive(:relative_path).with("ftp://admin:test@host1/subdir1").twice.
|
400
|
+
and_return("/subdir1")
|
401
|
+
mock_connection.should_receive(:rmdir).with("/subdir1") do
|
402
|
+
sleep 1
|
403
|
+
end
|
404
|
+
|
405
|
+
lambda do
|
406
|
+
FTPUtils.rm_r "ftp://admin:test@host1/subdir1"
|
407
|
+
end.should raise_error("Removing ftp://admin:test@host1/subdir1 timed out after 0.1 seconds")
|
408
|
+
end
|
278
409
|
end
|
279
410
|
|
280
411
|
describe "create a directory and all its parents" do
|
@@ -299,6 +430,25 @@ describe "FTPUtils" do
|
|
299
430
|
|
300
431
|
FTPUtils.mkdir_p("subdir1/subdir2")
|
301
432
|
end
|
433
|
+
|
434
|
+
it "should time out a creation that takes too long" do
|
435
|
+
FTPUtils.timeout_period = 0.1
|
436
|
+
|
437
|
+
mock_connection = mock(FTPUtils::FTPConnection)
|
438
|
+
FTPUtils::FTPConnection.should_receive(:connect).with("ftp://admin:test@host1/subdir1/subdir2").
|
439
|
+
and_return(mock_connection)
|
440
|
+
|
441
|
+
FTPUtils::FTPFile.should_receive(:relative_path).with("ftp://admin:test@host1/subdir1/subdir2").
|
442
|
+
and_return("/subdir1/subdir2")
|
443
|
+
|
444
|
+
mock_connection.should_receive(:mkdir).with("subdir1") do
|
445
|
+
sleep 1
|
446
|
+
end
|
447
|
+
|
448
|
+
lambda do
|
449
|
+
FTPUtils.mkdir_p "ftp://admin:test@host1/subdir1/subdir2"
|
450
|
+
end.should raise_error("Creating ftp://admin:test@host1/subdir1/subdir2 timed out after 0.1 seconds")
|
451
|
+
end
|
302
452
|
end
|
303
453
|
|
304
454
|
describe "copying recursively" do
|
@@ -375,6 +525,18 @@ describe "FTPUtils" do
|
|
375
525
|
|
376
526
|
FTPUtils.cp_r "/home/me/subdir1", "/home/me/subdir2"
|
377
527
|
end
|
528
|
+
|
529
|
+
it "should time out a copy that takes too long" do
|
530
|
+
FTPUtils.timeout_period = 0.1
|
531
|
+
|
532
|
+
FTPUtils::FTPFile.should_receive(:directory?).with("ftp://admin:test@host1/subdir1") do
|
533
|
+
sleep 1
|
534
|
+
end
|
535
|
+
|
536
|
+
lambda do
|
537
|
+
FTPUtils.cp_r "ftp://admin:test@host1/subdir1", "ftp://admin:test@host2/subdir2"
|
538
|
+
end.should raise_error("Copying ftp://admin:test@host1/subdir1 to ftp://admin:test@host2/subdir2 timed out after 0.1 seconds")
|
539
|
+
end
|
378
540
|
end
|
379
541
|
|
380
542
|
describe "listing the entries in a directory" do
|
@@ -402,5 +564,17 @@ describe "FTPUtils" do
|
|
402
564
|
|
403
565
|
FTPUtils.ls("/home/me/subdir1")
|
404
566
|
end
|
567
|
+
|
568
|
+
it "should time out a directory listing that takes too long" do
|
569
|
+
FTPUtils.timeout_period = 0.1
|
570
|
+
|
571
|
+
FTPUtils::FTPFile.should_receive(:directory?).with("ftp://admin:test@host1/subdir1") do
|
572
|
+
sleep 1
|
573
|
+
end
|
574
|
+
|
575
|
+
lambda do
|
576
|
+
FTPUtils.ls("ftp://admin:test@host1/subdir1")
|
577
|
+
end.should raise_error("Listing ftp://admin:test@host1/subdir1 timed out after 0.1 seconds")
|
578
|
+
end
|
405
579
|
end
|
406
580
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 1
|
9
|
+
version: 0.2.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Bruz Marzolf
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date:
|
17
|
+
date: 2011-06-20 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -56,11 +56,12 @@ extra_rdoc_files:
|
|
56
56
|
- README.rdoc
|
57
57
|
files:
|
58
58
|
- .document
|
59
|
-
- .
|
59
|
+
- CHANGELOG.rdoc
|
60
60
|
- LICENSE
|
61
61
|
- README.rdoc
|
62
62
|
- Rakefile
|
63
63
|
- VERSION
|
64
|
+
- ftputils.gemspec
|
64
65
|
- lib/ftputils.rb
|
65
66
|
- lib/ftputils/ext/class.rb
|
66
67
|
- lib/ftputils/ftpconnection.rb
|
@@ -77,8 +78,8 @@ homepage: http://github.com/bmarzolf/ftputils
|
|
77
78
|
licenses: []
|
78
79
|
|
79
80
|
post_install_message:
|
80
|
-
rdoc_options:
|
81
|
-
|
81
|
+
rdoc_options: []
|
82
|
+
|
82
83
|
require_paths:
|
83
84
|
- lib
|
84
85
|
required_ruby_version: !ruby/object:Gem::Requirement
|