bfs-scp 0.7.6 → 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6de04002b6c77e4844986f058b84ed6ec066ea0449a8046f14f5bb5d30c9451
4
- data.tar.gz: 8da046cce602ade820a2d3143918919db5f5d7d5f5af4f083e98a3bd81082fa1
3
+ metadata.gz: 764bb3ccf2dcd35ea53ffa7394d8943661fcb6ce6c17592ddfb5a912ded02df0
4
+ data.tar.gz: 184fc9c2e7cc5209822b395ac895e2df40bf238d9d5b2b324aba114809416a0f
5
5
  SHA512:
6
- metadata.gz: 18039611b8beffc15715cc13de3e1d9f36af8f71bd5a79ff2847289572d16d6793bd3a3d9ee90cce28623a6b40f1fad5894b4c64d1a131ea9cc8230d06bcf34b
7
- data.tar.gz: a6be1bb4418cc1e31c45a6e247879a0269d3f5832bb62dabf9b083658050eb05a20b429a030d8b36d4403f13cadfd239a9705037123dd08e536847ef22b61cb1
6
+ metadata.gz: dd816f10a701439f12b77b1a11429b154601fb8383748646a171d98428cbafb02f8d11a29ab1e9736f94b572a8b0d94e1441f2d3277b62624b7a5ced5006e71a
7
+ data.tar.gz: 49757704938ac5ca0dc66e0988486a96f697fe2be8ce242d35854c4eb43c19fb28fa4369ef537db535d3e10fc3d543cc75bc26f9b0ef5db17c291c54844fc1d4
@@ -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
- prefix = @prefix ? abs_path(@prefix) : '/'
46
- Enumerator.new do |y|
47
- sh! 'find', prefix, '-type', 'f' do |out|
48
- out.each_line do |line|
49
- path = trim_prefix(norm_path(line.strip))
50
- y << path if File.fnmatch?(pattern, path, File::FNM_PATHNAME)
51
- end
52
- end
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! 'stat', '-c', '%s;%Z;%a', full
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::TempWriter.new(path, encoding: encoding, perm: perm) do |temp_path|
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! 'rm', '-f', path
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! 'cp', '-a', '-f', full_src, full_dst
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! 'mv', '-f', full_src, full_dst
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! 'mkdir', '-p', path
171
+ sh! %(mkdir -p #{Shellwords.escape(path)})
145
172
  end
146
173
 
147
- def sh!(*cmd) # rubocop:disable Metrics/MethodLength
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(cmdstr) do |_, _success|
180
+ ch.exec(command) do |_, _success|
155
181
  ch.on_data do |_, data|
182
+ stdout << data
183
+
156
184
  if block_given?
157
- yield data
158
- else
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(cmdstr, status, stderr) unless status.zero?
204
+ raise CommandError.new(command, status, stderr) unless status.zero?
172
205
 
173
206
  stdout
174
207
  end
@@ -1,24 +1,25 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe BFS::Bucket::SCP, scp: true do
4
+ subject { described_class.new hostname, **conn_opts }
5
+
4
6
  let(:hostname) { '127.0.0.1' }
5
7
  let(:conn_opts) { { port: 7022, user: 'root', password: 'root', prefix: prefix } }
6
8
  let(:prefix) { SecureRandom.uuid }
7
9
 
8
- subject { described_class.new hostname, **conn_opts }
9
10
  after { subject.close }
10
11
 
11
- context 'absolute' do
12
+ context 'with absolute path' do
12
13
  it_behaves_like 'a bucket', content_type: false, metadata: false
13
14
  end
14
15
 
15
- context 'relative' do
16
+ context 'with relative path' do
16
17
  let(:prefix) { "~/#{SecureRandom.uuid}" }
17
18
 
18
19
  it_behaves_like 'a bucket', content_type: false, metadata: false
19
20
  end
20
21
 
21
- it 'should resolve from URL' do
22
+ it 'resolves from URL' do
22
23
  bucket = BFS.resolve('scp://root:root@127.0.0.1:7022')
23
24
  expect(bucket).to be_instance_of(described_class)
24
25
  expect(bucket.instance_variable_get(:@prefix)).to be_nil
@@ -30,7 +31,7 @@ RSpec.describe BFS::Bucket::SCP, scp: true do
30
31
  bucket.close
31
32
  end
32
33
 
33
- it 'should handle absolute and relative paths' do
34
+ it 'handles absolute and relative paths' do
34
35
  abs = BFS::Blob.new("scp://root:root@127.0.0.1:7022/#{SecureRandom.uuid}/file.txt")
35
36
  abs.create {|w| w.write 'absolute' }
36
37
 
@@ -44,7 +45,7 @@ RSpec.describe BFS::Bucket::SCP, scp: true do
44
45
  rel.close
45
46
  end
46
47
 
47
- it 'should support custom perms' do
48
+ it 'supports custom perms' do
48
49
  blob = BFS::Blob.new("scp://root:root@127.0.0.1:7022/#{SecureRandom.uuid}/file.txt")
49
50
  blob.create(perm: 0o666) {|w| w.write 'foo' }
50
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.7.6
4
+ version: 0.8.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitrij Denissenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-10 00:00:00.000000000 Z
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.7.6
19
+ version: 0.8.4
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.7.6
26
+ version: 0.8.4
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.1.2
70
+ rubygems_version: 3.2.15
71
71
  signing_key:
72
72
  specification_version: 4
73
73
  summary: SCP/SSH adapter for bfs