xftp 0.3.3 → 0.4.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.
- checksums.yaml +4 -4
- data/README.md +33 -1
- data/lib/xftp/operations/ftp/glob.rb +5 -0
- data/lib/xftp/session/base.rb +6 -0
- data/lib/xftp/session/ftp.rb +41 -7
- data/lib/xftp/session/sftp.rb +51 -8
- data/lib/xftp/version.rb +2 -2
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 519e2c6a592998d81cfcff39a0b07896de6d107a
|
|
4
|
+
data.tar.gz: 7c964302e0290616bb71e32fa2da427804c0a839
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 21e2e2c9f5d002ea1cbb48bafb28fb08f1e6645ba5eac6d1131dcf1093b8b1f1458cbc0ea077c951cdf6ac4267e38fdd9728f0f46b33a4432504900a91cf3b4a
|
|
7
|
+
data.tar.gz: 06b5984a465cefa1e955550d5dfc0859d5f995fa7ce3294c7f7985e66c2e4cf9afcbc3cd4a31e86d9047c335f28952932bf10598386182f7acfa8c31f2703249
|
data/README.md
CHANGED
|
@@ -17,8 +17,9 @@ or
|
|
|
17
17
|
$ gem install xftp
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
## Usage
|
|
20
|
+
## Usage examples
|
|
21
21
|
|
|
22
|
+
Basic example:
|
|
22
23
|
```ruby
|
|
23
24
|
XFTP.start('ftps://hostname', credentials: { login: 'login', password: 'pass' }) do |x|
|
|
24
25
|
x.chdir 'remote-src-path'
|
|
@@ -32,6 +33,37 @@ XFTP.start('ftps://hostname', credentials: { login: 'login', password: 'pass' })
|
|
|
32
33
|
end
|
|
33
34
|
```
|
|
34
35
|
|
|
36
|
+
Connection as anonymous with emtpy password, checking remote dir existence, globbing and getting `StringIO`'s:
|
|
37
|
+
```ruby
|
|
38
|
+
XFTP.start('ftp://hostname') do |x|
|
|
39
|
+
x.mkdir 'some-dir' unless x.exist? 'some-dir'
|
|
40
|
+
x.glob '*.csv' do |filename|
|
|
41
|
+
io = x.get filename
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Example using `each_io`:
|
|
47
|
+
```ruby
|
|
48
|
+
XFTP.start('ftps://hostname', credentials: { login: 'login', password: 'password' }) do |x|
|
|
49
|
+
x.chdir 'some-dir'
|
|
50
|
+
x.each_io do |filename, io|
|
|
51
|
+
# do smth with it
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Wihout block argument (ntoe that you should rely on you local execution context objects):
|
|
57
|
+
```ruby
|
|
58
|
+
XFTP.start('ftps://hostname', credentials: credentials)
|
|
59
|
+
chdir 'blahblah'
|
|
60
|
+
each_file do |filename|
|
|
61
|
+
download filename, to: File.join('local-dir', filename)
|
|
62
|
+
move filename, to: File.join('remote-archive-path', filename)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
```
|
|
66
|
+
|
|
35
67
|
## Development
|
|
36
68
|
|
|
37
69
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
@@ -7,6 +7,8 @@ module XFTP
|
|
|
7
7
|
# @note It isn't tested on Windows OS and chances are that it won't work,
|
|
8
8
|
# that's why it is implemented as a separate "command"
|
|
9
9
|
class Glob
|
|
10
|
+
NO_SUCH_FILE_OR_DIRECTORY_CODE = 450
|
|
11
|
+
|
|
10
12
|
def initialize(ftp)
|
|
11
13
|
@ftp = ftp
|
|
12
14
|
end
|
|
@@ -17,6 +19,9 @@ module XFTP
|
|
|
17
19
|
# @param [Proc] callback
|
|
18
20
|
def call(pattern, &callback)
|
|
19
21
|
@ftp.nlst(pattern).each { |filename| callback.call(filename) }
|
|
22
|
+
rescue Net::FTPTempError => err
|
|
23
|
+
code = err.to_s[0, 3].try(:to_i)
|
|
24
|
+
raise err unless code == NO_SUCH_FILE_OR_DIRECTORY_CODE
|
|
20
25
|
end
|
|
21
26
|
end
|
|
22
27
|
end
|
data/lib/xftp/session/base.rb
CHANGED
data/lib/xftp/session/ftp.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
require 'active_support/core_ext/hash/deep_merge'
|
|
2
|
-
require 'forwardable'
|
|
3
2
|
require 'net/ftp'
|
|
4
3
|
|
|
5
4
|
require 'xftp/session/base'
|
|
@@ -10,12 +9,6 @@ module XFTP
|
|
|
10
9
|
# FTP session adapter
|
|
11
10
|
# @api private
|
|
12
11
|
class FTP < Base
|
|
13
|
-
extend Forwardable
|
|
14
|
-
|
|
15
|
-
# Delegate methods which have the same method signature
|
|
16
|
-
# directly to Net::FTP session
|
|
17
|
-
def_delegators :@ftp, :chdir, :mkdir, :rmdir
|
|
18
|
-
|
|
19
12
|
# Creates an FTP session adapter instance
|
|
20
13
|
# @param [URI] uri the remote uri
|
|
21
14
|
# @param [Hash] settings the adapter connection settings
|
|
@@ -30,14 +23,40 @@ module XFTP
|
|
|
30
23
|
options.each { |key, val| @ftp.public_send("#{key}=", val) }
|
|
31
24
|
end
|
|
32
25
|
|
|
26
|
+
# Changes the current (remote) working directory
|
|
27
|
+
# @param [String] path the relative (remote) path
|
|
28
|
+
def chdir(path)
|
|
29
|
+
ensure_relative_path! :chdir, path
|
|
30
|
+
@ftp.chdir path
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Creates a remote directory
|
|
34
|
+
# @param [String] dirname the name of new directory
|
|
35
|
+
# relative to the current (remote) working directory
|
|
36
|
+
def mkdir(dirname)
|
|
37
|
+
ensure_relative_path! :mkdir, dirname
|
|
38
|
+
@ftp.mkdir dirname
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Removes the remote directory
|
|
42
|
+
# @param [String] dirname the name of directory to be removed
|
|
43
|
+
def rmdir(dirname)
|
|
44
|
+
ensure_relative_path! :rmdir, dirname
|
|
45
|
+
@ftp.rmdir dirname
|
|
46
|
+
end
|
|
47
|
+
|
|
33
48
|
# @return [Boolean] `true` if the argument refers to a directory on the remote host
|
|
34
49
|
def exists?(dirname)
|
|
35
50
|
entries.include? dirname
|
|
36
51
|
end
|
|
37
52
|
|
|
53
|
+
# HACK: It looks ridiculous, but its the only way to find out
|
|
54
|
+
# if the given remote path is a file or directory
|
|
55
|
+
|
|
38
56
|
# @return [Boolean] `true` if the argument refers to
|
|
39
57
|
# a directory on the remote host
|
|
40
58
|
def directory?(path)
|
|
59
|
+
ensure_relative_path! :directory?, path
|
|
41
60
|
chdir path
|
|
42
61
|
chdir '..'
|
|
43
62
|
true
|
|
@@ -65,6 +84,21 @@ module XFTP
|
|
|
65
84
|
files.each { |filename| yield filename }
|
|
66
85
|
end
|
|
67
86
|
|
|
87
|
+
# Calls the block once for each entry in the current directory
|
|
88
|
+
# on the remote server and yields a filename and `StringIO` object to the block
|
|
89
|
+
def each_io
|
|
90
|
+
each_file do |filename|
|
|
91
|
+
io = get filename
|
|
92
|
+
yield filename, io
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Downloads file into IO object
|
|
97
|
+
# @return [StringIO] the remote file data
|
|
98
|
+
def get(filename)
|
|
99
|
+
@ftp.getbinaryfile(filename, nil)
|
|
100
|
+
end
|
|
101
|
+
|
|
68
102
|
# @see XFTP::Operations::FTP::Glob
|
|
69
103
|
def glob(pattern, &callback)
|
|
70
104
|
Operations::FTP::Glob.new(@ftp).call(pattern, &callback)
|
data/lib/xftp/session/sftp.rb
CHANGED
|
@@ -8,6 +8,31 @@ module XFTP
|
|
|
8
8
|
# SFTP session adapter
|
|
9
9
|
# @api private
|
|
10
10
|
class SFTP < Base
|
|
11
|
+
# Helper class for progress monitoring
|
|
12
|
+
class ProgressHandler
|
|
13
|
+
include Helpers::Logging
|
|
14
|
+
|
|
15
|
+
def on_open(_downloader, file)
|
|
16
|
+
log "starting download: #{file.remote} -> #{file.local} (#{file.size} bytes)"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def on_get(_downloader, file, offset, data)
|
|
20
|
+
log "writing #{data.length} bytes to #{file.local} starting at #{offset}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def on_close(_downloader, file)
|
|
24
|
+
log "finished with #{file.remote}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def on_mkdir(_downloader, path)
|
|
28
|
+
log "creating directory #{path}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def on_finish(_downloader)
|
|
32
|
+
log 'done'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
11
36
|
# Default flags for rename operation
|
|
12
37
|
RENAME_OPERATION_FLAGS = 0x0004
|
|
13
38
|
# Default flags for glob operation
|
|
@@ -26,6 +51,7 @@ module XFTP
|
|
|
26
51
|
# Changes the current (remote) working directory
|
|
27
52
|
# @param [String] path the relative (remote) path
|
|
28
53
|
def chdir(path)
|
|
54
|
+
ensure_relative_path! :chdir, path
|
|
29
55
|
@path += path
|
|
30
56
|
end
|
|
31
57
|
|
|
@@ -35,9 +61,17 @@ module XFTP
|
|
|
35
61
|
# @param [Hash] attrs the attributes of new directory
|
|
36
62
|
# supported by the the version of SFTP protocol in use
|
|
37
63
|
def mkdir(dirname, attrs = {})
|
|
64
|
+
ensure_relative_path! :mkdir, path
|
|
38
65
|
@sftp.mkdir!(remote_path(dirname), attrs)
|
|
39
66
|
end
|
|
40
67
|
|
|
68
|
+
# Removes the remote directory
|
|
69
|
+
# @param [String] dirname the name of directory to be removed
|
|
70
|
+
def rmdir(dirname)
|
|
71
|
+
ensure_relative_path! :rmdir, path
|
|
72
|
+
@sftp.rmdir! remote_path(dirname)
|
|
73
|
+
end
|
|
74
|
+
|
|
41
75
|
# @return [Boolean] `true` if the file exists
|
|
42
76
|
# in a current working directory on the remote host
|
|
43
77
|
def exists?(filename)
|
|
@@ -47,6 +81,7 @@ module XFTP
|
|
|
47
81
|
# @return [Boolean] `true` if the argument refers to
|
|
48
82
|
# a directory on the remote host
|
|
49
83
|
def directory?(path)
|
|
84
|
+
ensure_relative_path! :directory?, path
|
|
50
85
|
@sftp.file.directory? remote_path(path)
|
|
51
86
|
end
|
|
52
87
|
|
|
@@ -56,12 +91,6 @@ module XFTP
|
|
|
56
91
|
!directory?(path)
|
|
57
92
|
end
|
|
58
93
|
|
|
59
|
-
# Removes the remote directory
|
|
60
|
-
# @param [String] dirname the name of directory to be removed
|
|
61
|
-
def rmdir(dirname)
|
|
62
|
-
@sftp.rmdir! remote_path(dirname)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
94
|
# Renames (moves) a file on the server
|
|
66
95
|
# @param [String] from the path to move from
|
|
67
96
|
# @param [String] to the path to move to
|
|
@@ -79,6 +108,21 @@ module XFTP
|
|
|
79
108
|
end
|
|
80
109
|
end
|
|
81
110
|
|
|
111
|
+
# Calls the block once for each entry in the current directory
|
|
112
|
+
# on the remote server and (asynchronously) yields a filename and `StringIO` object to the block
|
|
113
|
+
def each_io
|
|
114
|
+
each_file do |filename|
|
|
115
|
+
io = get filename
|
|
116
|
+
yield filename, io
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Downloads file into IO object
|
|
121
|
+
# @return [StringIO] the remote file data
|
|
122
|
+
def get(filename)
|
|
123
|
+
@sftp.download!(remote_path(filename), nil, progress: ProgressHandler)
|
|
124
|
+
end
|
|
125
|
+
|
|
82
126
|
# For more info (see Dir#glob), it's almost of the same nature
|
|
83
127
|
# @param [String] pattern the search pattern relative
|
|
84
128
|
# the the current working directory
|
|
@@ -105,8 +149,7 @@ module XFTP
|
|
|
105
149
|
entries.reject { |filename| directory? filename }
|
|
106
150
|
end
|
|
107
151
|
|
|
108
|
-
# @return [Array<String>] an array of entries (including directories)
|
|
109
|
-
# in the remote directory
|
|
152
|
+
# @return [Array<String>] an array of entries (including directories) in the remote directory
|
|
110
153
|
def entries
|
|
111
154
|
@sftp.dir.entries(@path.to_s).map(&:name)
|
|
112
155
|
end
|
data/lib/xftp/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: xftp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vasiliy Yorkin
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-04-
|
|
11
|
+
date: 2015-04-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -239,6 +239,6 @@ rubyforge_project:
|
|
|
239
239
|
rubygems_version: 2.2.2
|
|
240
240
|
signing_key:
|
|
241
241
|
specification_version: 4
|
|
242
|
-
summary: xftp-0.
|
|
242
|
+
summary: xftp-0.4.1
|
|
243
243
|
test_files: []
|
|
244
244
|
has_rdoc:
|