(#12790) Raise an exception if recursion is detected

Facter can already detect fact dependency cycles (fact recursions).

Without this patch facter will return nil (or an already cached value)
as a factvalue when a recursion is detected. This can silently break
things. Example

    Facter.add(:foo)
      if Facter.value(:bar) != 'baz'
        something happens here
      end
    end

If there is now a recursion when querying the bar fact we will always
execute the following codeblock (nil != baz). This may lead to strange
and inexplicable results for the foo fact.

The fix now changes the behaviour when a recursion is detected: Do not
just print a debug message but throw an error. This way a recursion is
a lot easier to detect and we can actually fix it.
[#11299] Replace facter/util/plist with cfpropertylist

Previously, the facter/util/plist library was used for plist
manipulation in OS X. This library could only handle XML plists, and
thus we needed to convert every possible plist that Facter could read to
XML before reading it. This incurred a great speed hit for anyone using
Facter with OS X.

The CFPropertyList project (https://github.com/ckruse/cfpropertylist),
maintained by Christian Kruse, is a library that can not only read XML
and Binary plist files, but also can use either the libxml, nokogiri, or
built-in REXML library to do so. This is ideal as the libxml library can
utilize c extensions to do the reading/converty and thus is quite fast.

This commit introduces the CFPropertyList project into the puppet/util
namespace, and refactors all code to use this library. The version committed
into Facter is 2.1 of the CFPropertyList library.
Merge branch '1.6.x'

* 1.6.x:
  (#12831) Add rspec tests to have_which method in Resolution
  (#12831) Fix recursion on first kernel fact resolution
  Update CHANGELOG for Facter 1.6.7
  Updating CHANGELOG and lib/facter.rb for Facter 1.6.7rc1
(#13678) Convert command to absolute paths before executing

The former behaviour of facter is to allow passing commands to
Facter::Util::Resolution.exec where the executable is not an absolute
pathname. To check if the executable is present on the system facter would
then run %{which commandname}. As a result we end up with two shell
invocations just to run a single command.

The fix now tries to convert the executable of the command into an
absolute pathname so we can easiliy check with the File.executable?
method if we can try to run the command.

The two methods `which` and `absolute_path?` are adopted from puppet
which claim to run on both windows and unix systems. This is great
because we do not have to distinct between the platforms in the exec
method anymore.
(#13678) Add RDoc documentation for new methods

The refactor on #13678 introduced new methods:

    Facter::Util::Resolution::search_paths
    Facter::Util::Resolution::which
    Facter::Util::Resolution::absolute_path?
    Facter::Util::Resolution::expand_command

Add documentation for those.
(#13678) Add more unit tests for new methods

There is currently one bug in `expand_command` shown by a test marked as
pending:

When `expand_command` is run with e.g. "foo.exe" `expand_command` tries to
replace the binary foo.exe with a full path to foo. If foo is now found
in a path that contains spaces, `expand_command` doesn't escape these.

So `expand_command('foo.exe /a')` might return `C:\My Tools\foo.exe /a` when
it probably should return `"C:\My Tools\foo.exe" /a`
(#13678) Fix quoting in expand_command

If the expand_command method is called with a commandline where the
binary is not specified with as an absolute pathname, expand_command
will determine the absolute pathname by calling the `which` method. The
full pathname to the binary may include spaces (especially on windows).

Since expand_command should return a commandline that is ready to be run by
the shell it has to add quotes around the binary if the pathname contains
spaces.
(#13678) Fix spec failures on windows

Facter now tries to expand commands before running them. As a sideeffect
we can no longer run shell-builtins directly since facter is not able to
find it in the filesystem. This broke a few spec tests that assumed we
can run "echo foo" on both unix and windows.

The fix now explicitly calls the shell (cmd.exe) to run the echo
builtin. On Unix we already have a native echo (most likely /bin/echo).

Note: The former implementation did allow windows builtins but did not
allow unix buildins because the former implementation used `which` to
check if we can run a command on unix and `which` does not work on
builtins.
Namespace CFPropertyList under Puppet::Util

Previously, the code inserted into lib/puppet/util/cfpropertylist was
still being namespaced as 'CFPropertyList'.  Since CFPropertyList also
exists as Rubygem, Puppet could potentially call a different version of
CFPropertyList than the version that's been inserted into the
lib/puppet/util/cfpropertylist directory.  To remedy this, the
library has been namespaced as Puppet::Util::CFPropertylist and all code and
tests have been changed.
maint: Add shared context for specs to imitate windows or posix

Add "windows" and "posix" shared contexts to rspec. The shared context
was borrowed from the puppet codebase. If you give :as_platform =>
:posix or :as_platform => :windows as an argument to a describe block or
a context block, it will stub is_windows, File::SEPARATOR, and
File::ALT_SEPARATOR. In addition to puppets shared_context it will also
stub File::PATH_SEPARATOR
(#13678) Extend spec tests for expand_command

The spec tests for expand_command and exec were restructured to make use
of the new shared_beviour :as_platform to have more accurate tests and
were also restructured to reduce code duplication.

These reveal a few open issues:

* on windows, facter should continue to support shell buildins which is
  currently not the case
* on unix, facter should quote binaries that are found in a path with
  spaces in single quotes, not double quotes
* on windows, we trusted File.join('C:','Windows') to return C:\Windows
  which is not the case. File.join uses File::SEPARATOR ('/' on windows)
  and not File::ALT_SEPARATOR ('\' on windows).

The issues will be addressed in a following commit
(#13678) Join PATHs correctly on windows

On windows File.join joins with the File::SEPARATOR which is '/' on
windows. While a lot of the windows API and the ruby filetests allow
/ as a separator we should use File::ALT_SEPARATOR ('\' on windows) to
create pathnames on windows
(#13678) Single quote paths on unix with spaces

If we want to execute a command foo which is found in a path with spaces
we have to quote the path in order to be able to pass the command to the
shell.

Instead of using double quotes we should use single quotes on unix. On
windows only double quotes are valid
Merge branch '1.6.x'

* 1.6.x:
  Update CHANGELOG for Facter 1.6.8
  Update CHANGELOG lib/facter.rb for 1.6.8rc1
(#13678) Allow passing shell built-ins to exec method on windows

The former exec method tried to run the command on windows no matter
wether it could be found on the filesystem or not. This allowed end
users to run shell-builtins with the exec method.

The new exec method always tried to expand the binary first and returned
nil if the binary was not found. This commit now restores the old
behaviour on windows: Even if we fail to expand the command, we will try
to run the command in the exact same way as it was passed to the exec
method in case it is indeed a shell built-in. But we will now raise a
deprecation warning.

Reason for deprecating this "even if we cannot find it, just run it"
behaviour: We may want to predetermine the paths where facter tries to find
binaries in the future. A fall back behaviour may then lead to strange
results. Most built-ins can be expressed in pure ruby anyways.
(#12864) Windows: get primary DNS from registry

Windows does not expose the host's primary DNS suffix via WMI, only the
registry. This commit adds a registry helper class and will retrieve the
primary DNS suffix from the registry. In the case the primary DNS suffix
does not exist or is empty, the domain fact will fall back to using WMI
for any connection-specific DNS suffix.
Merge branch 'ticket/master/12864_windows_primary_dns_suffix'

* ticket/master/12864_windows_primary_dns_suffix:
  (#12864) Windows: get primary DNS from registry
(#7484) Domain fact should handle only TLD

Prior to this commit, the domain fact executed "hostname" on all platforms,
however the default on Linux is that "hostname" does not return FQDN.
This causes problems when the machine only has a TLD, rather than being
in a second level domain. For example, ns01.tld vs ns01.puppetlabs.com.

This commit fixes that issue, and handles the case where hostname does
not accept the -f option on Solaris.
(#7484) Domain Fact should handle TLD

Before this commit, using hostname -f was opt-out. With this commit
it has been changed to be opt-in, to prevent problems on certain
operating systems like Solaris and HP-UX.
(#3226) Strip whitespace from fact

Prior to this commit, Facter was not removing trailing or leading
whitespace from facts. This change normalizes all facts by
stripping whitespace. However, since in some custom facts trailing
and leading whitespace may be essential, it is possible to opt
out of stripping the whitespace on certain facts.