Class: Chef::ChefFS::PathUtils
- Inherits:
-
Object
- Object
- Chef::ChefFS::PathUtils
- Defined in:
- lib/chef/chef_fs/path_utils.rb
Class Method Summary collapse
-
.descendant_path(path, ancestor) ⇒ Object
Given two general OS-dependent file paths, determines the relative path of the child with respect to the ancestor.
-
.is_absolute?(path) ⇒ Boolean
Given a server path, determines if it is absolute.
-
.join(*parts) ⇒ Object
A Chef-FS path is a path in a chef-repository that can be used to address both files on a local file-system as well as objects on a chef server.
-
.os_path_eq?(left, right) ⇒ Boolean
Compares two path fragments according to the case-sentitivity of the host platform.
-
.realest_path(path, cwd = Dir.pwd) ⇒ Object
Given a path which may only be partly real (i.e. /x/y/z when only /x exists, or /x/y/*/blah when /x/y/z/blah exists), call File.realpath on the biggest part that actually exists.
- .regexp_path_separator ⇒ Object
- .split(path) ⇒ Object
Class Method Details
.descendant_path(path, ancestor) ⇒ Object
Given two general OS-dependent file paths, determines the relative path of the child with respect to the ancestor. Both child and ancestor must exist and be fully resolved - this is strictly a lexical comparison. No trailing slashes and other shenanigans are allowed.
TODO: Move this to util/path_helper.
115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/chef/chef_fs/path_utils.rb', line 115 def self.descendant_path(path, ancestor) candidate_fragment = path[0, ancestor.length] return nil unless PathUtils.os_path_eq?(candidate_fragment, ancestor) if ancestor.length == path.length "" elsif path[ancestor.length, 1] =~ /#{PathUtils.regexp_path_separator}/ path[ancestor.length + 1..-1] else nil end end |
.is_absolute?(path) ⇒ Boolean
Given a server path, determines if it is absolute.
65 66 67 |
# File 'lib/chef/chef_fs/path_utils.rb', line 65 def self.is_absolute?(path) !!(path =~ /^#{regexp_path_separator}/) end |
.join(*parts) ⇒ Object
A Chef-FS path is a path in a chef-repository that can be used to address both files on a local file-system as well as objects on a chef server. These paths are stricter than file-system paths allowed on various OSes. Absolute Chef-FS paths begin with “/” (on windows, “" is acceptable as well). ”/“ is used as the path element separator (on windows, ”" is acceptable as well). No directory/path element may contain a literal “" character. Any such characters encountered are either dealt with as separators (on windows) or as escape characters (on POSIX systems). Relative Chef-FS paths may use ”..“ or ”.“ but may never use these to back-out of the root of a Chef-FS path. Any such extraneous ”..“s are ignored. Chef-FS paths are case sensitive (since the paths on the server are). On OSes with case insensitive paths, you may be unable to locally deal with two objects whose server paths only differ by case. OTOH, the case of path segments that are outside the Chef-FS root (such as when looking at a file-system absolute path to discover the Chef-FS root path) are handled in accordance to the rules of the local file-system and OS.
43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/chef/chef_fs/path_utils.rb', line 43 def self.join(*parts) return "" if parts.length == 0 # Determine if it started with a slash absolute = parts[0].length == 0 || parts[0].length > 0 && parts[0] =~ /^#{regexp_path_separator}/ # Remove leading and trailing slashes from each part so that the join will work (and the slash at the end will go away) parts = parts.map { |part| part.gsub(/^#{regexp_path_separator}+|#{regexp_path_separator}+$/, "") } # Don't join empty bits result = parts.select { |part| part != "" }.join("/") # Put the / back on absolute ? "/#{result}" : result end |
.os_path_eq?(left, right) ⇒ Boolean
Compares two path fragments according to the case-sentitivity of the host platform.
105 106 107 |
# File 'lib/chef/chef_fs/path_utils.rb', line 105 def self.os_path_eq?(left, right) ChefUtils.windows? ? left.casecmp(right) == 0 : left == right end |
.realest_path(path, cwd = Dir.pwd) ⇒ Object
Given a path which may only be partly real (i.e. /x/y/z when only /x exists, or /x/y/*/blah when /x/y/z/blah exists), call File.realpath on the biggest part that actually exists. The paths operated on here are not Chef-FS paths. These are OS paths that may contain symlinks but may not also fully exist.
If /x is a symlink to /blarghle, and has no subdirectories, then: PathUtils.realest_path(‘/x/y/z’) == ‘/blarghle/y/z’ PathUtils.realest_path(‘/x/*/z’) == ‘/blarghle/*/z’ PathUtils.realest_path(‘/*/y/z’) == ‘/*/y/z’
TODO: Move this to wherever util/path_helper is these days.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/chef/chef_fs/path_utils.rb', line 80 def self.realest_path(path, cwd = Dir.pwd) path = File.(path, cwd) parent_path = File.dirname(path) suffix = [] # File.dirname happens to return the path as its own dirname if you're # at the root (such as at \\foo\bar, C:\ or /) until parent_path == path # This can occur if a path such as "C:" is given. Ruby gives the parent as "C:." # for reasons only it knows. raise ArgumentError "Invalid path segment #{path}" if parent_path.length > path.length begin path = File.realpath(path) break rescue Errno::ENOENT, Errno::EINVAL suffix << File.basename(path) path = parent_path parent_path = File.dirname(path) end end File.join(path, *suffix.reverse) end |
.regexp_path_separator ⇒ Object
60 61 62 |
# File 'lib/chef/chef_fs/path_utils.rb', line 60 def self.regexp_path_separator ChefUtils.windows? ? '[\/\\\\]' : "/" end |
.split(path) ⇒ Object
56 57 58 |
# File 'lib/chef/chef_fs/path_utils.rb', line 56 def self.split(path) path.split(Regexp.new(regexp_path_separator)) end |