bfs-scp 0.7.5 → 0.8.3
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/lib/bfs/bucket/scp.rb +55 -22
- data/spec/bfs/bucket/scp_spec.rb +13 -11
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d524b38b123694cf69ceb9b14ed758047564190ef3dba78e2eccc191970f0e89
|
4
|
+
data.tar.gz: 8e805bf4b7f688334333a5afb4fdff89c1c78fa734812e82e1d8fe3630a45ccd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3956f06a9b2f00fb526f2768cb69b767372dab35adcb2b889a08bf440a1e43f462676a72927712e7e81fe1ddebf8a49687eb3b1ffe56cd8edd96c764f76e485
|
7
|
+
data.tar.gz: 424781ca80c8e6302511abc854e850db438408e54dc7af3d5eea5acf12bbc8aff99722be2f633588b271613fc8b6892f1d7ab739e1d8c8e1165a42d2c340eca8
|
data/lib/bfs/bucket/scp.rb
CHANGED
@@ -42,14 +42,15 @@ module BFS
|
|
42
42
|
|
43
43
|
# Lists the contents of a bucket using a glob pattern
|
44
44
|
def ls(pattern = '**/*', **_opts)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
45
|
+
Enumerator.new do |acc|
|
46
|
+
walk(pattern) {|path| acc << path }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Iterates over the contents of a bucket using a glob pattern
|
51
|
+
def glob(pattern = '**/*', **_opts)
|
52
|
+
Enumerator.new do |acc|
|
53
|
+
walk(pattern, with_stat: true) {|info| acc << info }
|
53
54
|
end
|
54
55
|
end
|
55
56
|
|
@@ -57,9 +58,11 @@ module BFS
|
|
57
58
|
def info(path, **_opts)
|
58
59
|
full = full_path(path)
|
59
60
|
path = norm_path(path)
|
60
|
-
out = sh!
|
61
|
+
out = sh! %(stat -c '%F;%s;%Z;%a' #{Shellwords.escape full})
|
62
|
+
|
63
|
+
type, size, epoch, mode = out.strip.split(';', 4)
|
64
|
+
raise BFS::FileNotFound, path unless type.include?('file')
|
61
65
|
|
62
|
-
size, epoch, mode = out.strip.split(';', 3)
|
63
66
|
BFS::FileInfo.new(path: path, size: size.to_i, mtime: Time.at(epoch.to_i), mode: BFS.norm_mode(mode))
|
64
67
|
rescue CommandError => e
|
65
68
|
e.status == 1 ? raise(BFS::FileNotFound, path) : raise
|
@@ -72,7 +75,7 @@ module BFS
|
|
72
75
|
full = full_path(path)
|
73
76
|
|
74
77
|
opts[:preserve] = true if perm && !opts.key?(:preserve)
|
75
|
-
BFS::
|
78
|
+
BFS::Writer.new(path, encoding: encoding, perm: perm) do |temp_path|
|
76
79
|
mkdir_p File.dirname(full)
|
77
80
|
@client.upload!(temp_path, full, **opts)
|
78
81
|
end.perform(&block)
|
@@ -93,7 +96,7 @@ module BFS
|
|
93
96
|
# Deletes a file.
|
94
97
|
def rm(path, **_opts)
|
95
98
|
path = full_path(path)
|
96
|
-
sh!
|
99
|
+
sh! %(rm -f #{Shellwords.escape(path)})
|
97
100
|
end
|
98
101
|
|
99
102
|
# Copies src to dst
|
@@ -105,7 +108,7 @@ module BFS
|
|
105
108
|
full_dst = full_path(dst)
|
106
109
|
|
107
110
|
mkdir_p File.dirname(full_dst)
|
108
|
-
sh!
|
111
|
+
sh! %(cp -a -f #{Shellwords.escape(full_src)} #{Shellwords.escape(full_dst)})
|
109
112
|
rescue CommandError => e
|
110
113
|
e.status == 1 ? raise(BFS::FileNotFound, src) : raise
|
111
114
|
end
|
@@ -119,7 +122,7 @@ module BFS
|
|
119
122
|
full_dst = full_path(dst)
|
120
123
|
|
121
124
|
mkdir_p File.dirname(full_dst)
|
122
|
-
sh!
|
125
|
+
sh! %(mv -f #{Shellwords.escape(full_src)} #{Shellwords.escape(full_dst)})
|
123
126
|
rescue CommandError => e
|
124
127
|
e.status == 1 ? raise(BFS::FileNotFound, src) : raise
|
125
128
|
end
|
@@ -140,23 +143,47 @@ module BFS
|
|
140
143
|
abs_path(super)
|
141
144
|
end
|
142
145
|
|
146
|
+
def walk(pattern, with_stat: false)
|
147
|
+
prefix = @prefix ? abs_path(@prefix) : '/'
|
148
|
+
command = %(find #{Shellwords.escape(prefix)} -type f)
|
149
|
+
command << %( -exec stat -c '%s;%Z;%a;%n' {} \\;) if with_stat
|
150
|
+
|
151
|
+
sh!(command) do |out|
|
152
|
+
out.each_line do |line|
|
153
|
+
line.strip!
|
154
|
+
|
155
|
+
if with_stat
|
156
|
+
size, epoch, mode, path = out.strip.split(';', 4)
|
157
|
+
path = trim_prefix(norm_path(path))
|
158
|
+
next unless File.fnmatch?(pattern, path, File::FNM_PATHNAME)
|
159
|
+
|
160
|
+
info = BFS::FileInfo.new(path: path, size: size.to_i, mtime: Time.at(epoch.to_i), mode: BFS.norm_mode(mode))
|
161
|
+
yield info
|
162
|
+
else
|
163
|
+
path = trim_prefix(norm_path(line))
|
164
|
+
yield path if File.fnmatch?(pattern, path, File::FNM_PATHNAME)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
143
170
|
def mkdir_p(path)
|
144
|
-
sh!
|
171
|
+
sh! %(mkdir -p #{Shellwords.escape(path)})
|
145
172
|
end
|
146
173
|
|
147
|
-
def sh!(
|
174
|
+
def sh!(command) # rubocop:disable Metrics/MethodLength
|
148
175
|
stdout = ''
|
149
176
|
stderr = nil
|
150
177
|
status = 0
|
151
|
-
cmdstr = cmd.map {|x| Shellwords.escape(x) }.join(' ')
|
152
178
|
|
153
179
|
@client.session.open_channel do |ch|
|
154
|
-
ch.exec(
|
180
|
+
ch.exec(command) do |_, _success|
|
155
181
|
ch.on_data do |_, data|
|
182
|
+
stdout << data
|
183
|
+
|
156
184
|
if block_given?
|
157
|
-
|
158
|
-
|
159
|
-
stdout += data
|
185
|
+
pos = stdout.rindex("\n")
|
186
|
+
yield stdout.slice!(0..pos) if pos
|
160
187
|
end
|
161
188
|
end
|
162
189
|
ch.on_extended_data do |_, _, data|
|
@@ -167,8 +194,14 @@ module BFS
|
|
167
194
|
end
|
168
195
|
end
|
169
196
|
end
|
197
|
+
|
198
|
+
if block_given? && stdout.length.positive?
|
199
|
+
yield stdout
|
200
|
+
stdout.clear
|
201
|
+
end
|
202
|
+
|
170
203
|
@client.session.loop
|
171
|
-
raise CommandError.new(
|
204
|
+
raise CommandError.new(command, status, stderr) unless status.zero?
|
172
205
|
|
173
206
|
stdout
|
174
207
|
end
|
data/spec/bfs/bucket/scp_spec.rb
CHANGED
@@ -1,23 +1,25 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
sandbox = { host: '127.0.0.1', opts: { port: 7022, user: 'root', password: 'root' } }.freeze
|
4
|
-
|
5
3
|
RSpec.describe BFS::Bucket::SCP, scp: true do
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
subject { described_class.new hostname, **conn_opts }
|
5
|
+
|
6
|
+
let(:hostname) { '127.0.0.1' }
|
7
|
+
let(:conn_opts) { { port: 7022, user: 'root', password: 'root', prefix: prefix } }
|
8
|
+
let(:prefix) { SecureRandom.uuid }
|
9
|
+
|
10
|
+
after { subject.close }
|
9
11
|
|
12
|
+
context 'with absolute path' do
|
10
13
|
it_behaves_like 'a bucket', content_type: false, metadata: false
|
11
14
|
end
|
12
15
|
|
13
|
-
context 'relative' do
|
14
|
-
|
15
|
-
after { subject.close }
|
16
|
+
context 'with relative path' do
|
17
|
+
let(:prefix) { "~/#{SecureRandom.uuid}" }
|
16
18
|
|
17
19
|
it_behaves_like 'a bucket', content_type: false, metadata: false
|
18
20
|
end
|
19
21
|
|
20
|
-
it '
|
22
|
+
it 'resolves from URL' do
|
21
23
|
bucket = BFS.resolve('scp://root:root@127.0.0.1:7022')
|
22
24
|
expect(bucket).to be_instance_of(described_class)
|
23
25
|
expect(bucket.instance_variable_get(:@prefix)).to be_nil
|
@@ -29,7 +31,7 @@ RSpec.describe BFS::Bucket::SCP, scp: true do
|
|
29
31
|
bucket.close
|
30
32
|
end
|
31
33
|
|
32
|
-
it '
|
34
|
+
it 'handles absolute and relative paths' do
|
33
35
|
abs = BFS::Blob.new("scp://root:root@127.0.0.1:7022/#{SecureRandom.uuid}/file.txt")
|
34
36
|
abs.create {|w| w.write 'absolute' }
|
35
37
|
|
@@ -43,7 +45,7 @@ RSpec.describe BFS::Bucket::SCP, scp: true do
|
|
43
45
|
rel.close
|
44
46
|
end
|
45
47
|
|
46
|
-
it '
|
48
|
+
it 'supports custom perms' do
|
47
49
|
blob = BFS::Blob.new("scp://root:root@127.0.0.1:7022/#{SecureRandom.uuid}/file.txt")
|
48
50
|
blob.create(perm: 0o666) {|w| w.write 'foo' }
|
49
51
|
expect(blob.info.mode).to eq(0o666)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bfs-scp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitrij Denissenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bfs
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.8.3
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.8.3
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: net-scp
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
requirements: []
|
70
|
-
rubygems_version: 3.
|
70
|
+
rubygems_version: 3.2.15
|
71
71
|
signing_key:
|
72
72
|
specification_version: 4
|
73
73
|
summary: SCP/SSH adapter for bfs
|