bfs-ftp 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 996793546b6def5f901a9d609a1a87fb4c229ce11808519119b0b3e485d459eb
4
+ data.tar.gz: 973ca56c2d859de7ca93fb6774055667b66f929cbcc857849e24b1f6f0cb0723
5
+ SHA512:
6
+ metadata.gz: cd8dd65cf5f0b0230a0f30e2f51fc4f2d438768df108a7d9d0c07f0a129fe6fb2aded68c2ef8310cd37d8767ec36c9270f97618932044e4bd237174262d82135
7
+ data.tar.gz: 36ab986b28ca63d6c39f3d0bb32805509a0b66f332e153c168b5e8c0f682d0475f00e97c2a56b7cf3dd517323bdc232c045d7e31d7105b9cf84d452a68dead9a
@@ -0,0 +1,22 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'bfs-ftp'
3
+ s.version = File.read(File.expand_path('../.version', __dir__)).strip
4
+ s.platform = Gem::Platform::RUBY
5
+
6
+ s.licenses = ['Apache-2.0']
7
+ s.summary = 'FTP adapter for bfs'
8
+ s.description = 'https://github.com/bsm/bfs.rb'
9
+
10
+ s.authors = ['Dimitrij Denissenko']
11
+ s.email = 'dimitrij@blacksquaremedia.com'
12
+ s.homepage = 'https://github.com/bsm/bfs.rb'
13
+
14
+ s.executables = []
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- spec/*`.split("\n")
17
+ s.require_paths = ['lib']
18
+ s.required_ruby_version = '>= 2.4.0'
19
+
20
+ s.add_dependency 'bfs', s.version
21
+ s.add_dependency 'net-ftp-list'
22
+ end
@@ -0,0 +1,136 @@
1
+ require 'bfs'
2
+ require 'net/ftp/list'
3
+ require 'cgi'
4
+
5
+ module BFS
6
+ module Bucket
7
+ # FTP buckets are operating on ftp servers
8
+ class FTP < Abstract
9
+
10
+ # Initializes a new bucket
11
+ # @param [String] host the host name
12
+ # @param [Hash] opts options
13
+ # @option opts [Integer] :port custom port. Default: 21.
14
+ # @option opts [Boolean] :ssl will attempt to use SSL.
15
+ # @option opts [String] :username user name for login.
16
+ # @option opts [String] :password password for login.
17
+ # @option opts [String] :passive connect in passive mode. Default: true.
18
+ # @option opts [String] :prefix optional prefix.
19
+ def initialize(host, opts={})
20
+ opts = opts.dup
21
+ opts.keys.each do |key|
22
+ val = opts.delete(key)
23
+ opts[key.to_sym] = val unless val.nil?
24
+ end
25
+ super(opts)
26
+
27
+ prefix = opts.delete(:prefix)
28
+ @client = Net::FTP.new(host, opts)
29
+ @client.binary = true
30
+
31
+ if prefix # rubocop:disable Style/GuardClause
32
+ prefix = norm_path(prefix)
33
+ mkdir_p(prefix)
34
+ @client.chdir(prefix)
35
+ end
36
+ end
37
+
38
+ # Lists the contents of a bucket using a glob pattern
39
+ def ls(pattern='**/*', _opts={})
40
+ dir = pattern[%r{^[^\*\?\{\}\[\]]+/}]
41
+ dir&.chomp!('/')
42
+
43
+ Enumerator.new do |y|
44
+ glob(dir) do |path|
45
+ y << path if File.fnmatch?(pattern, path, File::FNM_PATHNAME)
46
+ end
47
+ end
48
+ end
49
+
50
+ # Info returns the object info
51
+ def info(path, _opts={})
52
+ path = norm_path(path)
53
+ BFS::FileInfo.new(path, @client.size(path), @client.mtime(path))
54
+ rescue Net::FTPPermError
55
+ raise BFS::FileNotFound, path
56
+ end
57
+
58
+ # Creates a new file and opens it for writing
59
+ def create(path, opts={}, &block)
60
+ path = norm_path(path)
61
+ enc = opts.delete(:encoding) || @encoding
62
+ temp = BFS::TempWriter.new(path, encoding: enc) do |t|
63
+ mkdir_p File.dirname(path)
64
+ @client.put(t, path)
65
+ end
66
+ return temp unless block
67
+
68
+ begin
69
+ yield temp
70
+ ensure
71
+ temp.close
72
+ end
73
+ end
74
+
75
+ # Opens an existing file for reading
76
+ def open(path, opts={}, &block)
77
+ path = norm_path(path)
78
+ enc = opts.delete(:encoding) || @encoding
79
+ temp = Tempfile.new(File.basename(path), encoding: enc)
80
+ temp.close
81
+
82
+ @client.get(path, temp.path)
83
+ File.open(temp.path, encoding: enc, &block)
84
+ rescue Net::FTPPermError
85
+ raise BFS::FileNotFound, path
86
+ end
87
+
88
+ # Deletes a file.
89
+ def rm(path, _opts={})
90
+ path = norm_path(path)
91
+ @client.delete(path)
92
+ rescue Net::FTPPermError # rubocop:disable Lint/HandleExceptions
93
+ end
94
+
95
+ # Closes the underlying connection
96
+ def close
97
+ @client.close
98
+ end
99
+
100
+ private
101
+
102
+ def glob(dir, &block)
103
+ @client.ls(dir || '.') do |e|
104
+ entry = Net::FTP::List.parse(e)
105
+ if entry.dir?
106
+ subdir = [dir, entry.basename].compact.join('/')
107
+ glob subdir, &block
108
+ elsif entry.file?
109
+ yield [dir, entry.basename].compact.join('/')
110
+ end
111
+ end
112
+ end
113
+
114
+ def mkdir_p(path)
115
+ parts = path.split('/').reject(&:empty?)
116
+ (0...parts.size).each do |i|
117
+ begin
118
+ @client.mkdir parts[0..i].join('/')
119
+ rescue Net::FTPPermError # rubocop:disable Lint/HandleExceptions
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ BFS.register('ftp', 'sftp') do |url|
128
+ params = CGI.parse(url.query.to_s)
129
+
130
+ BFS::Bucket::FTP.new url.host,
131
+ username: url.user ? CGI.unescape(url.user) : nil,
132
+ password: url.password ? CGI.unescape(url.password) : nil,
133
+ port: url.port,
134
+ ssl: params.key?('ssl') || url.scheme == 'sftp',
135
+ prefix: params.key?('prefix') ? params['prefix'].first : nil
136
+ end
@@ -0,0 +1 @@
1
+ require 'bfs/bucket/ftp'
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ sandbox = { host: '127.0.0.1', port: 7021, username: 'ftpuser', password: 'ftppass' }.freeze
4
+ run_spec = \
5
+ begin
6
+ ftp = Net::FTP.new sandbox[:host], sandbox
7
+ ftp.list
8
+ ftp.close
9
+ rescue Errno::ECONNREFUSED, Net::FTPError => e
10
+ warn "WARNING: unable to run #{File.basename __FILE__}: #{e.message}"
11
+ false
12
+ end
13
+
14
+ RSpec.describe BFS::Bucket::FTP, if: run_spec do
15
+ subject { described_class.new sandbox[:host], sandbox.merge(prefix: SecureRandom.uuid) }
16
+ after { subject.close }
17
+
18
+ it_behaves_like 'a bucket',
19
+ content_type: false,
20
+ metadata: false
21
+
22
+ it 'should resolve from URL' do
23
+ bucket = BFS.resolve('ftp://ftpuser:ftppass@127.0.0.1:7021')
24
+ expect(bucket).to be_instance_of(described_class)
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bfs-ftp
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.1
5
+ platform: ruby
6
+ authors:
7
+ - Dimitrij Denissenko
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-09-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bfs
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.4.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.4.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: net-ftp-list
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: https://github.com/bsm/bfs.rb
42
+ email: dimitrij@blacksquaremedia.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - bfs-ftp.gemspec
48
+ - lib/bfs/bucket/ftp.rb
49
+ - lib/bfs/ftp.rb
50
+ - spec/bfs/bucket/ftp_spec.rb
51
+ homepage: https://github.com/bsm/bfs.rb
52
+ licenses:
53
+ - Apache-2.0
54
+ metadata: {}
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 2.4.0
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubygems_version: 3.0.3
71
+ signing_key:
72
+ specification_version: 4
73
+ summary: FTP adapter for bfs
74
+ test_files:
75
+ - spec/bfs/bucket/ftp_spec.rb