code: def runner(self, jvm_options=None, args=None, executor=None):
      
      args = args or []
      if self._ivy_settings and '-settings' not in args:
        args = ['-settings', self._ivy_settings] + args
  
      options = list(jvm_options) if jvm_options else []
      if self._ivy_resolution_cache_dir and '-cache' not in args:
        # TODO(John Sirois): Currently this is a magic property to support hand-crafted <caches/> in
        # ivysettings.xml.  Ideally we'd support either simple -caches or these hand-crafted cases
        # instead of just hand-crafted.  Clean this up by taking over ivysettings.xml and generating
        # it from BUILD constructs.
        options += ['-Divy.cache.dir={}'.format(self._ivy_resolution_cache_dir)]
      options += self._extra_jvm_options
  
      executor = executor or SubprocessExecutor(DistributionLocator.cached())
      if not isinstance(executor, Executor):
        raise ValueError('The executor argument must be an Executor instance, given {} of type {}'.format(
                           executor, type(executor)))
  
      return executor.runner(classpath=self._classpath, main='org.apache.ivy.Main',
                             jvm_options=options, args=args)
docs: Creates an ivy commandline client runner for the given args.