recls-ruby 2.6.4
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/LICENSE +31 -0
- data/README.md +2 -0
- data/examples/show_hidden_files.rb +15 -0
- data/examples/show_readonly_files.rb +14 -0
- data/lib/recls.rb +41 -0
- data/lib/recls/entry.rb +328 -0
- data/lib/recls/filesearch.rb +251 -0
- data/lib/recls/flags.rb +77 -0
- data/lib/recls/foreach.rb +103 -0
- data/lib/recls/recls.rb +113 -0
- data/lib/recls/stat.rb +104 -0
- data/lib/recls/util.rb +73 -0
- data/lib/recls/version.rb +53 -0
- data/lib/recls/ximpl/os.rb +85 -0
- data/lib/recls/ximpl/unix.rb +81 -0
- data/lib/recls/ximpl/util.rb +650 -0
- data/lib/recls/ximpl/windows.rb +197 -0
- data/test/scratch/test_display_parts.rb +40 -0
- data/test/scratch/test_entry.rb +81 -0
- data/test/scratch/test_foreach.rb +41 -0
- data/test/scratch/test_show_dev_and_ino.rb +13 -0
- data/test/scratch/test_show_hidden.rb +30 -0
- data/test/unit/tc_recls_entries.rb +55 -0
- data/test/unit/tc_recls_entry.rb +40 -0
- data/test/unit/tc_recls_file_search.rb +68 -0
- data/test/unit/tc_recls_module.rb +78 -0
- data/test/unit/tc_recls_util.rb +159 -0
- data/test/unit/tc_recls_ximpl_util.rb +908 -0
- data/test/unit/ts_all.rb +20 -0
- metadata +73 -0
data/lib/recls/stat.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# ######################################################################### #
|
2
|
+
# File: recls/stat.rb
|
3
|
+
#
|
4
|
+
# Purpose: Defines the Recls.stat() method for the recls.Ruby library.
|
5
|
+
#
|
6
|
+
# Created: 24th July 2012
|
7
|
+
# Updated: 28th December 2015
|
8
|
+
#
|
9
|
+
# Author: Matthew Wilson
|
10
|
+
#
|
11
|
+
# Copyright (c) 2012-2015, Matthew Wilson and Synesis Software
|
12
|
+
# All rights reserved.
|
13
|
+
#
|
14
|
+
# Redistribution and use in source and binary forms, with or without
|
15
|
+
# modification, are permitted provided that the following conditions are met:
|
16
|
+
#
|
17
|
+
# * Redistributions of source code must retain the above copyright notice,
|
18
|
+
# this list of conditions and the following disclaimer.
|
19
|
+
#
|
20
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
21
|
+
# this list of conditions and the following disclaimer in the documentation
|
22
|
+
# and/or other materials provided with the distribution.
|
23
|
+
#
|
24
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
25
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
26
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
27
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
28
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
29
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
30
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
31
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
32
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
33
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
34
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
35
|
+
#
|
36
|
+
# ######################################################################### #
|
37
|
+
|
38
|
+
|
39
|
+
require 'recls/entry'
|
40
|
+
require 'recls/flags'
|
41
|
+
|
42
|
+
module Recls
|
43
|
+
|
44
|
+
# USAGE:
|
45
|
+
#
|
46
|
+
# - stat(path)
|
47
|
+
# - stat(path, flags)
|
48
|
+
# - stat(path, search_root)
|
49
|
+
# - stat(path, search_root, flags)
|
50
|
+
# - stat(path, flags, search_root)
|
51
|
+
def self.stat(path, *args)
|
52
|
+
|
53
|
+
flags = 0
|
54
|
+
search_root = nil
|
55
|
+
message = nil
|
56
|
+
|
57
|
+
path = File.expand_path(path) if path =~ /^~[\\\/]*/
|
58
|
+
|
59
|
+
case args.size
|
60
|
+
when 0
|
61
|
+
;
|
62
|
+
when 1
|
63
|
+
case args[0]
|
64
|
+
when ::Integer
|
65
|
+
flags = args[0]
|
66
|
+
when ::String
|
67
|
+
search_root = args[0]
|
68
|
+
else
|
69
|
+
message = "argument '#{args[0]}' (#{args[0].class}) not valid"
|
70
|
+
end
|
71
|
+
when 2
|
72
|
+
if false
|
73
|
+
elsif ::Integer === args[0] && ::String === args[1]
|
74
|
+
flags = args[0]
|
75
|
+
search_root = args[1]
|
76
|
+
elsif ::String === args[0] && ::Integer === args[1]
|
77
|
+
search_root = args[0]
|
78
|
+
flags = args[1]
|
79
|
+
else
|
80
|
+
message = "invalid combination of arguments"
|
81
|
+
end
|
82
|
+
else
|
83
|
+
message = "too many arguments"
|
84
|
+
end
|
85
|
+
|
86
|
+
raise ArgumentError, "#{message}: Recls.stat() takes one (path), two (path+flags or path+search_root), or three (path+search_root+flags) arguments" if message
|
87
|
+
|
88
|
+
begin
|
89
|
+
Recls::Entry.new(path, Recls::Ximpl::FileStat.stat(path), search_root, flags)
|
90
|
+
rescue Errno::ENOENT => x
|
91
|
+
|
92
|
+
if 0 != (flags & Recls::DETAILS_LATER)
|
93
|
+
|
94
|
+
Recls::Entry.new(path, nil, search_root, flags)
|
95
|
+
else
|
96
|
+
|
97
|
+
nil
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# ############################## end of file ############################# #
|
104
|
+
|
data/lib/recls/util.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# ######################################################################### #
|
2
|
+
# File: recls/util.rb
|
3
|
+
#
|
4
|
+
# Purpose: Utility module functions for recls library
|
5
|
+
#
|
6
|
+
# Created: 17th February 2014
|
7
|
+
# Updated: 27th August 2015
|
8
|
+
#
|
9
|
+
# Author: Matthew Wilson
|
10
|
+
#
|
11
|
+
# Copyright (c) 2012-2015, Matthew Wilson and Synesis Software
|
12
|
+
# All rights reserved.
|
13
|
+
#
|
14
|
+
# Redistribution and use in source and binary forms, with or without
|
15
|
+
# modification, are permitted provided that the following conditions are met:
|
16
|
+
#
|
17
|
+
# * Redistributions of source code must retain the above copyright notice,
|
18
|
+
# this list of conditions and the following disclaimer.
|
19
|
+
#
|
20
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
21
|
+
# this list of conditions and the following disclaimer in the documentation
|
22
|
+
# and/or other materials provided with the distribution.
|
23
|
+
#
|
24
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
25
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
26
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
27
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
28
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
29
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
30
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
31
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
32
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
33
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
34
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
35
|
+
#
|
36
|
+
# ######################################################################### #
|
37
|
+
|
38
|
+
|
39
|
+
require 'recls/ximpl/util'
|
40
|
+
require 'recls/ximpl/os'
|
41
|
+
|
42
|
+
module Recls
|
43
|
+
|
44
|
+
# Obtains the absolute form of the given path
|
45
|
+
def self.absolute_path(path)
|
46
|
+
|
47
|
+
return Recls::Ximpl.absolute_path path
|
48
|
+
end
|
49
|
+
|
50
|
+
# Canonicalises the given path, by removing dots ('.' and '..')
|
51
|
+
# directories
|
52
|
+
def self.canonicalise_path(path)
|
53
|
+
|
54
|
+
return Recls::Ximpl.canonicalise_path path
|
55
|
+
end
|
56
|
+
|
57
|
+
# Derives a given path relative to an origin, unless the path is
|
58
|
+
# absolute
|
59
|
+
def self.derive_relative_path(origin, path)
|
60
|
+
|
61
|
+
return Recls::Ximpl.derive_relative_path origin, path
|
62
|
+
end
|
63
|
+
|
64
|
+
# Combines paths, optionally canonicalising them
|
65
|
+
#
|
66
|
+
def self.combine_paths(origin, path, options={})
|
67
|
+
|
68
|
+
return Recls::Ximpl.combine_paths origin, path, options
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# ############################## end of file ############################# #
|
73
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# ######################################################################### #
|
2
|
+
# File: recls/version.rb
|
3
|
+
#
|
4
|
+
# Purpose: Version for recls library
|
5
|
+
#
|
6
|
+
# Created: 14th February 2014
|
7
|
+
# Updated: 31st May 2016
|
8
|
+
#
|
9
|
+
# Author: Matthew Wilson
|
10
|
+
#
|
11
|
+
# Copyright (c) 2012-2016, Matthew Wilson and Synesis Software
|
12
|
+
# All rights reserved.
|
13
|
+
#
|
14
|
+
# Redistribution and use in source and binary forms, with or without
|
15
|
+
# modification, are permitted provided that the following conditions are met:
|
16
|
+
#
|
17
|
+
# * Redistributions of source code must retain the above copyright notice,
|
18
|
+
# this list of conditions and the following disclaimer.
|
19
|
+
#
|
20
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
21
|
+
# this list of conditions and the following disclaimer in the documentation
|
22
|
+
# and/or other materials provided with the distribution.
|
23
|
+
#
|
24
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
25
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
26
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
27
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
28
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
29
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
30
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
31
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
32
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
33
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
34
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
35
|
+
#
|
36
|
+
# ######################################################################### #
|
37
|
+
|
38
|
+
|
39
|
+
module Recls
|
40
|
+
|
41
|
+
# Current version of the recls.Ruby library
|
42
|
+
VERSION = '2.6.4'
|
43
|
+
|
44
|
+
private
|
45
|
+
VERSION_PARTS_ = VERSION.split(/[.]/).collect { |n| n.to_i } # :nodoc:
|
46
|
+
public
|
47
|
+
VERSION_MAJOR = VERSION_PARTS_[0] # :nodoc:
|
48
|
+
VERSION_MINOR = VERSION_PARTS_[1] # :nodoc:
|
49
|
+
VERSION_REVISION = VERSION_PARTS_[2] # :nodoc:
|
50
|
+
end
|
51
|
+
|
52
|
+
# ############################## end of file ############################# #
|
53
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# ######################################################################### #
|
2
|
+
# File: recls/ximpl/os.rb
|
3
|
+
#
|
4
|
+
# Purpose: Operating system internal implementation constructs for the
|
5
|
+
# recls library.
|
6
|
+
#
|
7
|
+
# Created: 16th February 2014
|
8
|
+
# Updated: 27th August 2015
|
9
|
+
#
|
10
|
+
# Author: Matthew Wilson
|
11
|
+
#
|
12
|
+
# Copyright (c) 2012-2015, Matthew Wilson and Synesis Software
|
13
|
+
# All rights reserved.
|
14
|
+
#
|
15
|
+
# Redistribution and use in source and binary forms, with or without
|
16
|
+
# modification, are permitted provided that the following conditions are met:
|
17
|
+
#
|
18
|
+
# * Redistributions of source code must retain the above copyright notice,
|
19
|
+
# this list of conditions and the following disclaimer.
|
20
|
+
#
|
21
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
22
|
+
# this list of conditions and the following disclaimer in the documentation
|
23
|
+
# and/or other materials provided with the distribution.
|
24
|
+
#
|
25
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
26
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
27
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
28
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
29
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
30
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
31
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
32
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
33
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
34
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
35
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
36
|
+
#
|
37
|
+
# ######################################################################### #
|
38
|
+
|
39
|
+
|
40
|
+
module Recls
|
41
|
+
|
42
|
+
module Ximpl
|
43
|
+
|
44
|
+
module OS
|
45
|
+
|
46
|
+
OS_IS_WINDOWS = (RUBY_PLATFORM =~ /(mswin|mingw|bccwin|wince)/i) ? true : false
|
47
|
+
|
48
|
+
PATH_NAME_SEPARATOR = OS_IS_WINDOWS ? '\\' : '/'
|
49
|
+
|
50
|
+
PATH_SEPARATOR = OS_IS_WINDOWS ? ';' : ':'
|
51
|
+
|
52
|
+
WILDCARDS_ALL = OS_IS_WINDOWS ? '*' : '*'
|
53
|
+
|
54
|
+
def OS.get_number_of_dots_dir_(p)
|
55
|
+
|
56
|
+
if p
|
57
|
+
if ?. == p[0]
|
58
|
+
return 1 if 1 == p.size
|
59
|
+
return 1 if ?/ == p[1]
|
60
|
+
return 1 if OS_IS_WINDOWS and ?\\ == p[1]
|
61
|
+
if ?. == p[1]
|
62
|
+
return 2 if 2 == p.size
|
63
|
+
return 2 if ?/ == p[2]
|
64
|
+
return 2 if OS_IS_WINDOWS and ?\\ == p[2]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
return 0
|
70
|
+
end
|
71
|
+
|
72
|
+
def OS.is_root_dir_(p)
|
73
|
+
|
74
|
+
return nil if not p
|
75
|
+
return true if '/' == p
|
76
|
+
return true if OS_IS_WINDOWS and '\\' == p
|
77
|
+
|
78
|
+
return false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# ############################## end of file ############################# #
|
85
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# ######################################################################### #
|
2
|
+
# File: recls/ximpl/unix.rb
|
3
|
+
#
|
4
|
+
# Purpose: UNIX-specific constructs for the recls library.
|
5
|
+
#
|
6
|
+
# Created: 19th February 2014
|
7
|
+
# Updated: 27th August 2015
|
8
|
+
#
|
9
|
+
# Author: Matthew Wilson
|
10
|
+
#
|
11
|
+
# Copyright (c) 2012-2015, Matthew Wilson and Synesis Software
|
12
|
+
# All rights reserved.
|
13
|
+
#
|
14
|
+
# Redistribution and use in source and binary forms, with or without
|
15
|
+
# modification, are permitted provided that the following conditions are met:
|
16
|
+
#
|
17
|
+
# * Redistributions of source code must retain the above copyright notice,
|
18
|
+
# this list of conditions and the following disclaimer.
|
19
|
+
#
|
20
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
21
|
+
# this list of conditions and the following disclaimer in the documentation
|
22
|
+
# and/or other materials provided with the distribution.
|
23
|
+
#
|
24
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
25
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
26
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
27
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
28
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
29
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
30
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
31
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
32
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
33
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
34
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
35
|
+
#
|
36
|
+
# ######################################################################### #
|
37
|
+
|
38
|
+
|
39
|
+
require 'recls/ximpl/util'
|
40
|
+
|
41
|
+
module Recls
|
42
|
+
|
43
|
+
module Ximpl
|
44
|
+
|
45
|
+
class FileStat < File::Stat
|
46
|
+
|
47
|
+
private
|
48
|
+
def initialize(path)
|
49
|
+
|
50
|
+
@path = path
|
51
|
+
|
52
|
+
super(path)
|
53
|
+
end
|
54
|
+
|
55
|
+
public
|
56
|
+
attr_reader :path
|
57
|
+
|
58
|
+
def hidden?
|
59
|
+
|
60
|
+
basename = File.basename @path
|
61
|
+
|
62
|
+
return false if basename.empty?
|
63
|
+
return false if '.' == basename
|
64
|
+
return false if '..' == basename
|
65
|
+
return false if ?. != basename[0]
|
66
|
+
|
67
|
+
return true
|
68
|
+
end
|
69
|
+
|
70
|
+
public
|
71
|
+
def FileStat.stat(path)
|
72
|
+
|
73
|
+
Recls::Ximpl::FileStat.new(path)
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# ############################## end of file ############################# #
|
81
|
+
|
@@ -0,0 +1,650 @@
|
|
1
|
+
# ######################################################################### #
|
2
|
+
# File: recls/ximpl/util.rb
|
3
|
+
#
|
4
|
+
# Purpose: Internal implementation constructs for the recls library.
|
5
|
+
#
|
6
|
+
# Created: 24th July 2012
|
7
|
+
# Updated: 20th December 2015
|
8
|
+
#
|
9
|
+
# Author: Matthew Wilson
|
10
|
+
#
|
11
|
+
# Copyright (c) 2012-2015, Matthew Wilson and Synesis Software
|
12
|
+
# All rights reserved.
|
13
|
+
#
|
14
|
+
# Redistribution and use in source and binary forms, with or without
|
15
|
+
# modification, are permitted provided that the following conditions are met:
|
16
|
+
#
|
17
|
+
# * Redistributions of source code must retain the above copyright notice,
|
18
|
+
# this list of conditions and the following disclaimer.
|
19
|
+
#
|
20
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
21
|
+
# this list of conditions and the following disclaimer in the documentation
|
22
|
+
# and/or other materials provided with the distribution.
|
23
|
+
#
|
24
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
25
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
26
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
27
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
28
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
29
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
30
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
31
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
32
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
33
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
34
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
35
|
+
#
|
36
|
+
# ######################################################################### #
|
37
|
+
|
38
|
+
|
39
|
+
require 'recls/ximpl/os'
|
40
|
+
require 'recls/flags'
|
41
|
+
|
42
|
+
require 'pathname'
|
43
|
+
|
44
|
+
module Recls
|
45
|
+
|
46
|
+
module Ximpl
|
47
|
+
|
48
|
+
module Util
|
49
|
+
|
50
|
+
def self.is_path_name_separator(c)
|
51
|
+
|
52
|
+
return true if ?/ == c
|
53
|
+
|
54
|
+
if Recls::Ximpl::OS::OS_IS_WINDOWS
|
55
|
+
return true if ?\\ == c
|
56
|
+
end
|
57
|
+
|
58
|
+
return false
|
59
|
+
end
|
60
|
+
|
61
|
+
# Indicates whether a trailing slash is on the given path
|
62
|
+
#
|
63
|
+
# dependencies: none
|
64
|
+
def self.has_trailing_slash(p)
|
65
|
+
|
66
|
+
return p if p.nil? or p.empty?
|
67
|
+
|
68
|
+
return self.is_path_name_separator(p[-1])
|
69
|
+
end
|
70
|
+
|
71
|
+
# returns the trailing slash, or nil if none present
|
72
|
+
#
|
73
|
+
# dependencies: none
|
74
|
+
def self.get_trailing_slash(p, args = {})
|
75
|
+
|
76
|
+
return nil if p.nil?
|
77
|
+
return nil if p.empty?
|
78
|
+
|
79
|
+
return self.is_path_name_separator(p[-1]) ? p[-1] : nil
|
80
|
+
end
|
81
|
+
|
82
|
+
# appends trailing slash to a path if not already
|
83
|
+
# present
|
84
|
+
#
|
85
|
+
# dependencies: none
|
86
|
+
def self.append_trailing_slash(p, slash = nil)
|
87
|
+
|
88
|
+
return p if not p or p.empty?
|
89
|
+
|
90
|
+
return p if self.is_path_name_separator(p[-1])
|
91
|
+
|
92
|
+
slash = '/' if not slash
|
93
|
+
|
94
|
+
"#{p}#{slash}"
|
95
|
+
end
|
96
|
+
|
97
|
+
# trims trailing slash from a path, unless it is the
|
98
|
+
# root
|
99
|
+
#
|
100
|
+
# dependencies: none
|
101
|
+
def self.trim_trailing_slash(p)
|
102
|
+
|
103
|
+
return p if not p or p.empty?
|
104
|
+
|
105
|
+
p = p[0 ... -1] if self.is_path_name_separator(p[-1])
|
106
|
+
|
107
|
+
return p
|
108
|
+
end
|
109
|
+
|
110
|
+
# From path p, returns a tuple containing either:
|
111
|
+
#
|
112
|
+
# [ nil, p ] if p does not contain a Windows root, or
|
113
|
+
#
|
114
|
+
# [ wroot, remainder ] if p does contain a Windows root, or
|
115
|
+
#
|
116
|
+
# [ nil, nil ] if p is nil
|
117
|
+
#
|
118
|
+
# dependencies: none
|
119
|
+
def self.get_windows_root(p)
|
120
|
+
|
121
|
+
return [ nil, nil ] if not p
|
122
|
+
|
123
|
+
if Recls::Ximpl::OS::OS_IS_WINDOWS
|
124
|
+
|
125
|
+
# Windows local drive (e.g. 'H:')
|
126
|
+
#
|
127
|
+
# NOTE: this works for both rooted and unrooted paths
|
128
|
+
if p =~ /^([a-zA-Z]:)/
|
129
|
+
return [ $1, $' ]
|
130
|
+
end
|
131
|
+
|
132
|
+
# UNC network drive
|
133
|
+
#
|
134
|
+
# NOTE: there are several permutations ...
|
135
|
+
if p =~ /^(\\\\[^\\\/:*?<>|]+\\[^\\\/:*?<>|]+)([\\\/].*)$/
|
136
|
+
# \\server\share{\{... rest of path}}
|
137
|
+
return [ $1, $2 ]
|
138
|
+
end
|
139
|
+
if p =~ /^(\\\\[^\\\/:*?<>|]+\\[^\\\/:*?<>|]+)$/
|
140
|
+
# \\server\share
|
141
|
+
return [ $1, nil ]
|
142
|
+
end
|
143
|
+
if p =~ /^(\\\\[^\\\/:*?<>|]+\\)$/
|
144
|
+
# \\server\
|
145
|
+
return [ $1, nil ]
|
146
|
+
end
|
147
|
+
if p =~ /^(\\\\[^\\\/:*?<>|]+)$/
|
148
|
+
# \\server
|
149
|
+
return [ $1, nil ]
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
return [ nil, p ]
|
154
|
+
end
|
155
|
+
|
156
|
+
# obtains the parts from a path, including any Windows root and
|
157
|
+
# the file basename
|
158
|
+
def self.path_parts(path)
|
159
|
+
|
160
|
+
return nil if path.nil?
|
161
|
+
return [] if path.empty?
|
162
|
+
|
163
|
+
parts = []
|
164
|
+
|
165
|
+
wr, rem = self.get_windows_root(path)
|
166
|
+
|
167
|
+
parts << wr if wr
|
168
|
+
|
169
|
+
until rem.nil? || rem.empty?
|
170
|
+
if rem =~ /^([^\\\/]*[\\\/])/
|
171
|
+
parts << $1
|
172
|
+
rem = $'
|
173
|
+
else
|
174
|
+
parts << rem
|
175
|
+
rem = ''
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
parts
|
180
|
+
end
|
181
|
+
|
182
|
+
# Returns a tuple consisting of the following
|
183
|
+
# elements (or nil, for any element that is not)
|
184
|
+
# present
|
185
|
+
#
|
186
|
+
# f1. Windows root, or nil
|
187
|
+
# f2. directory, or nil
|
188
|
+
# f3. basename, or nil
|
189
|
+
# f4. basename-minus-extension, or nil
|
190
|
+
# f5. extension, or nil
|
191
|
+
# f6. array of directory path parts, which may be empty (not nil)
|
192
|
+
# f7. array of all path parts, which may be empty (not nil)
|
193
|
+
#
|
194
|
+
# dependencies: Util.path_parts, Util.get_windows_root
|
195
|
+
def self.split_path(p)
|
196
|
+
|
197
|
+
f1_windows_root, remainder = self.get_windows_root p
|
198
|
+
f1_windows_root = nil if not f1_windows_root or f1_windows_root.empty?
|
199
|
+
remainder = nil if not remainder or remainder.empty?
|
200
|
+
|
201
|
+
if not remainder or remainder.empty?
|
202
|
+
f2_directory = nil
|
203
|
+
f3_basename = nil
|
204
|
+
f4_nameonly = nil
|
205
|
+
f5_extension = nil
|
206
|
+
else
|
207
|
+
if remainder =~ /^(.*[\\\/])([^\\\/]*)$/
|
208
|
+
f2_directory = $1
|
209
|
+
f3_basename = $2
|
210
|
+
else
|
211
|
+
f2_directory = nil
|
212
|
+
f3_basename = remainder
|
213
|
+
f4_nameonly = nil
|
214
|
+
f5_extension = nil
|
215
|
+
end
|
216
|
+
|
217
|
+
f2_directory = nil if not f2_directory or f2_directory.empty?
|
218
|
+
f3_basename = nil if not f3_basename or f3_basename.empty?
|
219
|
+
|
220
|
+
if f3_basename
|
221
|
+
# special case: treat '.' and '..' as file-name only
|
222
|
+
if '.' == f3_basename or '..' == f3_basename
|
223
|
+
f4_nameonly = f3_basename
|
224
|
+
f5_extension = nil
|
225
|
+
elsif f3_basename =~ /^(.*)(\.[^.]*)$/
|
226
|
+
f4_nameonly = $1
|
227
|
+
f5_extension = $2
|
228
|
+
else
|
229
|
+
f4_nameonly = f3_basename
|
230
|
+
f5_extension = nil
|
231
|
+
end
|
232
|
+
else
|
233
|
+
f4_nameonly = nil
|
234
|
+
f5_extension = nil
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
f4_nameonly = nil if not f4_nameonly or f4_nameonly.empty?
|
239
|
+
f5_extension = nil if not f5_extension or f5_extension.empty?
|
240
|
+
f6_directory_parts = self.path_parts(f2_directory)
|
241
|
+
f7_path_parts = self.path_parts(p)
|
242
|
+
|
243
|
+
return [ f1_windows_root, f2_directory, f3_basename, f4_nameonly, f5_extension, f6_directory_parts, f7_path_parts ]
|
244
|
+
end
|
245
|
+
|
246
|
+
# Returns a tuple consisting of:
|
247
|
+
#
|
248
|
+
# f1. The canonicalised array of parts
|
249
|
+
# f2. A boolean indicating whether to 'consume' the basename
|
250
|
+
#
|
251
|
+
# dependencies: OS.is_root_dir_, OS.get_number_of_dots_dir_,
|
252
|
+
def self.canonicalise_parts(parts, basename = nil)
|
253
|
+
|
254
|
+
newParts = []
|
255
|
+
|
256
|
+
trailing_slash = parts.empty? ? nil : self.get_trailing_slash(parts[-1])
|
257
|
+
|
258
|
+
lastSingleDots = nil
|
259
|
+
|
260
|
+
path_is_rooted = nil
|
261
|
+
|
262
|
+
index = -1
|
263
|
+
parts.each do |part|
|
264
|
+
|
265
|
+
index += 1
|
266
|
+
|
267
|
+
next if not part
|
268
|
+
next if part.empty?
|
269
|
+
|
270
|
+
if path_is_rooted.nil?
|
271
|
+
path_is_rooted = self.is_path_name_separator(part[0])
|
272
|
+
end
|
273
|
+
|
274
|
+
if ?. == part[0]
|
275
|
+
if self.is_path_name_separator(part[1])
|
276
|
+
# single dots, so ...
|
277
|
+
|
278
|
+
# ... remember the last instance, and ...
|
279
|
+
lastSingleDots = part
|
280
|
+
|
281
|
+
# ... skip to leave this out of the result
|
282
|
+
next
|
283
|
+
elsif ?. == part[1]
|
284
|
+
if self.is_path_name_separator(part[2])
|
285
|
+
# double dots, so ...
|
286
|
+
# ... skip this and pop prior from the new list iff:
|
287
|
+
#
|
288
|
+
# 1. there is a prior elements in the new list (size > 1); AND
|
289
|
+
# 2. the last element in the new list is not the root directory; AND
|
290
|
+
# 3. the last element in the list is not a dots directory
|
291
|
+
if not newParts.empty? # 1.
|
292
|
+
priorPart = newParts[-1]
|
293
|
+
if 1 == newParts.size and OS.is_root_dir_(priorPart)
|
294
|
+
# 2.
|
295
|
+
next
|
296
|
+
else
|
297
|
+
dirtype = OS.get_number_of_dots_dir_(priorPart)
|
298
|
+
if 0 == dirtype # 3.
|
299
|
+
if newParts.pop
|
300
|
+
next
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
else
|
306
|
+
# it's a ..X part
|
307
|
+
end
|
308
|
+
else
|
309
|
+
# it's a .X part
|
310
|
+
end
|
311
|
+
else
|
312
|
+
# it's a non-dots part
|
313
|
+
end
|
314
|
+
|
315
|
+
newParts << part
|
316
|
+
end
|
317
|
+
|
318
|
+
consume_basename = false
|
319
|
+
|
320
|
+
if basename
|
321
|
+
if ?. == basename[0]
|
322
|
+
if 1 == basename.size
|
323
|
+
# single dots
|
324
|
+
if newParts.empty?
|
325
|
+
lastSingleDots = false
|
326
|
+
else
|
327
|
+
consume_basename = true
|
328
|
+
end
|
329
|
+
elsif ?. == basename[1] and 2 == basename.size
|
330
|
+
# double dots, so ...
|
331
|
+
#
|
332
|
+
# ... pop unless we already have some outstanding double dots
|
333
|
+
if newParts.empty?
|
334
|
+
newParts << '..'
|
335
|
+
consume_basename = true
|
336
|
+
elsif 1 == newParts.size && 1 == newParts[0].size && Util.is_path_name_separator(newParts[0][0])
|
337
|
+
consume_basename = true
|
338
|
+
else
|
339
|
+
if 2 != OS.get_number_of_dots_dir_(newParts[-1])
|
340
|
+
newParts.pop
|
341
|
+
consume_basename = true
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
# push lastSingleDots (which may contain a trailing slash) if
|
349
|
+
# exists and newParts is empty
|
350
|
+
newParts << lastSingleDots if lastSingleDots and newParts.empty?
|
351
|
+
|
352
|
+
if not newParts.empty?
|
353
|
+
if 2 == OS.get_number_of_dots_dir_(newParts[-1])
|
354
|
+
# the last element is the double-dots directory, but
|
355
|
+
# need to determine whether to ensure/remote a
|
356
|
+
# trailing slash
|
357
|
+
if basename and not basename.empty?
|
358
|
+
if not consume_basename
|
359
|
+
# leave as is
|
360
|
+
else
|
361
|
+
#
|
362
|
+
newParts[-1] = '..'
|
363
|
+
end
|
364
|
+
end
|
365
|
+
end
|
366
|
+
else
|
367
|
+
# handle case where all (double)-dots have eliminated
|
368
|
+
# all regular directories
|
369
|
+
if not basename or basename.empty? or consume_basename
|
370
|
+
newParts << '.'
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
[ newParts.join(''), consume_basename ]
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
# Canonicalises a path
|
379
|
+
#
|
380
|
+
# Note: contains a trailing slash if, in the context of the given
|
381
|
+
# path, the last element of the canonicalised path is a directory
|
382
|
+
# unequivocally
|
383
|
+
def self.canonicalise_path(path)
|
384
|
+
|
385
|
+
return nil if not path
|
386
|
+
return '' if path.empty?
|
387
|
+
|
388
|
+
f1_windows_root, f2_directory, f3_basename, dummy1, dummy2, directory_parts, dummy3 = Util.split_path(path)
|
389
|
+
|
390
|
+
if not f2_directory
|
391
|
+
canonicalised_directory = nil
|
392
|
+
else
|
393
|
+
canonicalised_directory, consume_basename = Util.canonicalise_parts(directory_parts, f3_basename)
|
394
|
+
f3_basename = nil if consume_basename
|
395
|
+
end
|
396
|
+
|
397
|
+
return "#{f1_windows_root}#{canonicalised_directory}#{f3_basename}"
|
398
|
+
end
|
399
|
+
|
400
|
+
# determines the absolute path of a given path
|
401
|
+
def self.absolute_path(path, refdir = nil)
|
402
|
+
|
403
|
+
case path
|
404
|
+
when ::NilClass
|
405
|
+
return nil
|
406
|
+
when ::String
|
407
|
+
when ::Recls::Entry
|
408
|
+
path = path.to_s
|
409
|
+
else
|
410
|
+
raise TypeError, "parameter path ('#{path}') is of type #{path.class} must be an instance of #{::String} or #{::Recls::Entry}"
|
411
|
+
end
|
412
|
+
|
413
|
+
return '' if path.empty?
|
414
|
+
|
415
|
+
f1_windows_root, f2_directory, f3_basename, dummy1, dummy2, dummy3, dummy4 = Util.split_path(path)
|
416
|
+
|
417
|
+
if f2_directory =~ /^[\\\/]/
|
418
|
+
return path
|
419
|
+
end
|
420
|
+
|
421
|
+
cwd = refdir ? refdir : Dir.getwd
|
422
|
+
|
423
|
+
trailing_slash = Util.get_trailing_slash(path)
|
424
|
+
|
425
|
+
if '.' == path
|
426
|
+
return Util.trim_trailing_slash cwd
|
427
|
+
elsif 2 == path.size and trailing_slash
|
428
|
+
return Util.append_trailing_slash(cwd, path[1..1])
|
429
|
+
end
|
430
|
+
|
431
|
+
cwd = Util.append_trailing_slash(cwd)
|
432
|
+
|
433
|
+
path = "#{cwd}#{path}"
|
434
|
+
|
435
|
+
path = canonicalise_path path
|
436
|
+
|
437
|
+
if trailing_slash
|
438
|
+
path = Util.append_trailing_slash path, trailing_slash
|
439
|
+
else
|
440
|
+
path = Util.trim_trailing_slash path
|
441
|
+
end
|
442
|
+
|
443
|
+
path
|
444
|
+
end
|
445
|
+
|
446
|
+
# obtains the basename of a path, e.g.
|
447
|
+
# the basename of
|
448
|
+
# abc/def/ghi.jkl
|
449
|
+
# or (on Windows)
|
450
|
+
# C:\abc\def\ghi.jkl
|
451
|
+
# is
|
452
|
+
# ghi.jkl
|
453
|
+
#
|
454
|
+
def self.basename(path)
|
455
|
+
|
456
|
+
return nil if not path
|
457
|
+
|
458
|
+
# NOTE: we don't implement in terms of split_path
|
459
|
+
# because all but the UNC case work with just
|
460
|
+
# detecting the last (back)slash
|
461
|
+
|
462
|
+
if Recls::Ximpl::OS::OS_IS_WINDOWS
|
463
|
+
wr, rem = Util.get_windows_root(path)
|
464
|
+
|
465
|
+
if not rem
|
466
|
+
return ''
|
467
|
+
else
|
468
|
+
path = rem
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
if not path.is_a? String
|
473
|
+
path = path.to_s
|
474
|
+
end
|
475
|
+
|
476
|
+
if path =~ /^.*[\/\\](.*)/
|
477
|
+
$1
|
478
|
+
else
|
479
|
+
path
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
# obtains the file extension of a basename, e.g.
|
484
|
+
# the file_ext of
|
485
|
+
# ghi.jkl
|
486
|
+
# is
|
487
|
+
# .jkl
|
488
|
+
def self.file_ext(path)
|
489
|
+
|
490
|
+
return nil if not path
|
491
|
+
|
492
|
+
use_split_path = false
|
493
|
+
|
494
|
+
if Recls::Ximpl::OS::OS_IS_WINDOWS
|
495
|
+
if path.include? ?\\
|
496
|
+
use_split_path = true
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
if path.include? ?/
|
501
|
+
use_split_path = true
|
502
|
+
end
|
503
|
+
|
504
|
+
if use_split_path
|
505
|
+
ext = Util.split_path(path)[4]
|
506
|
+
else
|
507
|
+
if path =~ /^.*(\.[^.]*)$/
|
508
|
+
ext = $1
|
509
|
+
else
|
510
|
+
ext = nil
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
return ext ? ext : ''
|
515
|
+
end
|
516
|
+
|
517
|
+
# obtains the directory from the directory path
|
518
|
+
#
|
519
|
+
def self.directory_from_directory_path(directory_path)
|
520
|
+
|
521
|
+
wr, rem = Util.get_windows_root(directory_path)
|
522
|
+
|
523
|
+
rem
|
524
|
+
end
|
525
|
+
|
526
|
+
# obtains the directory parts from a directory
|
527
|
+
def self.directory_parts_from_directory(directory)
|
528
|
+
|
529
|
+
return nil if not directory
|
530
|
+
|
531
|
+
directory_parts = []
|
532
|
+
|
533
|
+
until directory.empty?
|
534
|
+
if directory =~ /^([^\\\/]*[\\\/])/
|
535
|
+
directory_parts << $1
|
536
|
+
directory = $'
|
537
|
+
else
|
538
|
+
directory_parts << directory
|
539
|
+
directory = ''
|
540
|
+
end
|
541
|
+
end
|
542
|
+
|
543
|
+
directory_parts
|
544
|
+
end
|
545
|
+
|
546
|
+
# obtains the relative path of a given path and
|
547
|
+
# a reference directory
|
548
|
+
def self.derive_relative_path(origin, path)
|
549
|
+
|
550
|
+
return nil if path.nil?
|
551
|
+
return nil if path.empty?
|
552
|
+
return path if origin.nil?
|
553
|
+
return path if origin.empty?
|
554
|
+
|
555
|
+
path = self.canonicalise_path path
|
556
|
+
origin = self.canonicalise_path origin
|
557
|
+
|
558
|
+
path_splits = Util.split_path(path)
|
559
|
+
origin_splits = Util.split_path(origin)
|
560
|
+
|
561
|
+
# if different windows root, then cannot provide relative
|
562
|
+
if path_splits[0] and origin_splits[0]
|
563
|
+
return path if path_splits[0] != origin_splits[0]
|
564
|
+
end
|
565
|
+
|
566
|
+
trailing_slash = Util.get_trailing_slash(path)
|
567
|
+
|
568
|
+
path_parts = path_splits[6]
|
569
|
+
origin_parts = origin_splits[6]
|
570
|
+
|
571
|
+
while true
|
572
|
+
|
573
|
+
break if path_parts.empty?
|
574
|
+
break if origin_parts.empty?
|
575
|
+
|
576
|
+
path_part = path_parts[0]
|
577
|
+
origin_part = origin_parts[0]
|
578
|
+
|
579
|
+
if 1 == path_parts.size || 1 == origin_parts.size
|
580
|
+
path_part = Util.append_trailing_slash(path_part)
|
581
|
+
origin_part = Util.append_trailing_slash(origin_part)
|
582
|
+
end
|
583
|
+
|
584
|
+
if path_part == origin_part
|
585
|
+
path_parts.shift
|
586
|
+
origin_parts.shift
|
587
|
+
else
|
588
|
+
break
|
589
|
+
end
|
590
|
+
end
|
591
|
+
|
592
|
+
return ".#{trailing_slash}" if path_parts.empty? and origin_parts.empty?
|
593
|
+
|
594
|
+
# at this point, all reference parts should be converted into '..'
|
595
|
+
|
596
|
+
return origin_parts.map { |rp| '..' }.join('/') if path_parts.empty?
|
597
|
+
|
598
|
+
return '../' * origin_parts.size + path_parts.join('')
|
599
|
+
end
|
600
|
+
|
601
|
+
|
602
|
+
def self.combine_paths(origin, path, options)
|
603
|
+
|
604
|
+
f1_windows_root, f2_directory, f3_basename, dummy1, dummy2, dummy3, dummy4 = Util.split_path(path)
|
605
|
+
|
606
|
+
# return path if f1_windows_root
|
607
|
+
return path if f2_directory && Util.is_path_name_separator(f2_directory[0])
|
608
|
+
|
609
|
+
r = File.join origin, path
|
610
|
+
|
611
|
+
if options[:clean_path]
|
612
|
+
|
613
|
+
r = Pathname.new(r).cleanpath
|
614
|
+
end
|
615
|
+
|
616
|
+
r
|
617
|
+
end
|
618
|
+
|
619
|
+
|
620
|
+
# Elicits the contents of the given directory, or, if the flag
|
621
|
+
# STOP_ON_ACCESS_FAILURE is specified throws an exception if the
|
622
|
+
# directory does not exist
|
623
|
+
#
|
624
|
+
# Some known conditions:
|
625
|
+
#
|
626
|
+
# * (Mac OSX) /dev/fd/<N> - some of these stat() as directories but
|
627
|
+
# Dir.new fails with ENOTDIR
|
628
|
+
#
|
629
|
+
def self.dir_entries_maybe(dir, flags)
|
630
|
+
|
631
|
+
begin
|
632
|
+
|
633
|
+
Dir.new(dir).to_a
|
634
|
+
|
635
|
+
rescue SystemCallError => x
|
636
|
+
|
637
|
+
# TODO this should be filtered up and/or logged
|
638
|
+
|
639
|
+
if(0 != (STOP_ON_ACCESS_FAILURE & flags))
|
640
|
+
raise
|
641
|
+
end
|
642
|
+
|
643
|
+
return []
|
644
|
+
end
|
645
|
+
end
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
# ############################## end of file ############################# #
|
650
|
+
|