Class: Knife::Windows::PathHelper
- Inherits:
-
Object
- Object
- Knife::Windows::PathHelper
- Defined in:
- lib/knife-windows/path_helper.rb
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.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/knife-windows/path_helper.rb', line 106 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
127 128 129 130 131 132 133 134 |
# File 'lib/knife-windows/path_helper.rb', line 127 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
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/knife-windows/path_helper.rb', line 28 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
143 144 145 146 |
# File 'lib/knife-windows/path_helper.rb', line 143 def self.escape_glob(*parts) path = cleanpath(join(*parts)) path.gsub(/[\\\{\}\[\]\*\?]/) { |x| "\\"+x } end |
.join(*args) ⇒ Object
57 58 59 60 61 62 63 64 |
# File 'lib/knife-windows/path_helper.rb', line 57 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
49 50 51 52 53 54 55 |
# File 'lib/knife-windows/path_helper.rb', line 49 def self.path_separator if Chef::Platform.windows? File::ALT_SEPARATOR || BACKSLASH else File::SEPARATOR end end |
.paths_eql?(path1, path2) ⇒ Boolean
136 137 138 |
# File 'lib/knife-windows/path_helper.rb', line 136 def self.paths_eql?(path1, path2) canonical_path(path1) == canonical_path(path2) end |
.printable?(string) ⇒ Boolean
95 96 97 98 99 100 101 102 103 |
# File 'lib/knife-windows/path_helper.rb', line 95 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
148 149 150 |
# File 'lib/knife-windows/path_helper.rb', line 148 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
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/knife-windows/path_helper.rb', line 66 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
83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/knife-windows/path_helper.rb', line 83 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 |