class_docstr: Creates a sibling to a dataset in a RIA store
  
  Communication with a dataset in a RIA store is implemented via two
  siblings. A regular Git remote (repository sibling) and a git-annex
  special remote for data transfer (storage sibling) -- with the former
  having a publication dependency on the latter. By default, the name of the
  storage sibling is derived from the repository sibling's name by appending
  "-storage".
  
  The store's base path is expected to not exist, be an empty directory,
  or a valid RIA store.
  
  Notes
  -----
  
  
  **RIA URL format**
  
  Interactions with new or existing RIA stores require RIA URLs to identify
  the store or specific datasets inside of it.
  
  The general structure of a RIA URL pointing to a store takes the form
  ``ria+[scheme]://<storelocation>`` (e.g.,
  ``ria+ssh://[user@]hostname:/absolute/path/to/ria-store``, or
  ``ria+file:///absolute/path/to/ria-store``)
  
  The general structure of a RIA URL pointing to a dataset in a store (for
  example for cloning) takes a similar form, but appends either the datasets
  UUID or a "~" symbol followed by the dataset's alias name:
  ``ria+[scheme]://<storelocation>#<dataset-UUID>`` or
  ``ria+[scheme]://<storelocation>#~<aliasname>``.
  In addition, specific version identifiers can be appended to the URL with an
  additional "@" symbol:
  ``ria+[scheme]://<storelocation>#<dataset-UUID>@<dataset-version>``,
  where ``dataset-version`` refers to a branch or tag.
  
  
  **RIA store layout**
  
  A RIA store is a directory tree with a dedicated subdirectory for each
  dataset in the store. The subdirectory name is constructed from the
  DataLad dataset ID, e.g. ``124/68afe-59ec-11ea-93d7-f0d5bf7b5561``, where
  the first three characters of the ID are used for an intermediate
  subdirectory in order to mitigate files system limitations for stores
  containing a large number of datasets.
  
  By default, a dataset in a RIA store consists of two components:
  A Git repository (for all dataset contents stored in Git) and a
  storage sibling (for dataset content stored in git-annex).
  
  It is possible to selectively disable either component using
  ``storage-sibling 'off'`` or ``storage-sibling 'only'``, respectively.
  If neither component is disabled, a dataset's subdirectory layout in a RIA
  store contains a standard bare Git repository and an ``annex/`` subdirectory
  inside of it.
  The latter holds a Git-annex object store and comprises the storage sibling.
  Disabling the standard git-remote (``storage-sibling='only'``) will result
  in not having the bare git repository, disabling the storage sibling
  (``storage-sibling='off'``) will result in not having the ``annex/``
  subdirectory.
  
  Optionally, there can be a further subdirectory ``archives`` with
  (compressed) 7z archives of annex objects. The storage remote is able to
  pull annex objects from these archives, if it cannot find in the regular
  annex object store. This feature can be useful for storing large
  collections of rarely changing data on systems that limit the number of
  files that can be stored.
  
  Each dataset directory also contains a ``ria-layout-version`` file that
  identifies the data organization (as, for example, described above).
  
  Lastly, there is a global ``ria-layout-version`` file at the store's
  base path that identifies where dataset subdirectories themselves are
  located. At present, this file must contain a single line stating the
  version (currently "1"). This line MUST end with a newline character.
  
  It is possible to define an alias for an individual dataset in a store by
  placing a symlink to the dataset location into an ``alias/`` directory
  in the root of the store. This enables dataset access via URLs of format:
  ``ria+<protocol>://<storelocation>#~<aliasname>``.
  
  Compared to standard git-annex object stores, the ``annex/`` subdirectories
  used as storage siblings follow a different layout naming scheme
  ('dirhashmixed' instead of 'dirhashlower').
  This is mostly noted as a technical detail, but also serves to remind
  git-annex powerusers to refrain from running git-annex commands
  directly in-store as it can cause severe damage due to the layout
  difference. Interactions should be handled via the ORA special remote
  instead.
  
  
  **Error logging**
  
  To enable error logging at the remote end, append a pipe symbol and an "l"
  to the version number in ria-layout-version (like so: ``1|l\n``).
  
  Error logging will create files in an "error_log" directory whenever the
  git-annex special remote (storage sibling) raises an exception, storing the
  Python traceback of it. The logfiles are named according to the scheme
  ``<dataset id>.<annex uuid of the remote>.log`` showing "who" ran into this
  issue with which dataset. Because logging can potentially leak personal
  data (like local file paths for example), it can be disabled client-side
  by setting the configuration variable
  ``annex.ora-remote.<storage-sibling-name>.ignore-remote-config``.
code: def __call__(
      url,
      name,
      *,  # note that `name` is required but not posarg in CLI
      dataset=None,
      storage_name=None,
      alias=None,
      post_update_hook=False,
      shared=None,
      group=None,
      storage_sibling=True,
      existing="error",
      new_store_ok=False,
      trust_level=None,
      recursive=False,
      recursion_limit=None,
      disable_storage__=None,
      push_url=None,
  ):
      if disable_storage__ is not None:
          import warnings
  
          warnings.warn(
              "datalad-create-sibling-ria --no-storage-sibling "
              "is deprecated, use --storage-sibling off instead.",
              DeprecationWarning,
          )
          # recode to new setup
          disable_storage__ = None
          storage_sibling = False
  
      if storage_sibling == "only" and storage_name:
          lgr.warning(
              "Sibling name will be used for storage sibling in "
              "storage-sibling-only mode, but a storage sibling name "
              "was provided"
          )
  
      ds = require_dataset(
          dataset, check_installed=True, purpose="create RIA sibling(s)"
      )
      res_kwargs = dict(
          ds=ds,
          action="create-sibling-ria",
          logger=lgr,
      )
  
      # parse target URL
      # Note: URL parsing is done twice ATM (for top-level ds). This can't be
      # reduced to single instance, since rewriting url based on config could
      # be different for subdatasets.
      try:
          ssh_host, url_base_path, rewritten_url = verify_ria_url(
              push_url if push_url else url, ds.config
          )
      except ValueError as e:
          yield get_status_dict(
              status="error", message=str(e), **res_kwargs
          )
          return
  
      local_base_path = Path(url_path2local_path(url_base_path))
  
      if ds.repo.get_hexsha() is None or ds.id is None:
          raise RuntimeError(
              "Repository at {} is not a DataLad dataset, "
              "run 'datalad create [--force]' first.".format(ds.path)
          )
  
      if not storage_sibling and storage_name:
          lgr.warning(
              "Storage sibling setup disabled, but a storage sibling name "
              "was provided"
          )
  
      if storage_sibling and not storage_name:
          storage_name = "{}-storage".format(name)
  
      if storage_sibling and name == storage_name:
          # leads to unresolvable, circular dependency with publish-depends
          raise ValueError("sibling names must not be equal")
  
      if not isinstance(url, str):
          raise TypeError("url is not a string, but %s" % type(url))
  
      # Query existing siblings upfront in order to fail early on
      # existing=='error', since misconfiguration (particularly of special
      # remotes) only to fail in a subdataset later on with that config, can
      # be quite painful.
      # TODO: messages - this is "create-sibling". Don't confuse existence of
      #       local remotes with existence of the actual remote sibling
      #       in wording
      if existing == "error":
          failed = False
          for dpath, sname in _yield_ds_w_matching_siblings(
              ds,
              (name, storage_name),
              recursive=recursive,
              recursion_limit=recursion_limit,
          ):
              res = get_status_dict(
                  status="error",
                  message=(
                      "a sibling %r is already configured in dataset %r",
                      sname,
                      dpath,
                  ),
                  type="sibling",
                  name=sname,
                  **res_kwargs,
              )
              failed = True
              yield res
          if failed:
              return
      # TODO: - URL parsing + store creation needs to be RF'ed based on
      #         command abstractions
      #       - more generally consider store creation a dedicated command or
      #         option
  
      io = SSHRemoteIO(ssh_host) if ssh_host else LocalIO()
      try:
          # determine the existence of a store by trying to read its layout.
          # Because this raises a FileNotFound error if non-existent, we need
          # to catch it
          io.read_file(local_base_path / "ria-layout-version")
      except (
          FileNotFoundError,
          RIARemoteError,
          RemoteCommandFailedError,
      ) as e:
          if not new_store_ok:
              # we're instructed to only act in case of an existing RIA store
              res = get_status_dict(
                  status="error",
                  message="No store found at '{}'. Forgot "
                  "--new-store-ok ?".format(local_base_path),
                  **res_kwargs,
              )
              yield res
              return
  
      log_progress(
          lgr.info,
          "create-sibling-ria",
          "Creating a new RIA store at %s",
          local_base_path,
      )
      create_store(io, local_base_path, "1")
  
      yield from _create_sibling_ria(
          ds,
          url,
          push_url,
          name,
          storage_sibling,
          storage_name,
          alias,
          existing,
          shared,
          group,
          post_update_hook,
          trust_level,
          res_kwargs,
      )
  
      if recursive:
          # Note: subdatasets can be treated independently, so go full
          # recursion when querying for them and _no_recursion with the
          # actual call. Theoretically this can be parallelized.
  
          for subds in ds.subdatasets(
              state="present",
              recursive=True,
              recursion_limit=recursion_limit,
              return_type="generator",
              result_renderer="disabled",
              result_xfm="datasets",
          ):
              yield from _create_sibling_ria(
                  subds,
                  url,
                  push_url,
                  name,
                  storage_sibling,
                  storage_name,
                  None,  # subdatasets can't have the same alias as the parent
                  existing,
                  shared,
                  group,
                  post_update_hook,
                  trust_level,
                  res_kwargs,
              )
  
imports: import logging
  from pathlib import PurePosixPath
  from datalad.cmd import WitlessRunner
  from datalad.core.distributed.clone import decode_source_spec
  from datalad.customremotes.ria_utils import create_ds_in_store, create_store, get_layout_locations, verify_ria_url
  from datalad.distributed.ora_remote import LocalIO, RemoteCommandFailedError, RIARemoteError, SSHRemoteIO
  from datalad.distribution.dataset import EnsureDataset, datasetmethod, require_dataset
  from datalad.distribution.utils import _yield_ds_w_matching_siblings
  from datalad.interface.base import Interface, build_doc, eval_results
  from datalad.interface.common_opts import recursion_flag, recursion_limit
  from datalad.interface.results import get_status_dict
  from datalad.log import log_progress
  from datalad.support.annexrepo import AnnexRepo
  from datalad.support.constraints import EnsureBool, EnsureChoice, EnsureNone, EnsureStr
  from datalad.support.exceptions import CommandError
  from datalad.support.gitrepo import GitRepo
  from datalad.support.network import url_path2local_path
  from datalad.support.param import Parameter
  from datalad.utils import Path, quote_cmdlinearg
label_desc: Use image node_id 1 for calling the CreateSiblingRia obj's underlying member method code with example usage: obj.__call__(url, name) without return types