xftp 0.1.0.pre.alpha
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 +7 -0
- data/.gitignore +9 -0
- data/.overcommit.yml +42 -0
- data/.reek +3 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +19 -0
- data/README.md +49 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/rspec +16 -0
- data/bin/setup +7 -0
- data/lib/configuration.rb +61 -0
- data/lib/initializers/i18n.rb +10 -0
- data/lib/xftp.rb +67 -0
- data/lib/xftp/dsl/block_evaluator.rb +18 -0
- data/lib/xftp/errors.rb +20 -0
- data/lib/xftp/locale/en.yml +5 -0
- data/lib/xftp/locale/ru.yml +5 -0
- data/lib/xftp/operations/ftp/glob.rb +23 -0
- data/lib/xftp/session/base.rb +30 -0
- data/lib/xftp/session/ftp.rb +54 -0
- data/lib/xftp/session/sftp.rb +97 -0
- data/lib/xftp/validator/settings.rb +25 -0
- data/lib/xftp/version.rb +12 -0
- data/xftp.gemspec +35 -0
- metadata +214 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4fadf37a688351959fd702257a6e2efb8e9600a8
|
4
|
+
data.tar.gz: 0459bf1922cabbcc204bba768700a9148f483a3a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3a758097ffcd936285221424b9bedf7c5c4906b97e3ad2f90073a7ad20963990053ab1b3065f2e8dd30d6ded38f0c94c96793cfcbb12e806ac963dae5904226f
|
7
|
+
data.tar.gz: e48ed2864845c10837de4ae37999b765cee5ab9957eca157888267616bab73e1e9cec2ea77189d03e53b5026d79034c0fcc41824d5103f81ccfc0c95f27ddc80
|
data/.gitignore
ADDED
data/.overcommit.yml
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# Use this file to configure the Overcommit hooks you wish to use. This will
|
2
|
+
# extend the default configuration defined in:
|
3
|
+
# https://github.com/brigade/overcommit/blob/master/config/default.yml
|
4
|
+
#
|
5
|
+
# At the topmost level of this YAML file is a key representing type of hook
|
6
|
+
# being run (e.g. pre-commit, commit-msg, etc.). Within each type you can
|
7
|
+
# customize each hook, such as whether to only run it on certain files (via
|
8
|
+
# `include`), whether to only display output if it fails (via `quiet`), etc.
|
9
|
+
#
|
10
|
+
# For a complete list of hooks, see:
|
11
|
+
# https://github.com/brigade/overcommit/tree/master/lib/overcommit/hook
|
12
|
+
#
|
13
|
+
# For a complete list of options that you can use to customize hooks, see:
|
14
|
+
# https://github.com/brigade/overcommit#configuration
|
15
|
+
#
|
16
|
+
# Uncomment the following lines to make the configuration take effect.
|
17
|
+
|
18
|
+
CommitMsg:
|
19
|
+
HardTabs:
|
20
|
+
enabled: true
|
21
|
+
|
22
|
+
PreCommit:
|
23
|
+
Rubocop:
|
24
|
+
enabled: true
|
25
|
+
on_warn: fail
|
26
|
+
HardTabs:
|
27
|
+
enabled: true
|
28
|
+
Reek:
|
29
|
+
enabled: true
|
30
|
+
LocalPathsInGemfile:
|
31
|
+
enabled: true
|
32
|
+
TrailingWhitespace:
|
33
|
+
enabled: true
|
34
|
+
BundleCheck:
|
35
|
+
enabled: true
|
36
|
+
|
37
|
+
PostCheckout:
|
38
|
+
SubmoduleStatus:
|
39
|
+
enabled: true
|
40
|
+
GitGuilt:
|
41
|
+
enabled: true
|
42
|
+
|
data/.reek
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.5
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
group :development, :test do
|
6
|
+
gem 'pry-byebug'
|
7
|
+
end
|
8
|
+
|
9
|
+
group :development do
|
10
|
+
gem 'reek', require: false
|
11
|
+
gem 'brakeman', require: false
|
12
|
+
gem 'rubocop', require: false
|
13
|
+
gem 'overcommit'
|
14
|
+
end
|
15
|
+
|
16
|
+
group :test do
|
17
|
+
gem 'mutant'
|
18
|
+
gem 'mutant-rspec'
|
19
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# xftp
|
2
|
+
|
3
|
+
Unified interface for ftp/sftp.
|
4
|
+
Protocol is selected by url scheme.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
gem 'xftp'
|
10
|
+
```
|
11
|
+
|
12
|
+
or
|
13
|
+
|
14
|
+
```
|
15
|
+
$ gem install xftp
|
16
|
+
```
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
XFTP.start('ftps://hostname', login: 'login', password: 'pass') do |x|
|
22
|
+
x.chdir 'remote-src-path'
|
23
|
+
x.mkdir 'new-remote-dir'
|
24
|
+
x.rmdir 'dir-to-remove'
|
25
|
+
|
26
|
+
x.glob '**/*.{xls,xlsx}' do |io|
|
27
|
+
# process entry
|
28
|
+
end
|
29
|
+
|
30
|
+
x.download '**/*.{xls,xlsx}', to: 'local-dst-path' do |file|
|
31
|
+
# process file
|
32
|
+
x.move file, to: 'remote-archive-path'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
## Development
|
38
|
+
|
39
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
40
|
+
|
41
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
42
|
+
|
43
|
+
## Contributing
|
44
|
+
|
45
|
+
1. Fork it ( https://github.com/[my-github-username]/xftp/fork )
|
46
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
47
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
48
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
49
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "xftp"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/rspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This file was generated by Bundler.
|
4
|
+
#
|
5
|
+
# The application 'rspec' is installed as part of a gem, and
|
6
|
+
# this file is here to facilitate running it.
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'pathname'
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
11
|
+
Pathname.new(__FILE__).realpath)
|
12
|
+
|
13
|
+
require 'rubygems'
|
14
|
+
require 'bundler/setup'
|
15
|
+
|
16
|
+
load Gem.bin_path('rspec-core', 'rspec')
|
data/bin/setup
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'net/ftp'
|
2
|
+
require 'net/ssh'
|
3
|
+
|
4
|
+
require 'active_support/configurable'
|
5
|
+
|
6
|
+
module XFTP
|
7
|
+
# Provides a way to store and retrive configuration options
|
8
|
+
class Configuration
|
9
|
+
include ActiveSupport::Configurable
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# HACK: This is required to smooth a future transition to activesupport 4.x
|
13
|
+
# Since 3-2's config_accessor doesn't take a block or provide an option to set the default value of a config.
|
14
|
+
alias_method :old_config_accessor, :config_accessor
|
15
|
+
|
16
|
+
def config_accessor(*names)
|
17
|
+
old_config_accessor(*names)
|
18
|
+
return unless block_given?
|
19
|
+
|
20
|
+
names.each do |name|
|
21
|
+
send("#{name}=", yield)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
config_accessor :logging do
|
27
|
+
default_logger = lambda do
|
28
|
+
logger = Logger.new(STDERR)
|
29
|
+
logger.level = Logger::ERROR
|
30
|
+
end
|
31
|
+
|
32
|
+
rails_logger = -> { Rails.logger || default_logger.call }
|
33
|
+
logger = defined?(Rails) ? rails_logger.call : default_logger.call
|
34
|
+
|
35
|
+
{
|
36
|
+
logger: logger,
|
37
|
+
verbose: false,
|
38
|
+
colorize: true
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
config_accessor :ftp do
|
43
|
+
{
|
44
|
+
binary: true,
|
45
|
+
passive: true,
|
46
|
+
debug_mode: false,
|
47
|
+
open_timeout: nil,
|
48
|
+
resume: false
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
config_accessor :ssh do
|
53
|
+
{
|
54
|
+
keepalive: true,
|
55
|
+
keepalive_interval: 30,
|
56
|
+
forward_agent: true,
|
57
|
+
verbose: :error
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'i18n'
|
2
|
+
|
3
|
+
locale_paths = File.join(File.dirname(__FILE__), '..', 'xftp', 'locale', '*.yml')
|
4
|
+
|
5
|
+
Dir[locale_paths].each { |path| I18n.load_path << path }
|
6
|
+
I18n.backend.load_translations unless defined?(Rails)
|
7
|
+
|
8
|
+
I18n.config.enforce_available_locales = true
|
9
|
+
I18n.default_locale = :en
|
10
|
+
I18n.available_locales = [:en, :ru]
|
data/lib/xftp.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'active_support/core_ext/object'
|
2
|
+
require 'active_support/core_ext/hash'
|
3
|
+
|
4
|
+
require 'configuration'
|
5
|
+
require 'xftp/version'
|
6
|
+
require 'xftp/errors'
|
7
|
+
require 'xftp/validator/settings'
|
8
|
+
require 'xftp/session/ftp'
|
9
|
+
require 'xftp/session/sftp'
|
10
|
+
|
11
|
+
require_relative 'initializers/i18n'
|
12
|
+
|
13
|
+
# The XFTP entry point (facade)
|
14
|
+
module XFTP
|
15
|
+
include Errors
|
16
|
+
|
17
|
+
SCHEME_ADAPTERS = {
|
18
|
+
ftp: XFTP::Session::FTP,
|
19
|
+
ftps: XFTP::Session::SFTP
|
20
|
+
}
|
21
|
+
|
22
|
+
# Config accessor
|
23
|
+
def self.config
|
24
|
+
@configuration ||= Configuration.new
|
25
|
+
end
|
26
|
+
|
27
|
+
# For a block { |config| ... }
|
28
|
+
# @yield the (see #config)
|
29
|
+
def self.configure
|
30
|
+
yield config
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.validator
|
34
|
+
@validator ||= Validator::Settings.new
|
35
|
+
end
|
36
|
+
|
37
|
+
# Initiates a new session
|
38
|
+
#
|
39
|
+
# @param [String] :url the remote host url
|
40
|
+
# @param [Hash] settings the connection settings
|
41
|
+
# @option settings [Hash<Symbol, String>] :credentials the authentication credentials
|
42
|
+
#
|
43
|
+
# @raise [URI::InvalidURIError] if url given is not a correct URI
|
44
|
+
# @raise [XFTP::MissingArgument] if some of the required settings are missing
|
45
|
+
# @raise [XFTP::NotSupportedProtocol] if protocol detected by schema is not supported
|
46
|
+
#
|
47
|
+
# @see Net::SSH
|
48
|
+
# @see Net::FTP
|
49
|
+
#
|
50
|
+
# @see XFTP::Validator::Settings
|
51
|
+
def self.start(url, settings = {}, &block)
|
52
|
+
uri = URI.parse(url)
|
53
|
+
validator.call!(uri, settings)
|
54
|
+
klass = adapter_class(uri.scheme)
|
55
|
+
session = klass.new(uri, settings.deep_dup)
|
56
|
+
session.start(&block)
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# Detects a session adapter class
|
62
|
+
# @param [String, Symbol] scheme the uri scheme
|
63
|
+
# @return [Class] session adapter class
|
64
|
+
def self.adapter_class(scheme)
|
65
|
+
SCHEME_ADAPTERS[scheme.to_sym] || not_supported_protocol!(scheme)
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module XFTP
|
2
|
+
# Contains helper classes and modules to simplify building a DSL
|
3
|
+
module DSL
|
4
|
+
# Gives the target class an ability to expose both DSL design patterns.
|
5
|
+
# It yields self as a block argument if arity of the given block takes exactly 1 argument, otherwise
|
6
|
+
# it simply evaluates the given block of the target class instance (see BasicObject#instance_eval)
|
7
|
+
module BlockEvaluator
|
8
|
+
def evaluate(&callback)
|
9
|
+
return unless block_given?
|
10
|
+
if callback.arity == 1
|
11
|
+
yield self
|
12
|
+
else
|
13
|
+
instance_eval(&callback)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/xftp/errors.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module XFTP
|
2
|
+
# Raises when the given argument does not match required format
|
3
|
+
class InvalidArgument < ArgumentError; end
|
4
|
+
# Raises when required argument is missing or blank
|
5
|
+
class MissingArgument < ArgumentError; end
|
6
|
+
# Raise when the given protocol is not supported
|
7
|
+
class NotSupportedProtocol < ArgumentError; end
|
8
|
+
|
9
|
+
# Shortcut method to fail
|
10
|
+
# with a localized error message
|
11
|
+
module Errors
|
12
|
+
def missing_setting!(setting)
|
13
|
+
fail MissingArgument, I18n.t('errors.missing_setting', key: setting)
|
14
|
+
end
|
15
|
+
|
16
|
+
def not_supported_protocol!(protocol)
|
17
|
+
fail NotSupportedProtocol, I18n.t('errors.not_supported_protocol', protocol: protocol)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module XFTP
|
2
|
+
module Operations
|
3
|
+
module FTP
|
4
|
+
# @api private
|
5
|
+
class Glob
|
6
|
+
def initialize(ftp)
|
7
|
+
@ftp = ftp
|
8
|
+
end
|
9
|
+
|
10
|
+
# Expands pattern and returns the results
|
11
|
+
# as matches or as arguments given to the block
|
12
|
+
# @param [String] pattern the search pattern
|
13
|
+
# @param [Proc] callback
|
14
|
+
# :reek:UnusedParameters
|
15
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
16
|
+
def call(pattern, &callback)
|
17
|
+
fail NotImplementedError
|
18
|
+
end
|
19
|
+
# rubocop:enable Lint/UnusedMethodArgument
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'xftp/dsl/block_evaluator'
|
2
|
+
|
3
|
+
module XFTP
|
4
|
+
module Session
|
5
|
+
# @abstract Base class for xftp session adapters
|
6
|
+
# @api private
|
7
|
+
class Base
|
8
|
+
include DSL::BlockEvaluator
|
9
|
+
|
10
|
+
attr_reader :uri, :credentials, :settings
|
11
|
+
|
12
|
+
# Creates a session adapter instance
|
13
|
+
# @param [URI] uri the remote uri
|
14
|
+
# @param [Hash] settings the adapter connection settings
|
15
|
+
def initialize(uri, settings = {})
|
16
|
+
@uri = uri
|
17
|
+
@credentials = settings.delete(:credentials) || {}
|
18
|
+
@settings = settings
|
19
|
+
end
|
20
|
+
|
21
|
+
# Opens a new connection, evaluates the given block and closes the connection
|
22
|
+
# @param [Proc] callback the callback to operate on a connection session
|
23
|
+
def start(&callback)
|
24
|
+
open
|
25
|
+
evaluate(&callback)
|
26
|
+
close
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'active_support/core_ext/hash/deep_merge'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'net/ftp'
|
4
|
+
|
5
|
+
require 'xftp/session/base'
|
6
|
+
|
7
|
+
module XFTP
|
8
|
+
module Session
|
9
|
+
# FTP session adapter
|
10
|
+
# @api private
|
11
|
+
class FTP < Base
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
# Delegate methods which have the same method signature
|
15
|
+
# directly to Net::FTP session
|
16
|
+
def_delegators :@ftp, :chdir, :mkdir, :rmdir, :close
|
17
|
+
|
18
|
+
# Creates an FTP session adapter instance
|
19
|
+
# @param [URI] uri the remote uri
|
20
|
+
# @param [Hash] settings the adapter connection settings
|
21
|
+
def initialize(uri, settings = {})
|
22
|
+
super
|
23
|
+
|
24
|
+
@ftp = Net::FTP.new
|
25
|
+
@port = uri.port || settings.delete(:port) || Net::FTP::FTP_PORT
|
26
|
+
@credentials[:login] ||= 'anonymous'
|
27
|
+
|
28
|
+
options = XFTP.config.ftp.deep_merge(@settings)
|
29
|
+
options.each { |key, val| @ftp.public_send("#{key}=", val) }
|
30
|
+
end
|
31
|
+
|
32
|
+
# Renames (moves) a file on the server
|
33
|
+
# @param [String] from the path to move from
|
34
|
+
# @param [String] to the new path to move to
|
35
|
+
def move(from, to:)
|
36
|
+
@ftp.rename(from, to)
|
37
|
+
end
|
38
|
+
|
39
|
+
# @see XFTP::Operations::FTP::Glob
|
40
|
+
def glob(pattern, &callback)
|
41
|
+
Operations::Glob.new(@ftp).call(pattern, &callback)
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
# Opens a new FTP connection and
|
47
|
+
# authenticates on the remote server
|
48
|
+
def open
|
49
|
+
@ftp.connect(@uri.host, @port)
|
50
|
+
@ftp.login(@credentials[:login], @credentials[:password])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'net/ssh'
|
2
|
+
require 'net/sftp'
|
3
|
+
|
4
|
+
require 'xftp/session/base'
|
5
|
+
|
6
|
+
module XFTP
|
7
|
+
module Session
|
8
|
+
# SFTP session adapter
|
9
|
+
# @api private
|
10
|
+
class SFTP < Base
|
11
|
+
# Default flags for rename operation
|
12
|
+
RENAME_OPERATION_FLAGS = 0x0004
|
13
|
+
# Default flags for glob operation
|
14
|
+
GLOB_OPERATION_FLAGS = File::FNM_EXTGLOB
|
15
|
+
|
16
|
+
# Creates an SFTP session adapter instance
|
17
|
+
# @param [URI] uri the remote uri
|
18
|
+
# @param [Hash] settings the adapter connection settings
|
19
|
+
def initialize(uri, settings = {})
|
20
|
+
super
|
21
|
+
@path = Pathname '.'
|
22
|
+
@settings.merge!(password: @credentials[:password])
|
23
|
+
@options = XFTP.config.sftp.deep_merge(@settings)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Changes the current (remote) working directory
|
27
|
+
# @param [String] path the relative (remote) path
|
28
|
+
def chdir(path)
|
29
|
+
@path /= path
|
30
|
+
end
|
31
|
+
|
32
|
+
# Creates a remote directory
|
33
|
+
# @param [String] dirname the name of new directory
|
34
|
+
# relative to the current (remote) working directory
|
35
|
+
# @param [Hash] attrs the attributes of new directory
|
36
|
+
# supported by the the version of SFTP protocol in use
|
37
|
+
def mkdir(dirname, attrs = {})
|
38
|
+
@sftp.mkdir! pathname(dirname), attrs
|
39
|
+
end
|
40
|
+
|
41
|
+
# Removes the remote directory
|
42
|
+
# @param [String] dirname the name of directory to be removed
|
43
|
+
def rmdir(dirname)
|
44
|
+
@sftp.rmdir! pathname(dirname)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Renames (moves) a file on the server
|
48
|
+
# @param [String] from the path to move from
|
49
|
+
# @param [String] to the path to move to
|
50
|
+
def move(from, to:, flags: RENAME_OPERATION_FLAGS)
|
51
|
+
@sftp.rename(from, to, flags)
|
52
|
+
end
|
53
|
+
|
54
|
+
# For more info (see Dir#glob), it's almost of the same nature
|
55
|
+
# @param [String] pattern the search pattern relative
|
56
|
+
# the the current working directory
|
57
|
+
# @param [Integer] (see File.fnmatch) for the meaning of the flags parameter.
|
58
|
+
# Default value is `File::FNM_EXTGLOB`
|
59
|
+
def glob(pattern, flags: GLOB_OPERATION_FLAGS)
|
60
|
+
@sftp.dir.glob(@path.to_s, pattern, flags)
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
# Opens a new SFTP connection
|
66
|
+
def open
|
67
|
+
connect
|
68
|
+
rescue Object => anything
|
69
|
+
begin
|
70
|
+
@ssh.shutdown!
|
71
|
+
rescue ::Exception # rubocop:disable Lint/HandleExceptions, Lint/RescueException
|
72
|
+
# swallow exceptions that occur while trying to shutdown
|
73
|
+
end
|
74
|
+
|
75
|
+
raise anything
|
76
|
+
end
|
77
|
+
|
78
|
+
# Closes SFTP (SSH) connection
|
79
|
+
def close
|
80
|
+
@ssh.close
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def connect
|
86
|
+
@ssh = Net::SSH.start(@uri.host, @credentials[:login], @options)
|
87
|
+
@sftp = Net::SFTP::Session.new @ssh
|
88
|
+
@sftp.connect!
|
89
|
+
end
|
90
|
+
|
91
|
+
# @return [String] a path name relative to the current working directory
|
92
|
+
def pathname(relative)
|
93
|
+
(@path / relative).to_s
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module XFTP
|
2
|
+
module Validator
|
3
|
+
# Connection settings validator
|
4
|
+
# @api private
|
5
|
+
class Settings
|
6
|
+
include Errors
|
7
|
+
|
8
|
+
# Validates the given connection settings
|
9
|
+
# @param [URI] uri the remote uri
|
10
|
+
# @param [Hash] settings the session connection settings
|
11
|
+
# @raise [XFTP::MissingArgument] if some of the required settings are missing
|
12
|
+
def call!(uri, settings)
|
13
|
+
validate_credentials!(settings[:credentials]) if uri.scheme == 'ftps'
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def validate_credentials!(credentials)
|
19
|
+
missing_setting!(:credentials) unless credentials.present?
|
20
|
+
missing_setting!(:login) unless credentials[:login].present?
|
21
|
+
missing_setting!(:password) unless credentials[:password].present?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/xftp/version.rb
ADDED
data/xftp.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'xftp/version'
|
5
|
+
|
6
|
+
TEST_FILES = %r{^(test|spec|features)/}
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = 'xftp'
|
10
|
+
spec.version = XFTP::VERSION::STRING
|
11
|
+
spec.authors = ['Vasiliy Yorkin']
|
12
|
+
spec.email = ['vasiliy.yorkin@gmail.com']
|
13
|
+
|
14
|
+
spec.summary = 'Unified interface for ftp/sftp'
|
15
|
+
spec.description = spec.summary
|
16
|
+
spec.homepage = 'https://github.com/vyorkin/xftp'
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match TEST_FILES }
|
19
|
+
spec.bindir = 'bin'
|
20
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
spec.test_files = spec.files.grep(TEST_FILES)
|
22
|
+
spec.require_paths = ['lib']
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.8'
|
25
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
26
|
+
spec.add_development_dependency 'yard', '~> 0.8.7'
|
27
|
+
spec.add_development_dependency 'yard-rspec', '~> 0.1'
|
28
|
+
spec.add_development_dependency 'rspec', '~> 3.2.0'
|
29
|
+
spec.add_development_dependency 'simplecov', '~> 0.9.2'
|
30
|
+
spec.add_development_dependency 'fake_ftp', '~> 0.1.1'
|
31
|
+
|
32
|
+
spec.add_runtime_dependency 'i18n', '~> 0.6.0'
|
33
|
+
spec.add_runtime_dependency 'net-sftp', '~> 2.1.2'
|
34
|
+
spec.add_runtime_dependency 'activesupport', '~> 3.2.21'
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xftp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.pre.alpha
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Vasiliy Yorkin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.8.7
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.8.7
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: yard-rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 3.2.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 3.2.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.9.2
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.9.2
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: fake_ftp
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.1.1
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.1.1
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: i18n
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.6.0
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.6.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: net-sftp
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 2.1.2
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 2.1.2
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: activesupport
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 3.2.21
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 3.2.21
|
153
|
+
description: Unified interface for ftp/sftp
|
154
|
+
email:
|
155
|
+
- vasiliy.yorkin@gmail.com
|
156
|
+
executables:
|
157
|
+
- console
|
158
|
+
- rspec
|
159
|
+
- setup
|
160
|
+
extensions: []
|
161
|
+
extra_rdoc_files: []
|
162
|
+
files:
|
163
|
+
- ".gitignore"
|
164
|
+
- ".overcommit.yml"
|
165
|
+
- ".reek"
|
166
|
+
- ".rspec"
|
167
|
+
- ".rubocop.yml"
|
168
|
+
- ".ruby-version"
|
169
|
+
- ".travis.yml"
|
170
|
+
- Gemfile
|
171
|
+
- README.md
|
172
|
+
- Rakefile
|
173
|
+
- bin/console
|
174
|
+
- bin/rspec
|
175
|
+
- bin/setup
|
176
|
+
- lib/configuration.rb
|
177
|
+
- lib/initializers/i18n.rb
|
178
|
+
- lib/xftp.rb
|
179
|
+
- lib/xftp/dsl/block_evaluator.rb
|
180
|
+
- lib/xftp/errors.rb
|
181
|
+
- lib/xftp/locale/en.yml
|
182
|
+
- lib/xftp/locale/ru.yml
|
183
|
+
- lib/xftp/operations/ftp/glob.rb
|
184
|
+
- lib/xftp/session/base.rb
|
185
|
+
- lib/xftp/session/ftp.rb
|
186
|
+
- lib/xftp/session/sftp.rb
|
187
|
+
- lib/xftp/validator/settings.rb
|
188
|
+
- lib/xftp/version.rb
|
189
|
+
- xftp.gemspec
|
190
|
+
homepage: https://github.com/vyorkin/xftp
|
191
|
+
licenses: []
|
192
|
+
metadata: {}
|
193
|
+
post_install_message:
|
194
|
+
rdoc_options: []
|
195
|
+
require_paths:
|
196
|
+
- lib
|
197
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
203
|
+
requirements:
|
204
|
+
- - ">"
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: 1.3.1
|
207
|
+
requirements: []
|
208
|
+
rubyforge_project:
|
209
|
+
rubygems_version: 2.2.2
|
210
|
+
signing_key:
|
211
|
+
specification_version: 4
|
212
|
+
summary: Unified interface for ftp/sftp
|
213
|
+
test_files: []
|
214
|
+
has_rdoc:
|