docs: def file(name,
           source_hash='',
           source_hash_name=None,
           user='root',
           template=None,
           context=None,
           replace=True,
           defaults=None,
           backup='',
           **kwargs):
      '''
      Provides file.managed-like functionality (templating, etc.) for a pre-made
      crontab file, to be assigned to a given user.
  
      name
          The source file to be used as the crontab. This source file can be
          hosted on either the salt master server, or on an HTTP or FTP server.
          For files hosted on the salt file server, if the file is located on
          the master in the directory named spam, and is called eggs, the source
          string is ``salt://spam/eggs``
  
          If the file is hosted on a HTTP or FTP server then the source_hash
          argument is also required
  
      source_hash
          This can be either a file which contains a source hash string for
          the source, or a source hash string. The source hash string is the
          hash algorithm followed by the hash of the file:
          ``md5=e138491e9d5b97023cea823fe17bac22``
  
      source_hash_name
          When ``source_hash`` refers to a hash file, Salt will try to find the
          correct hash by matching the filename/URI associated with that hash. By
          default, Salt will look for the filename being managed. When managing a
          file at path ``/tmp/foo.txt``, then the following line in a hash file
          would match:
  
          .. code-block:: text
  
              acbd18db4cc2f85cedef654fccc4a4d8    foo.txt
  
          However, sometimes a hash file will include multiple similar paths:
  
          .. code-block:: text
  
              37b51d194a7513e45b56f6524f2d51f2    ./dir1/foo.txt
              acbd18db4cc2f85cedef654fccc4a4d8    ./dir2/foo.txt
              73feffa4b7f6bb68e44cf984c85f6e88    ./dir3/foo.txt
  
          In cases like this, Salt may match the incorrect hash. This argument
          can be used to tell Salt which filename to match, to ensure that the
          correct hash is identified. For example:
  
          .. code-block:: yaml
  
              foo_crontab:
                cron.file:
                  - name: https://mydomain.tld/dir2/foo.txt
                  - source_hash: https://mydomain.tld/hashes
                  - source_hash_name: ./dir2/foo.txt
  
          .. note::
              This argument must contain the full filename entry from the
              checksum file, as this argument is meant to disambiguate matches
              for multiple files that have the same basename. So, in the
              example above, simply using ``foo.txt`` would not match.
  
          .. versionadded:: 2016.3.5
  
      user
          The user to whom the crontab should be assigned. This defaults to
          root.
  
      template
          If this setting is applied then the named templating engine will be
          used to render the downloaded file. Currently, jinja and mako are
          supported.
  
      context
          Overrides default context variables passed to the template.
  
      replace
          If the crontab should be replaced, if False then this command will
          be ignored if a crontab exists for the specified user. Default is True.
  
      defaults
          Default context passed to the template.
  
      backup
          Overrides the default backup mode for the user's crontab.
      '''
      # Initial set up
      mode = '0600'
  
      try:
          group = __salt__['user.info'](user)['groups'][0]
      except Exception:
          ret = {'changes': {},
                 'comment': "Could not identify group for user {0}".format(user),
                 'name': name,
                 'result': False}
          return ret
  
      cron_path = salt.utils.files.mkstemp()
      with salt.utils.files.fopen(cron_path, 'w+') as fp_:
          raw_cron = __salt__['cron.raw_cron'](user)
          if not raw_cron.endswith('\n'):
              raw_cron = "{0}\n".format(raw_cron)
          fp_.write(salt.utils.stringutils.to_str(raw_cron))
  
      ret = {'changes': {},
             'comment': '',
             'name': name,
             'result': True}
  
      # Avoid variable naming confusion in below module calls, since ID
      # declaration for this state will be a source URI.
      source = name
  
      if not replace and os.stat(cron_path).st_size > 0:
          ret['comment'] = 'User {0} already has a crontab. No changes ' \
                           'made'.format(user)
          os.unlink(cron_path)
          return ret
  
      if __opts__['test']:
          fcm = __salt__['file.check_managed'](name=cron_path,
                                               source=source,
                                               source_hash=source_hash,
                                               source_hash_name=source_hash_name,
                                               user=user,
                                               group=group,
                                               mode=mode,
                                               attrs=[],  # no special attrs for cron
                                               template=template,
                                               context=context,
                                               defaults=defaults,
                                               saltenv=__env__,
                                               **kwargs
                                               )
          ret['result'], ret['comment'] = fcm
          os.unlink(cron_path)
          return ret
  
      # If the source is a list then find which file exists
      source, source_hash = __salt__['file.source_list'](source,
                                                         source_hash,
                                                         __env__)
  
      # Gather the source file from the server
      try:
          sfn, source_sum, comment = __salt__['file.get_managed'](
              name=cron_path,
              template=template,
              source=source,
              source_hash=source_hash,
              source_hash_name=source_hash_name,
              user=user,
              group=group,
              mode=mode,
              attrs=[],
              saltenv=__env__,
              context=context,
              defaults=defaults,
              skip_verify=False,        # skip_verify
              **kwargs
          )
      except Exception as exc:
          ret['result'] = False
          ret['changes'] = {}
          ret['comment'] = 'Unable to manage file: {0}'.format(exc)
          return ret
  
      if comment:
          ret['comment'] = comment
          ret['result'] = False
          os.unlink(cron_path)
          return ret
  
      try:
          ret = __salt__['file.manage_file'](
              name=cron_path,
              sfn=sfn,
              ret=ret,
              source=source,
              source_sum=source_sum,
              user=user,
              group=group,
              mode=mode,
              attrs=[],
              saltenv=__env__,
              backup=backup
          )
      except Exception as exc:
          ret['result'] = False
          ret['changes'] = {}
          ret['comment'] = 'Unable to manage file: {0}'.format(exc)
          return ret
  
      cron_ret = None
      if "diff" in ret['changes']:
          cron_ret = __salt__['cron.write_cron_file_verbose'](user, cron_path)
          # Check cmd return code and show success or failure
          if cron_ret['retcode'] == 0:
              ret['comment'] = 'Crontab for user {0} was updated'.format(user)
              ret['result'] = True
              ret['changes'] = ret['changes']
          else:
              ret['comment'] = 'Unable to update user {0} crontab {1}.' \
                               ' Error: {2}'.format(user, cron_path, cron_ret['stderr'])
              ret['result'] = False
              ret['changes'] = {}
      elif ret['result']:
          ret['comment'] = 'Crontab for user {0} is in the correct ' \
                           'state'.format(user)
          ret['changes'] = {}
  
      os.unlink(cron_path)
      return ret