fun_sftp 0.0.9 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +16 -2
- data/fun_sftp.gemspec +1 -0
- data/lib/fun_sftp.rb +57 -63
- data/lib/fun_sftp/version.rb +1 -1
- data/spec/fun_sftp/sftp_client_spec.rb +75 -39
- metadata +29 -23
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 67b220be2614c7b34c153b584f02238f0174b74f
|
4
|
+
data.tar.gz: 22115d2401251baea5304935624f743d9916c245
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8f888a31d041721867705096b1854a40eb3927a000bf0e7f4581628ae314762b18dd220790960f4723c9a20b4538f294684006554c64a2c7a5842c251d014f20
|
7
|
+
data.tar.gz: 99611e5cb32b7f67c38136418eef4100e31a37919092f1ae5dd4e24b05ab51124915987ee937f1a7ed5514486294da93042a1252844576d244eb01925e205966
|
data/README.md
CHANGED
@@ -50,7 +50,7 @@ If you need to start from scratch then reset to the base path:
|
|
50
50
|
|
51
51
|
```ruby
|
52
52
|
conn.reset_path!
|
53
|
-
# => "Path Reset
|
53
|
+
# => "Path Reset!"
|
54
54
|
```
|
55
55
|
|
56
56
|
Now, you can upload your file:
|
@@ -86,6 +86,20 @@ conn.read("path/to/file_name.txt")
|
|
86
86
|
# => Hello World!
|
87
87
|
```
|
88
88
|
|
89
|
+
It is also possible to read the attributes size, access time and modified time.
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
conn.size("path/to/file_name.txt")
|
93
|
+
# => 1413455562
|
94
|
+
# works also for directories
|
95
|
+
|
96
|
+
conn.atime("path/to/file_name.txt")
|
97
|
+
# => 2014-10-16 12:32:42 +0200
|
98
|
+
|
99
|
+
conn.mtime("path/to/file_name.txt")
|
100
|
+
#=> 2014-10-16 12:32:42 +0200
|
101
|
+
```
|
102
|
+
|
89
103
|
When investigating items on the remote host, these commands can be handy:
|
90
104
|
|
91
105
|
```ruby
|
@@ -172,7 +186,7 @@ Contribute
|
|
172
186
|
License
|
173
187
|
-------
|
174
188
|
|
175
|
-
Copyright (c)
|
189
|
+
Copyright (c) 2014 George Diaz
|
176
190
|
|
177
191
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
178
192
|
|
data/fun_sftp.gemspec
CHANGED
data/lib/fun_sftp.rb
CHANGED
@@ -13,134 +13,128 @@ $VERBOSE = orig_verbose
|
|
13
13
|
# Reference: http://net-ssh.rubyforge.org/sftp/v2/api/
|
14
14
|
module FunSftp
|
15
15
|
class SFTPClient
|
16
|
-
|
16
|
+
|
17
|
+
attr_accessor :source
|
18
|
+
|
19
|
+
attr_reader :server, :user, :password, :client
|
20
|
+
|
21
|
+
alias_method :pwd, :source
|
17
22
|
|
18
23
|
def initialize(server, user, password)
|
19
24
|
@server, @user, @password = server, user, password
|
20
|
-
|
25
|
+
self.source = '.'
|
21
26
|
@client = setup_login
|
22
27
|
end
|
23
28
|
|
24
|
-
def source=(path)
|
25
|
-
@source = clean_path(path)
|
26
|
-
end
|
27
|
-
|
28
29
|
def setup_login
|
29
|
-
Net::SFTP.start(
|
30
|
+
Net::SFTP.start(server, user, password: password)
|
30
31
|
end
|
31
32
|
|
32
|
-
def upload!(
|
33
|
+
def upload!(src, target) #send to remote
|
33
34
|
#target example: 'some_directory/some_name.txt'
|
34
|
-
opts = {:
|
35
|
-
converted_target =
|
35
|
+
opts = { progress: UploadCallbacks.new, recursive: true }
|
36
|
+
converted_target = clean_path(target)
|
36
37
|
opts.delete(:progress) unless FunSftp.loggable?
|
37
|
-
opts.delete(:recursive) unless has_directory?(
|
38
|
-
|
38
|
+
opts.delete(:recursive) unless has_directory?(target)
|
39
|
+
client.upload!(src, converted_target, opts)
|
39
40
|
end
|
40
41
|
|
41
|
-
def download!(target,
|
42
|
-
opts = {:
|
43
|
-
converted_target =
|
42
|
+
def download!(target, src) #fetch locally from remote
|
43
|
+
opts = { progress: DownloadCallbacks.new, recursive: true}
|
44
|
+
converted_target = clean_path(target)
|
44
45
|
opts.delete(:progress) unless FunSftp.loggable?
|
45
|
-
opts.delete(:recursive) unless has_directory?(
|
46
|
-
|
46
|
+
opts.delete(:recursive) unless has_directory?(target)
|
47
|
+
client.download!(converted_target, src, opts)
|
47
48
|
end
|
48
49
|
|
49
50
|
def read(path) #read a file
|
50
|
-
file =
|
51
|
+
file = client.file.open(clean_path(path))
|
51
52
|
while !file.eof?
|
52
53
|
puts file.gets
|
53
54
|
end
|
54
55
|
end
|
55
56
|
|
56
|
-
def
|
57
|
-
|
57
|
+
def size(path) #returns the size of a file. ex: => 1413455562
|
58
|
+
client.file.open(clean_path(path)).stat.size
|
59
|
+
end
|
60
|
+
|
61
|
+
def atime(path) #returns the atime (access time) of a file. ex: => 2014-10-16 12:32:42 +0200
|
62
|
+
Time.at(client.file.open(clean_path(path)).stat.atime)
|
63
|
+
end
|
64
|
+
|
65
|
+
def mtime(path) #returns the mtime (modified time) of a file. ex: => 2014-10-16 12:32:42 +0200
|
66
|
+
Time.at(client.file.open(clean_path(path)).stat.mtime)
|
67
|
+
end
|
68
|
+
|
69
|
+
def glob(path, pattern='**/*') # ex: ('some_directory', '**/*.rb')
|
70
|
+
client.dir.glob(clean_path(path), pattern).collect(&:name)
|
58
71
|
end
|
72
|
+
alias_method :items_in, :glob
|
59
73
|
|
60
74
|
def entries(dir, show_dot_files = false) #array of directory entries not caring for '.' files
|
61
|
-
entries_arr =
|
75
|
+
entries_arr = client.dir.entries(clean_path(dir)).collect(&:name)
|
62
76
|
entries_arr.reject!{|a| a.match(/^\..*$/)} unless show_dot_files
|
63
77
|
entries_arr
|
64
78
|
end
|
65
79
|
|
66
|
-
def has_directory?(dir)
|
80
|
+
def has_directory?(dir)
|
67
81
|
begin
|
68
|
-
true if entries(dir)
|
82
|
+
true if client.dir.entries(clean_path(dir)).any?
|
69
83
|
rescue Net::SFTP::StatusException => e
|
70
84
|
false
|
71
85
|
end
|
72
86
|
end
|
73
87
|
|
74
|
-
def print_directory_items(dir) #printout of directory's items
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
def items_in(root_dir) #array of *all* directories & files inside provided root directory
|
79
|
-
glob(root_dir, '**/*').sort
|
88
|
+
def print_directory_items(dir='.') #printout of directory's items
|
89
|
+
client.dir.foreach(clean_path(dir)) { |file| puts "#{file.name}" }
|
80
90
|
end
|
81
|
-
|
82
|
-
#################################
|
83
|
-
# Some Handy File Util Methods #
|
84
|
-
#################################
|
91
|
+
alias_method :ll, :print_directory_items
|
85
92
|
|
86
93
|
def mkdir!(path) #make directory
|
87
|
-
|
94
|
+
client.mkdir!(clean_path(path))
|
88
95
|
end
|
89
96
|
|
90
97
|
def rm(path) #remove a file
|
91
|
-
|
98
|
+
client.remove!(clean_path(path))
|
92
99
|
end
|
93
100
|
|
94
101
|
def rmdir!(path) #remove directory
|
95
|
-
|
102
|
+
client.rmdir!(clean_path(path))
|
96
103
|
end
|
97
104
|
|
98
105
|
def rename(name, new_name) #rename a file
|
99
|
-
previous, renamed =
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
def ll
|
104
|
-
print_directory_items('.')
|
106
|
+
previous, renamed = clean_path(name), clean_path(new_name)
|
107
|
+
client.rename!(previous, renamed)
|
105
108
|
end
|
106
109
|
|
107
110
|
def chdir(path)
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
+
clean_path = clean_path(path)
|
112
|
+
if has_directory? path
|
113
|
+
self.source = clean_path
|
114
|
+
"Current Path change to => #{source}"
|
111
115
|
else
|
112
|
-
|
116
|
+
"Sorry Path => #{path} not found"
|
113
117
|
end
|
114
118
|
end
|
115
119
|
|
116
|
-
def pwd
|
117
|
-
@source
|
118
|
-
end
|
119
|
-
|
120
120
|
def reset_path!
|
121
|
-
|
122
|
-
"Path Reset
|
121
|
+
self.source = '.'
|
122
|
+
"Path Reset!"
|
123
123
|
end
|
124
124
|
|
125
125
|
private
|
126
126
|
|
127
127
|
def join_to_pwd(path)
|
128
|
-
File.join(
|
128
|
+
File.join(source, path)
|
129
129
|
end
|
130
130
|
|
131
131
|
def clean_path(path)
|
132
|
-
|
133
|
-
|
134
|
-
end
|
135
|
-
|
136
|
-
def change_directory_check(converted_path, entered_path)
|
137
|
-
if has_directory? converted_path
|
138
|
-
@source = converted_path
|
139
|
-
"Current Path changed to => #{@source}"
|
132
|
+
if path.start_with? '~'
|
133
|
+
path.sub(/~/, '.')
|
140
134
|
else
|
141
|
-
|
135
|
+
Pathname(join_to_pwd(path)).cleanpath.to_path
|
142
136
|
end
|
143
137
|
end
|
144
138
|
|
145
139
|
end
|
146
|
-
end
|
140
|
+
end
|
data/lib/fun_sftp/version.rb
CHANGED
@@ -3,67 +3,103 @@ require 'spec_helper'
|
|
3
3
|
module FunSftp
|
4
4
|
describe 'sftp client' do
|
5
5
|
|
6
|
-
let(:sftp_mock) {double('sftp')}
|
6
|
+
let(:sftp_mock) { double('sftp') }
|
7
7
|
|
8
8
|
before do
|
9
|
-
Net::SFTP.
|
9
|
+
allow(Net::SFTP).to receive(:start).and_return(sftp_mock)
|
10
10
|
end
|
11
11
|
|
12
12
|
context 'initialization' do
|
13
13
|
it 'should initialize with creds' do
|
14
14
|
expect(SFTPClient).to receive(:new).with('localhost', 'user1', 'pass')
|
15
|
-
|
15
|
+
SFTPClient.new('localhost', 'user1', 'pass')
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
|
20
|
-
let(:
|
21
|
-
let(:
|
22
|
-
let(:
|
19
|
+
context 'file utilities' do
|
20
|
+
let(:sftp_cli) { SFTPClient.new('localhost', 'user1', 'pass') }
|
21
|
+
let(:test_file) { File.expand_path('../../support/test1.txt', __FILE__) }
|
22
|
+
let(:file_1) { double('sftp_dir', name: '.') }
|
23
|
+
let(:dir_1) { double('sftp_dir', name: 'import_docs') }
|
24
|
+
let(:dir_2) { double('sftp_dir', name: 'training_docs') }
|
23
25
|
|
24
|
-
|
25
|
-
sftp_mock.
|
26
|
-
@sftp_cli = SFTPClient.new('localhost', 'user1', 'pass')
|
27
|
-
expect(@sftp_cli.entries('Desktop')).to eq([dir_1.name, dir_2.name])
|
26
|
+
before do
|
27
|
+
allow(sftp_mock).to receive_message_chain(:file, :open).with(anything()).and_return(File.open(test_file))
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
describe '#entries' do
|
31
|
+
before do
|
32
|
+
allow(sftp_mock).to receive_message_chain(:dir, :entries).with('Desktop').and_return([file_1, dir_1, dir_2])
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should return entries without prepended '.' " do
|
36
|
+
expect(sftp_cli.entries('Desktop')).to eq([dir_1.name, dir_2.name])
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should return with all files including '.' " do
|
40
|
+
expect(sftp_cli.entries('Desktop', true)).to eq([file_1.name, dir_1.name, dir_2.name])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#read' do
|
45
|
+
it 'should read both lines from test file' do
|
46
|
+
expect(sftp_cli).to receive(:puts).twice
|
47
|
+
sftp_cli.read(test_file)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#size' do
|
52
|
+
it 'should get the size from test file' do
|
53
|
+
expect(sftp_cli.size(test_file)).to eq(File.size(test_file))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#atime' do
|
58
|
+
it 'should get the atime from test file' do
|
59
|
+
expect(sftp_cli.atime(test_file)).to eq(File.atime(test_file))
|
60
|
+
end
|
34
61
|
end
|
35
62
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
expect(@sftp_cli).to receive(:puts).twice
|
41
|
-
@sftp_cli.read(file)
|
63
|
+
describe '#mtime' do
|
64
|
+
it 'should get the mtime from test file' do
|
65
|
+
expect(sftp_cli.mtime(test_file)).to eq(File.mtime(test_file))
|
66
|
+
end
|
42
67
|
end
|
43
68
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
69
|
+
describe '#has_directory?' do
|
70
|
+
it 'should return false for directory not found' do
|
71
|
+
sftp_response = Object.new
|
72
|
+
def sftp_response.code; code = 2 end
|
73
|
+
def sftp_response.message; message = 'no such file' end
|
74
|
+
allow(sftp_mock).to receive_message_chain(:dir, :entries, :any?).and_raise(Net::SFTP::StatusException.new(sftp_response))
|
75
|
+
expect(sftp_cli.has_directory?('bogus_directory')).to eql(false)
|
76
|
+
end
|
51
77
|
end
|
52
78
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
79
|
+
describe '#chdir' do
|
80
|
+
before do
|
81
|
+
allow(sftp_cli).to receive(:has_directory?).with(anything()).and_return(true)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should change directory source path' do
|
85
|
+
sftp_cli.chdir('projects')
|
86
|
+
expect(sftp_cli.source).to eq('projects')
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should sub tilda for period in path' do
|
90
|
+
sftp_cli.chdir('~/some_dir/working_dir')
|
91
|
+
expect(sftp_cli.source).to eq('./some_dir/working_dir')
|
92
|
+
end
|
58
93
|
end
|
59
94
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
95
|
+
describe '#reset_path!' do
|
96
|
+
it 'resets source' do
|
97
|
+
sftp_cli.source = 'some_dir/one'
|
98
|
+
sftp_cli.reset_path!
|
99
|
+
expect(sftp_cli.source).to eq('.')
|
100
|
+
end
|
65
101
|
end
|
66
102
|
end
|
67
103
|
|
68
104
|
end
|
69
|
-
end
|
105
|
+
end
|
metadata
CHANGED
@@ -1,62 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fun_sftp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- George Diaz
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-11-02 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: net-sftp
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rspec
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: pry
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - ">="
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
60
67
|
- !ruby/object:Gem::Version
|
61
68
|
version: '0'
|
62
69
|
description: Wrapper for Ruby's Net::SFTP library which makes SFTP easy! See Documentation
|
@@ -67,8 +74,8 @@ executables: []
|
|
67
74
|
extensions: []
|
68
75
|
extra_rdoc_files: []
|
69
76
|
files:
|
70
|
-
- .gitignore
|
71
|
-
- .rspec
|
77
|
+
- ".gitignore"
|
78
|
+
- ".rspec"
|
72
79
|
- Gemfile
|
73
80
|
- README.md
|
74
81
|
- Rakefile
|
@@ -83,27 +90,26 @@ files:
|
|
83
90
|
- spec/support/test1.txt
|
84
91
|
homepage: https://rubygems.org/gems/fun_sftp
|
85
92
|
licenses: []
|
93
|
+
metadata: {}
|
86
94
|
post_install_message:
|
87
95
|
rdoc_options: []
|
88
96
|
require_paths:
|
89
97
|
- lib
|
90
98
|
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
-
none: false
|
92
99
|
requirements:
|
93
|
-
- -
|
100
|
+
- - ">="
|
94
101
|
- !ruby/object:Gem::Version
|
95
102
|
version: '0'
|
96
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
104
|
requirements:
|
99
|
-
- -
|
105
|
+
- - ">="
|
100
106
|
- !ruby/object:Gem::Version
|
101
107
|
version: '0'
|
102
108
|
requirements: []
|
103
109
|
rubyforge_project: fun_sftp
|
104
|
-
rubygems_version:
|
110
|
+
rubygems_version: 2.2.2
|
105
111
|
signing_key:
|
106
|
-
specification_version:
|
112
|
+
specification_version: 4
|
107
113
|
summary: FunSFTP for secure file transfers
|
108
114
|
test_files:
|
109
115
|
- spec/fun_sftp/sftp_client_spec.rb
|