net-ftp-list 3.2.11 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +21 -0
- data/.gitignore +9 -0
- data/.rubocop.yml +17 -0
- data/Gemfile +1 -5
- data/Gemfile.lock +47 -51
- data/Rakefile +10 -42
- data/lib/net/ftp/list.rb +3 -4
- data/lib/net/ftp/list/entry.rb +33 -53
- data/lib/net/ftp/list/microsoft.rb +14 -16
- data/lib/net/ftp/list/netware.rb +8 -10
- data/lib/net/ftp/list/parser.rb +35 -18
- data/lib/net/ftp/list/rumpus.rb +9 -10
- data/lib/net/ftp/list/unix.rb +31 -38
- data/lib/net/ftp/list/unknown.rb +3 -6
- data/net-ftp-list.gemspec +15 -57
- data/test/test_net_ftp_list.rb +2 -3
- data/test/test_net_ftp_list_entry.rb +20 -21
- data/test/test_net_ftp_list_microsoft.rb +6 -7
- data/test/test_net_ftp_list_netware.rb +6 -8
- data/test/test_net_ftp_list_rumpus.rb +5 -6
- data/test/test_net_ftp_list_unix.rb +49 -62
- metadata +46 -12
- data/.ruby-version +0 -1
- data/VERSION.yml +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3664e5c75774117ae0ec40734948526a60d5f8b55a38629a9abe56e0d2599813
|
4
|
+
data.tar.gz: 26ebefa96b9b63150c4c63af7c7912c8346f9ae080066eac3d37a198264645a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cff6489e1af74de5c0c25b5b5461b2be0ce57f4cb52086d36f7876836db07cacd120e3e34143c63d0ea06ad7504092ff1702ff7c87513368468aee72ef2486ad
|
7
|
+
data.tar.gz: 655bee68bff7169c0ab47f6e9124c129e6339b953e635165cb7feebd82fa44a85b921d688b63b432ad0eab8c7c8a189107ab538f5ec4bfdca8df0ec22f1f3ff7
|
@@ -0,0 +1,21 @@
|
|
1
|
+
name: Test
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [main]
|
6
|
+
pull_request:
|
7
|
+
branches: [main]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
ruby:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
matrix:
|
14
|
+
ruby-version: ["2.5", "2.6", "2.7", "3.0"]
|
15
|
+
steps:
|
16
|
+
- uses: actions/checkout@v2
|
17
|
+
- uses: ruby/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: ${{ matrix.ruby-version }}
|
20
|
+
bundler-cache: true
|
21
|
+
- run: bundle exec rake
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
inherit_gem:
|
2
|
+
rubocop-bsm:
|
3
|
+
- default.yml
|
4
|
+
inherit_mode:
|
5
|
+
merge:
|
6
|
+
- Exclude
|
7
|
+
|
8
|
+
AllCops:
|
9
|
+
TargetRubyVersion: "2.5"
|
10
|
+
|
11
|
+
Metrics/ParameterLists:
|
12
|
+
Exclude:
|
13
|
+
- lib/net/ftp/list/entry.rb
|
14
|
+
Metrics/MethodLength:
|
15
|
+
Exclude:
|
16
|
+
- lib/net/ftp/list/unix.rb
|
17
|
+
- test/**/*.rb
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,63 +1,59 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
net-ftp-list (3.3.0)
|
5
|
+
|
1
6
|
GEM
|
2
7
|
remote: https://rubygems.org/
|
3
8
|
specs:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
oauth2 (1.4.0)
|
40
|
-
faraday (>= 0.8, < 0.13)
|
41
|
-
jwt (~> 1.0)
|
42
|
-
multi_json (~> 1.3)
|
43
|
-
multi_xml (~> 0.5)
|
44
|
-
rack (>= 1.2, < 3)
|
45
|
-
power_assert (1.1.1)
|
46
|
-
psych (3.0.2)
|
47
|
-
rack (2.0.4)
|
48
|
-
rake (12.3.1)
|
49
|
-
rdoc (6.0.3)
|
50
|
-
semver2 (3.4.2)
|
51
|
-
test-unit (3.2.7)
|
9
|
+
ast (2.4.2)
|
10
|
+
parallel (1.20.1)
|
11
|
+
parser (3.0.1.1)
|
12
|
+
ast (~> 2.4.1)
|
13
|
+
power_assert (2.0.0)
|
14
|
+
rainbow (3.0.0)
|
15
|
+
rake (13.0.3)
|
16
|
+
regexp_parser (2.1.1)
|
17
|
+
rexml (3.2.5)
|
18
|
+
rubocop (1.15.0)
|
19
|
+
parallel (~> 1.10)
|
20
|
+
parser (>= 3.0.0.0)
|
21
|
+
rainbow (>= 2.2.2, < 4.0)
|
22
|
+
regexp_parser (>= 1.8, < 3.0)
|
23
|
+
rexml
|
24
|
+
rubocop-ast (>= 1.5.0, < 2.0)
|
25
|
+
ruby-progressbar (~> 1.7)
|
26
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
27
|
+
rubocop-ast (1.6.0)
|
28
|
+
parser (>= 3.0.1.1)
|
29
|
+
rubocop-bsm (0.6.0)
|
30
|
+
rubocop (~> 1.0)
|
31
|
+
rubocop-performance
|
32
|
+
rubocop-rake
|
33
|
+
rubocop-rspec
|
34
|
+
rubocop-performance (1.11.3)
|
35
|
+
rubocop (>= 1.7.0, < 2.0)
|
36
|
+
rubocop-ast (>= 0.4.0)
|
37
|
+
rubocop-rake (0.5.1)
|
38
|
+
rubocop
|
39
|
+
rubocop-rspec (2.3.0)
|
40
|
+
rubocop (~> 1.0)
|
41
|
+
rubocop-ast (>= 1.1.0)
|
42
|
+
ruby-progressbar (1.11.0)
|
43
|
+
test-unit (3.4.1)
|
52
44
|
power_assert
|
53
|
-
|
45
|
+
timecop (0.9.4)
|
46
|
+
unicode-display_width (2.0.0)
|
54
47
|
|
55
48
|
PLATFORMS
|
56
49
|
ruby
|
57
50
|
|
58
51
|
DEPENDENCIES
|
59
|
-
|
52
|
+
net-ftp-list!
|
53
|
+
rake
|
54
|
+
rubocop-bsm
|
60
55
|
test-unit
|
56
|
+
timecop
|
61
57
|
|
62
58
|
BUNDLED WITH
|
63
|
-
|
59
|
+
2.2.14
|
data/Rakefile
CHANGED
@@ -1,54 +1,22 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require 'yaml'
|
4
|
-
|
5
|
-
begin
|
6
|
-
require 'jeweler'
|
7
|
-
Jeweler::Tasks.new do |gem|
|
8
|
-
gem.name = "net-ftp-list"
|
9
|
-
gem.summary = %Q{Parse FTP LIST command output.}
|
10
|
-
gem.email = "enquiries@statelesssystems.com"
|
11
|
-
gem.homepage = "http://github.com/stateless-systems/net-ftp-list"
|
12
|
-
gem.authors = ["Stateless Systems"]
|
13
|
-
end
|
14
|
-
Jeweler::RubygemsDotOrgTasks.new
|
15
|
-
rescue LoadError
|
16
|
-
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
17
|
-
end
|
18
|
-
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'bundler/gem_tasks'
|
19
3
|
require 'rake/testtask'
|
4
|
+
require 'rdoc/task'
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
|
20
7
|
Rake::TestTask.new(:test) do |test|
|
21
8
|
test.libs << 'lib' << 'test'
|
22
9
|
test.pattern = 'test/**/test_*.rb'
|
23
10
|
test.verbose = true
|
24
11
|
end
|
25
12
|
|
26
|
-
begin
|
27
|
-
require 'rcov/rcovtask'
|
28
|
-
Rcov::RcovTask.new do |test|
|
29
|
-
test.libs << 'test'
|
30
|
-
test.pattern = 'test/**/test_*.rb'
|
31
|
-
test.verbose = true
|
32
|
-
end
|
33
|
-
rescue LoadError
|
34
|
-
task :rcov do
|
35
|
-
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
task :default => :test
|
40
|
-
|
41
|
-
require 'rdoc/task'
|
42
13
|
Rake::RDocTask.new do |rdoc|
|
43
|
-
if File.exist?('VERSION.yml')
|
44
|
-
config = YAML.load(File.read('VERSION.yml'))
|
45
|
-
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
46
|
-
else
|
47
|
-
version = ""
|
48
|
-
end
|
49
|
-
|
50
14
|
rdoc.rdoc_dir = 'rdoc'
|
51
|
-
rdoc.title =
|
15
|
+
rdoc.title = 'net-ftp-list'
|
52
16
|
rdoc.rdoc_files.include('README*')
|
53
17
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
18
|
end
|
19
|
+
|
20
|
+
RuboCop::RakeTask.new(:rubocop)
|
21
|
+
|
22
|
+
task default: %i[rubocop test]
|
data/lib/net/ftp/list.rb
CHANGED
@@ -21,9 +21,9 @@ module Net::FTP::List
|
|
21
21
|
end
|
22
22
|
|
23
23
|
# Parse a line from FTP LIST responsesa and return a Net::FTP::List::Entry
|
24
|
-
def self.parse(*args)
|
25
|
-
Parser.
|
26
|
-
entry =
|
24
|
+
def self.parse(*args, **opts)
|
25
|
+
Parser.parsers.each do |parser|
|
26
|
+
entry = parser.parse(*args, **opts)
|
27
27
|
return entry if entry
|
28
28
|
end
|
29
29
|
end
|
@@ -32,4 +32,3 @@ module Net::FTP::List
|
|
32
32
|
class ParseError < RuntimeError
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
data/lib/net/ftp/list/entry.rb
CHANGED
@@ -2,17 +2,28 @@
|
|
2
2
|
class Net::FTP::List::Entry
|
3
3
|
include Comparable
|
4
4
|
|
5
|
-
|
5
|
+
attr_reader :raw, :basename, :type, :filesize, :mtime, :server_type, :symlink_destination
|
6
|
+
alias to_s raw
|
7
|
+
alias name basename
|
8
|
+
alias size filesize
|
6
9
|
|
7
10
|
# Create a new entry object. The additional argument is the list of metadata keys
|
8
11
|
# that can be used on the object. By default just takes and set the raw list entry.
|
9
12
|
# Net::FTP::List.parse(raw_list_string) # => Net::FTP::List::Parser instance.
|
10
|
-
def initialize(raw_ls_line,
|
13
|
+
def initialize(raw_ls_line,
|
14
|
+
basename: nil,
|
15
|
+
type: nil,
|
16
|
+
mtime: nil,
|
17
|
+
filesize: nil,
|
18
|
+
server_type: nil,
|
19
|
+
symlink_destination: nil) #:nodoc:
|
11
20
|
@raw = raw_ls_line.respond_to?(:force_encoding) ? raw_ls_line.force_encoding('utf-8') : raw_ls_line
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
21
|
+
@basename = basename || ''
|
22
|
+
@type = type
|
23
|
+
@mtime = mtime || Time.now
|
24
|
+
@filesize = filesize || 0
|
25
|
+
@server_type = server_type || 'Unknown'
|
26
|
+
@symlink_destination = symlink_destination
|
16
27
|
end
|
17
28
|
|
18
29
|
# Tests for objects equality (value and type).
|
@@ -22,83 +33,52 @@ class Net::FTP::List::Entry
|
|
22
33
|
# @return [true, false] true if the objects are equal and have the same type; false otherwise.
|
23
34
|
#
|
24
35
|
def eql?(other)
|
25
|
-
return false
|
26
|
-
return true if
|
36
|
+
return false unless other.is_a?(::Net::FTP::List::Entry)
|
37
|
+
return true if equal?(other)
|
27
38
|
|
28
|
-
|
39
|
+
raw == other.raw # if it's exactly the same line then the objects are the same
|
29
40
|
end
|
30
41
|
|
31
|
-
|
32
42
|
# Compares the receiver against another object.
|
33
43
|
#
|
34
44
|
# @param (see #eql?)
|
35
45
|
#
|
36
|
-
# @return [
|
46
|
+
# @return [Integer] -1, 0, or +1 depending on whether the receiver is less than, equal to, or greater than the other object.
|
37
47
|
#
|
38
48
|
def <=>(other)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
49
|
+
case other
|
50
|
+
when ::Net::FTP::List::Entry
|
51
|
+
return filesize <=> other.filesize
|
52
|
+
when Numeric
|
53
|
+
return filesize <=> other
|
43
54
|
end
|
44
|
-
raise ArgumentError.new('comparison of %s with %s failed!' % [self.class, other.class])
|
45
|
-
end
|
46
55
|
|
47
|
-
|
48
|
-
def raw
|
49
|
-
@raw ||= ''
|
50
|
-
end
|
51
|
-
alias_method :to_s, :raw
|
52
|
-
|
53
|
-
# The items basename (filename).
|
54
|
-
def basename
|
55
|
-
@basename ||= ''
|
56
|
-
end
|
57
|
-
alias name basename
|
58
|
-
|
59
|
-
# Symlink destination, the "/etc" in "bar -> /etc". May be nil.
|
60
|
-
def symlink_destination
|
61
|
-
@symlink_destination
|
56
|
+
raise ArgumentError, format('comparison of %<self>s with %<other>s failed!', self: self.class, other: other.class)
|
62
57
|
end
|
63
58
|
|
64
59
|
# Looks like a directory, try CWD.
|
65
60
|
def dir?
|
66
|
-
|
61
|
+
type == :dir
|
67
62
|
end
|
68
63
|
alias directory? dir?
|
69
64
|
|
70
65
|
# Looks like a file, try RETR.
|
71
66
|
def file?
|
72
|
-
|
67
|
+
type == :file
|
73
68
|
end
|
74
69
|
|
75
70
|
# Looks like a symbolic link.
|
76
71
|
def symlink?
|
77
|
-
|
72
|
+
type == :symlink
|
78
73
|
end
|
79
74
|
|
80
75
|
# Looks like a device.
|
81
76
|
def device?
|
82
|
-
|
83
|
-
end
|
84
|
-
|
85
|
-
# Returns the modification time of the file/directory or the current time if unknown
|
86
|
-
def mtime
|
87
|
-
@mtime || Time.now
|
88
|
-
end
|
89
|
-
|
90
|
-
# Returns the filesize of the entry or 0 for directorties
|
91
|
-
def filesize
|
92
|
-
@filesize || 0
|
93
|
-
end
|
94
|
-
alias size filesize
|
95
|
-
|
96
|
-
# Returns the detected server type if this entry
|
97
|
-
def server_type
|
98
|
-
@server_type || "Unknown"
|
77
|
+
type == :device
|
99
78
|
end
|
100
79
|
|
80
|
+
# Is the entry type unknown?
|
101
81
|
def unknown?
|
102
|
-
|
82
|
+
!dir? && !file? && !symlink? && !device?
|
103
83
|
end
|
104
84
|
end
|
@@ -11,36 +11,34 @@ require 'date'
|
|
11
11
|
class Net::FTP::List::Microsoft < Net::FTP::List::Parser
|
12
12
|
REGEXP = %r!
|
13
13
|
^\s*
|
14
|
-
([0-9
|
14
|
+
([0-9\-:/]{5,})\s+([0-9\-:]{3,}(?:[aApP][mM])?)\s+
|
15
15
|
(?:(<DIR>)|([0-9]+))\s+
|
16
16
|
(\S.*)
|
17
17
|
\s*$
|
18
|
-
!x
|
18
|
+
!x.freeze
|
19
19
|
|
20
20
|
# Parse a Microsoft(NT) like FTP LIST entries.
|
21
|
-
def self.parse(raw)
|
21
|
+
def self.parse(raw, timezone: :utc)
|
22
22
|
match = REGEXP.match(raw.strip) or return false
|
23
23
|
|
24
|
-
date_match =
|
24
|
+
date_match = /(\d\d).(\d\d).(\d\d(?:\d\d)?)/.match(match[1])
|
25
25
|
date_format = date_match[1].to_i > 12 ? '%d-%m-%y' : '%m-%d-%y'
|
26
|
-
date_format.sub!(
|
26
|
+
date_format.sub!(/%y/, '%Y') if date_match[3].length > 2
|
27
27
|
|
28
|
-
|
29
|
-
date_format.
|
30
|
-
date_format.
|
28
|
+
unless /-/.match?(match[1])
|
29
|
+
date_format.tr!('-', '/') if %r{/}.match?(match[1])
|
30
|
+
date_format.tr!('-', ':') if /:/.match?(match[1])
|
31
31
|
end
|
32
32
|
|
33
|
-
mtime =
|
34
|
-
|
35
|
-
filesize = is_dir ? 0 : match[4].to_i
|
33
|
+
mtime = parse_time("#{match[1]} #{match[2]}", format: "#{date_format} %H:%M%p", timezone: timezone)
|
34
|
+
type = match[3] == '<DIR>' ? :dir : :file
|
36
35
|
|
37
36
|
emit_entry(
|
38
37
|
raw,
|
39
|
-
:
|
40
|
-
:
|
41
|
-
:
|
42
|
-
:
|
43
|
-
:mtime => mtime
|
38
|
+
type: type,
|
39
|
+
filesize: match[4].to_i,
|
40
|
+
basename: match[5],
|
41
|
+
mtime: mtime,
|
44
42
|
)
|
45
43
|
end
|
46
44
|
end
|