diff --git a/lib/puppet/parameter/path.rb b/lib/puppet/parameter/path.rb index 44886afd0..26e4933c7 100644 --- a/lib/puppet/parameter/path.rb +++ b/lib/puppet/parameter/path.rb @@ -1,42 +1,38 @@ require 'puppet/parameter' class Puppet::Parameter::Path < Puppet::Parameter def self.accept_arrays(bool = true) @accept_arrays = !!bool end def self.arrays? @accept_arrays end def validate_path(paths) if paths.is_a?(Array) and ! self.class.arrays? then fail "#{name} only accepts a single path, not an array of paths" end # We *always* support Unix path separators, as Win32 does now too. absolute = "[/#{::Regexp.quote(::File::SEPARATOR)}]" win32 = Puppet.features.microsoft_windows? - Array(paths).each do |path| - next if path =~ %r{^#{absolute}} - next if win32 and path =~ %r{^(?:[a-zA-Z]:)?#{absolute}} - fail("#{name} must be a fully qualified path") - end + fail("#{name} must be a fully qualified path") unless Array(paths).all? {|path| absolute_path?(path)} paths end # This will be overridden if someone uses the validate option, which is why # it just delegates to the other, useful, method. def unsafe_validate(paths) validate_path(paths) end # Likewise, this might be overridden, but by default... def unsafe_munge(paths) if paths.is_a?(Array) and ! self.class.arrays? then fail "#{name} only accepts a single path, not an array of paths" end paths end end diff --git a/spec/lib/puppet_spec/files.rb b/spec/lib/puppet_spec/files.rb index 725bf2af9..86afafbef 100755 --- a/spec/lib/puppet_spec/files.rb +++ b/spec/lib/puppet_spec/files.rb @@ -1,61 +1,61 @@ require 'fileutils' require 'tempfile' require 'pathname' # A support module for testing files. module PuppetSpec::Files # This code exists only to support tests that run as root, pretty much. # Once they have finally been eliminated this can all go... --daniel 2011-04-08 def self.in_tmp(path) tempdir = Dir.tmpdir Pathname.new(path).ascend do |dir| return true if File.identical?(tempdir, dir) end false end def self.cleanup $global_tempfiles ||= [] while path = $global_tempfiles.pop do fail "Not deleting tmpfile #{path} outside regular tmpdir" unless in_tmp(path) begin FileUtils.rm_r path, :secure => true rescue Errno::ENOENT # nothing to do end end end def make_absolute(path) return path unless Puppet.features.microsoft_windows? # REMIND UNC return path if path =~ /^[A-Za-z]:/ pwd = Dir.getwd - return "#{pwd[0,2]}#{path}" if pwd.length > 2 and pwd =~ /^[A-Za-z]:/ + return "#{pwd[0,2]}#{path}" if pwd =~ /^[A-Za-z]:/ return "C:#{path}" end def tmpfile(name) # Generate a temporary file, just for the name... source = Tempfile.new(name) path = source.path source.close! # ...record it for cleanup, $global_tempfiles ||= [] $global_tempfiles << File.expand_path(path) # ...and bam. path end def tmpdir(name) path = tmpfile(name) FileUtils.mkdir_p(path) path end end diff --git a/spec/shared_behaviours/path_parameters.rb b/spec/shared_behaviours/path_parameters.rb index b5a907900..bdcd4cf25 100755 --- a/spec/shared_behaviours/path_parameters.rb +++ b/spec/shared_behaviours/path_parameters.rb @@ -1,185 +1,187 @@ # In order to use this correctly you must define a method to get an instance # of the type being tested, so that this code can remain generic: # # it_should_behave_like "all path parameters", :path do # def instance(path) # Puppet::Type.type(:example).new( # :name => 'foo', :require => 'bar', :path_param => path # ) # end # # That method will be invoked for each test to create the instance that we # subsequently test through the system; you should ensure that the minimum of # possible attributes are set to keep the tests clean. # # You must also pass the symbolic name of the parameter being tested to the # block, and optionally can pass a hash of additional options to the block. # # The known options are: # :array :: boolean, does this support arrays of paths, default true. shared_examples_for "all pathname parameters with arrays" do |win32| path_types = { - "unix absolute" => "/foo/bar", - "unix relative" => "foo/bar", - "win32 absolute" => %q{\foo\bar}, - "win32 relative" => %q{foo\bar}, - "drive absolute" => %q{c:\foo\bar}, - "drive relative" => %q{c:foo\bar} + "unix absolute" => %q{/foo/bar}, + "unix relative" => %q{foo/bar}, + "win32 non-drive absolute" => %q{\foo\bar}, + "win32 non-drive relative" => %q{foo\bar}, + "win32 drive absolute" => %q{c:\foo\bar}, + "win32 drive relative" => %q{c:foo\bar} } describe "when given an array of paths" do (1..path_types.length).each do |n| path_types.keys.combination(n) do |set| data = path_types.collect { |k, v| set.member?(k) ? v : nil } .compact - reject = true - only_absolute = set.find { |k| k =~ /relative/ } .nil? - only_unix = set.reject { |k| k =~ /unix/ } .length == 0 - if only_absolute and (only_unix or win32) then + has_relative = set.find { |k| k =~ /relative/ or k =~ /non-drive/ } + has_windows = set.find { |k| k =~ /win32/ } + has_unix = set.find { |k| k =~ /unix/ } + + if has_relative or (has_windows and !win32) or (has_unix and win32) + reject = true + else reject = false end it "should #{reject ? 'reject' : 'accept'} #{set.join(", ")}" do if reject then expect { instance(data) }. should raise_error Puppet::Error, /fully qualified/ else instance = instance(data) instance[@param].should == data end end it "should #{reject ? 'reject' : 'accept'} #{set.join(", ")} doubled" do if reject then expect { instance(data + data) }. should raise_error Puppet::Error, /fully qualified/ else instance = instance(data + data) instance[@param].should == (data + data) end end end end end end shared_examples_for "all path parameters" do |param, options| # Extract and process options to the block. options ||= {} array = options[:array].nil? ? true : options.delete(:array) if options.keys.length > 0 then fail "unknown options for 'all path parameters': " + options.keys.sort.join(', ') end def instance(path) fail "we didn't implement the 'instance(path)' method in the it_should_behave_like block" end ######################################################################## # The actual testing code... before :all do @param = param end before :each do @file_separator = File::SEPARATOR end after :each do with_verbose_disabled do verbose, $VERBOSE = $VERBOSE, nil File::SEPARATOR = @file_separator $VERBOSE = verbose end end describe "on a Unix-like platform it" do before :each do with_verbose_disabled do File::SEPARATOR = '/' end Puppet.features.stubs(:microsoft_windows?).returns(false) Puppet.features.stubs(:posix?).returns(true) end if array then it_should_behave_like "all pathname parameters with arrays", false end it "should accept a fully qualified path" do path = File.join('', 'foo') instance = instance(path) instance[@param].should == path end it "should give a useful error when the path is not absolute" do path = 'foo' expect { instance(path) }. should raise_error Puppet::Error, /fully qualified/ end { "Unix" => '/', "Win32" => '\\' }.each do |style, slash| %w{q Q a A z Z c C}.sort.each do |drive| it "should reject drive letter '#{drive}' with #{style} path separators" do path = "#{drive}:#{slash}Program Files" expect { instance(path) }. should raise_error Puppet::Error, /fully qualified/ end end end end describe "on a Windows-like platform it" do before :each do with_verbose_disabled do File::SEPARATOR = '\\' end Puppet.features.stubs(:microsoft_windows?).returns(true) Puppet.features.stubs(:posix?).returns(false) end if array then it_should_behave_like "all pathname parameters with arrays", true end - it "should accept a fully qualified path" do - path = File.join('', 'foo') - instance = instance(path) - instance[@param].should == path + it "should reject a fully qualified unix path" do + path = '/foo' + expect { instance(path) }.to raise_error(Puppet::Error, /fully qualified/) end it "should give a useful error when the path is not absolute" do path = 'foo' expect { instance(path) }. should raise_error Puppet::Error, /fully qualified/ end it "also accepts Unix style path separators" do - path = '/Program Files' + path = 'C:/Program Files' instance = instance(path) instance[@param].should == path end { "Unix" => '/', "Win32" => '\\' }.each do |style, slash| %w{q Q a A z Z c C}.sort.each do |drive| it "should accept drive letter '#{drive}' with #{style} path separators " do path = "#{drive}:#{slash}Program Files" instance = instance(path) instance[@param].should == path end end end - { "UNC paths" => %q{\\foo\bar}, - "unparsed local paths" => %q{\\?\c:\foo}, - "unparsed UNC paths" => %q{\\?\foo\bar} + { "UNC paths" => %q{\\\\foo\bar}, + "unparsed local paths" => %q{\\\\?\c:\foo}, + "unparsed UNC paths" => %q{\\\\?\foo\bar} }.each do |name, path| it "should accept #{name} as absolute" do instance = instance(path) instance[@param].should == path end end end end