bfs-scp 0.7.5 → 0.8.3

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: ce2b40891ff68887074207496ca807a6565c68d8d10ab4c442d0a8584a4137b8
4
- data.tar.gz: c7c2fa83b17402d00f8a2b80107078266f9e92ab8225f2e0047cdfd1412509a1
3
+ metadata.gz: d524b38b123694cf69ceb9b14ed758047564190ef3dba78e2eccc191970f0e89
4
+ data.tar.gz: 8e805bf4b7f688334333a5afb4fdff89c1c78fa734812e82e1d8fe3630a45ccd
5
5
  SHA512:
6
- metadata.gz: 1f69d3f9ed84f8dcd6be21633abe18ec98eed989ad71c5dfcf3134af9cd3e057ea0768a26bd402d55a3fec82616f26ad257f10cdb45d4d4c8773fc0c53a885cf
7
- data.tar.gz: 5b53c05aec603396e18ac17276664d48540c675996a0238016e10d66ffdcee52e6e47069b67d464b40193a0075961fc69fab76861b766dc0c05b0e98ca7ccc21
6
+ metadata.gz: e3956f06a9b2f00fb526f2768cb69b767372dab35adcb2b889a08bf440a1e43f462676a72927712e7e81fe1ddebf8a49687eb3b1ffe56cd8edd96c764f76e485
7
+ data.tar.gz: 424781ca80c8e6302511abc854e850db438408e54dc7af3d5eea5acf12bbc8aff99722be2f633588b271613fc8b6892f1d7ab739e1d8c8e1165a42d2c340eca8
@@ -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,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
- context 'absolute' do
7
- subject { described_class.new sandbox[:host], **sandbox[:opts].merge(prefix: SecureRandom.uuid) }
8
- after { subject.close }
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
- subject { described_class.new sandbox[:host], **sandbox[:opts].merge(prefix: "~/#{SecureRandom.uuid}") }
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 'should resolve from URL' do
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 'should handle absolute and relative paths' do
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 'should support custom perms' do
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.7.5
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: 2020-11-02 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.5
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.7.5
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.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