# frozen_string_literal: true

module Puppet
  Puppet::Type.type(:file).newproperty(:target) do
    desc "The target for creating a link.  Currently, symlinks are the
      only type supported. This attribute is mutually exclusive with `source`
      and `content`.

      Symlink targets can be relative, as well as absolute:

          # (Useful on Solaris)
          file { '/etc/inetd.conf':
            ensure => link,
            target => 'inet/inetd.conf',
          }

      Directories of symlinks can be served recursively by instead using the
      `source` attribute, setting `ensure` to `directory`, and setting the
      `links` attribute to `manage`."

    newvalue(:notlink) do
      # We do nothing if the value is absent
      return :nochange
    end

    # Anything else, basically
    newvalue(/./) do
      @resource[:ensure] = :link unless @resource.should(:ensure)

      # Only call mklink if ensure didn't call us in the first place.
      currentensure = @resource.property(:ensure).retrieve
      mklink if @resource.property(:ensure).safe_insync?(currentensure)
    end

    # Create our link.
    def mklink
      raise Puppet::Error, "Cannot symlink on this platform version" unless provider.feature?(:manages_symlinks)

      target = should

      # Clean up any existing objects.  The argument is just for logging,
      # it doesn't determine what's removed.
      @resource.remove_existing(target)

      raise Puppet::Error, "Could not remove existing file" if Puppet::FileSystem.exist?(@resource[:path])

      Puppet::Util::SUIDManager.asuser(@resource.asuser) do
        mode = @resource.should(:mode)
        if mode
          Puppet::Util.withumask(0o00) do
            Puppet::FileSystem.symlink(target, @resource[:path])
          end
        else
          Puppet::FileSystem.symlink(target, @resource[:path])
        end
      end

      @resource.send(:property_fix)

      :link_created
    end

    def insync?(currentvalue)
      if [:nochange, :notlink].include?(should) or @resource.recurse?
        true
      elsif !@resource.replace? and Puppet::FileSystem.exist?(@resource[:path])
        true
      else
        super(currentvalue)
      end
    end

    def retrieve
      stat = @resource.stat
      if stat
        if stat.ftype == "link"
          Puppet::FileSystem.readlink(@resource[:path])
        else
          :notlink
        end
      else
        :absent
      end
    end
  end
end
