Class: Chef::Util::PathHelper
Constant Summary collapse
- WIN_MAX_PATH =
Maximum characters in a standard Windows path (260 including drive letter and NUL)
259
- BACKSLASH =
'\\'.freeze
Class Method Summary collapse
-
.canonical_path(path, add_prefix = true) ⇒ Object
Produces a comparable path.
- .cleanpath(path) ⇒ Object
- .dirname(path) ⇒ Object
-
.escape_glob(*parts) ⇒ Object
Paths which may contain glob-reserved characters need to be escaped before globbing can be done.
- .join(*args) ⇒ Object
- .path_separator ⇒ Object
- .paths_eql?(path1, path2) ⇒ Boolean
- .printable?(string) ⇒ Boolean
- .relative_path_from(from, to) ⇒ Object
- .validate_path(path) ⇒ Object
- .windows_max_length_exceeded?(path) ⇒ Boolean
Class Method Details
.canonical_path(path, add_prefix = true) ⇒ Object
Produces a comparable path.
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/chef/util/path_helper.rb', line 103 def self.canonical_path(path, add_prefix=true) # Rather than find an equivalent for File.absolute_path on 1.8.7, just bail out raise NotImplementedError, "This feature is not supported on Ruby versions < 1.9" if RUBY_VERSION.to_f < 1.9 # First remove extra separators and resolve any relative paths abs_path = File.absolute_path(path) if Chef::Platform.windows? # Add the \\?\ API prefix on Windows unless add_prefix is false # Downcase on Windows where paths are still case-insensitive abs_path.gsub!(::File::SEPARATOR, path_separator) if add_prefix && abs_path !~ /^\\\\?\\/ abs_path.insert(0, "\\\\?\\") end abs_path.downcase! end abs_path end |
.cleanpath(path) ⇒ Object
124 125 126 127 128 129 130 131 |
# File 'lib/chef/util/path_helper.rb', line 124 def self.cleanpath(path) path = Pathname.new(path).cleanpath.to_s # ensure all forward slashes are backslashes if Chef::Platform.windows? path = path.gsub(File::SEPARATOR, path_separator) end path end |
.dirname(path) ⇒ Object
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/chef/util/path_helper.rb', line 25 def self.dirname(path) if Chef::Platform.windows? # Find the first slash, not counting trailing slashes end_slash = path.size while true slash = path.rindex(/[#{Regexp.escape(File::SEPARATOR)}#{Regexp.escape(path_separator)}]/, end_slash - 1) if !slash return end_slash == path.size ? '.' : path_separator elsif slash == end_slash - 1 end_slash = slash else return path[0..slash-1] end end else ::File.dirname(path) end end |
.escape_glob(*parts) ⇒ Object
Paths which may contain glob-reserved characters need to be escaped before globbing can be done. stackoverflow.com/questions/14127343
140 141 142 143 |
# File 'lib/chef/util/path_helper.rb', line 140 def self.escape_glob(*parts) path = cleanpath(join(*parts)) path.gsub(/[\\\{\}\[\]\*\?]/) { |x| "\\"+x } end |
.join(*args) ⇒ Object
54 55 56 57 58 59 60 61 |
# File 'lib/chef/util/path_helper.rb', line 54 def self.join(*args) args.flatten.inject do |joined_path, component| # Joined path ends with / joined_path = joined_path.sub(/[#{Regexp.escape(File::SEPARATOR)}#{Regexp.escape(path_separator)}]+$/, '') component = component.sub(/^[#{Regexp.escape(File::SEPARATOR)}#{Regexp.escape(path_separator)}]+/, '') joined_path += "#{path_separator}#{component}" end end |
.path_separator ⇒ Object
46 47 48 49 50 51 52 |
# File 'lib/chef/util/path_helper.rb', line 46 def self.path_separator if Chef::Platform.windows? File::ALT_SEPARATOR || BACKSLASH else File::SEPARATOR end end |
.paths_eql?(path1, path2) ⇒ Boolean
133 134 135 |
# File 'lib/chef/util/path_helper.rb', line 133 def self.paths_eql?(path1, path2) canonical_path(path1) == canonical_path(path2) end |
.printable?(string) ⇒ Boolean
92 93 94 95 96 97 98 99 100 |
# File 'lib/chef/util/path_helper.rb', line 92 def self.printable?(string) # returns true if string is free of non-printable characters (escape sequences) # this returns false for whitespace escape sequences as well, e.g. \n\t if string =~ /[^[:print:]]/ false else true end end |
.relative_path_from(from, to) ⇒ Object
145 146 147 |
# File 'lib/chef/util/path_helper.rb', line 145 def self.relative_path_from(from, to) pathname = Pathname.new(Chef::Util::PathHelper.cleanpath(to)).relative_path_from(Pathname.new(Chef::Util::PathHelper.cleanpath(from))) end |
.validate_path(path) ⇒ Object
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/chef/util/path_helper.rb', line 63 def self.validate_path(path) if Chef::Platform.windows? unless printable?(path) msg = "Path '#{path}' contains non-printable characters. Check that backslashes are escaped with another backslash (e.g. C:\\\\Windows) in double-quoted strings." Chef::Log.error(msg) raise Chef::Exceptions::ValidationFailed, msg end if windows_max_length_exceeded?(path) Chef::Log.debug("Path '#{path}' is longer than #{WIN_MAX_PATH}, prefixing with'\\\\?\\'") path.insert(0, "\\\\?\\") end end path end |
.windows_max_length_exceeded?(path) ⇒ Boolean
80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/chef/util/path_helper.rb', line 80 def self.windows_max_length_exceeded?(path) # Check to see if paths without the \\?\ prefix are over the maximum allowed length for the Windows API # http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx unless path =~ /^\\\\?\\/ if path.length > WIN_MAX_PATH return true end end false end |