"""Patch ria_utils.py tp work with abstract RIA-paths
The ORARemote and CreateSiblingRia-patches use an abstract representation of
all paths that are related to elements of a RIA-store, e.g. `ria-layout-version`
or `ria-object-dir`. This patch adapts `ria_utils.py` to this modification.
"""
from __future__ import annotations
import logging
from pathlib import PurePosixPath
from datalad.customremotes.ria_utils import (
UnknownLayoutVersion,
get_layout_locations,
)
from . import apply_patch
lgr = logging.getLogger('datalad.customremotes.ria_utils')
# The following two blocks of comments and definitions are verbatim copies from
# `datalad.cutomremotes.ria_utils`
# TODO: Make versions a tuple of (label, description)?
# Object tree versions we introduced so far. This is about the layout within a
# dataset in a RIA store
known_versions_objt = ['1', '2']
# Dataset tree versions we introduced so far. This is about the layout of
# datasets in a RIA store
known_versions_dst = ['1']
# taken from `ria_utils._ensure_version` from datalad-core@864dc4ae24c8aac0ec4003604543b86de4735732
[docs]
def ria_utils__ensure_version(io, base_path, version):
"""Check a store or dataset version and make sure it is declared
Parameters
----------
io: SSHRemoteIO or LocalIO
base_path: PurePosixPath
root path of a store or dataset
version: str
target layout version of the store (dataset tree)
"""
# PATCH: ensure that `base_path` is an instance of `PurePosixPath`.
assert isinstance(base_path, PurePosixPath)
# PATCH: convert abstract `ria-layout-version`-path to concrete IO-specific
# path
version_file = io.url2transport_path(base_path / 'ria-layout-version')
if io.exists(version_file):
existing_version = io.read_file(version_file).split('|')[0].strip()
if existing_version != version.split('|')[0]:
# We have an already existing location with a conflicting version on
# record.
# Note, that a config flag after pipe symbol is fine.
raise ValueError("Conflicting version found at target: {}"
.format(existing_version))
else:
# already exists, recorded version fits - nothing to do
return
# Note, that the following does create the base-path dir as well, since
# mkdir has parents=True:
# PATCH: convert abstract path `base_path` to concrete IO-specific path
# before handing it to `mkdir`.
io.mkdir(io.url2transport_path(base_path))
io.write_file(version_file, version)
# taken from `ria_utils.create_store` from datalad-core@864dc4ae24c8aac0ec4003604543b86de4735732
[docs]
def ria_utils_create_store(io, base_path, version):
"""Helper to create a RIA store
Note, that this is meant as an internal helper and part of intermediate
RF'ing. Ultimately should lead to dedicated command or option for
create-sibling-ria.
Parameters
----------
io: SSHRemoteIO or LocalIO
Respective execution instance.
Note: To be replaced by proper command abstraction
base_path: PurePosixPath
root url path of the store
version: str
layout version of the store (dataset tree)
"""
# PATCH: ensure that `base_path` is an instance of `PurePosixPath`.
assert isinstance(base_path, PurePosixPath)
# At store level the only version we know as of now is 1.
if version not in known_versions_dst:
raise UnknownLayoutVersion("RIA store layout version unknown: {}."
"Supported versions: {}"
.format(version, known_versions_dst))
_ensure_version(io, base_path, version)
error_logs = base_path / 'error_logs'
# PATCH: convert abstract path `error_logs` to concrete IO-specific path
# before handing it to `mkdir`.
io.mkdir(io.url2transport_path(error_logs))
# taken from `ria_utils.create_ds_in_store` from datalad-core@864dc4ae24c8aac0ec4003604543b86de4735732
[docs]
def ria_utils_create_ds_in_store(io,
base_path,
dsid,
obj_version,
store_version,
alias=None,
init_obj_tree=True
):
"""Helper to create a dataset in a RIA store
Note, that this is meant as an internal helper and part of intermediate
RF'ing. Ultimately should lead to a version option for create-sibling-ria
in conjunction with a store creation command/option.
Parameters
----------
io: SSHRemoteIO or LocalIO
Respective execution instance.
Note: To be replaced by proper command abstraction
base_path: PurePosixPath
root path of the store
dsid: str
dataset id
store_version: str
layout version of the store (dataset tree)
obj_version: str
layout version of the dataset itself (object tree)
alias: str, optional
alias for the dataset in the store
init_obj_tree: bool
whether or not to create the base directory for an annex objects tree (
'annex/objects')
"""
# PATCH: ensure that `base_path` is an instance of `PurePosixPath`.
assert isinstance(base_path, PurePosixPath)
# TODO: Note for RF'ing, that this is about setting up a valid target
# for the special remote not a replacement for create-sibling-ria.
# There's currently no git (bare) repo created.
try:
# TODO: This is currently store layout version!
# Too entangled by current get_layout_locations.
dsgit_dir, archive_dir, dsobj_dir = \
get_layout_locations(int(store_version), base_path, dsid)
except ValueError as e:
raise UnknownLayoutVersion(str(e))
if obj_version not in known_versions_objt:
raise UnknownLayoutVersion("Dataset layout version unknown: {}. "
"Supported: {}"
.format(obj_version, known_versions_objt))
_ensure_version(io, dsgit_dir, obj_version)
# PATCH: convert abstract path `archive_dir` to concrete IO-specific path
# before handing it to `mkdir`.
io.mkdir(io.url2transport_path(archive_dir))
if init_obj_tree:
# PATCH: convert abstract path `dsobj_dir` to concrete IO-specific path
# before handing it to `mkdir`.
io.mkdir(io.url2transport_path(dsobj_dir))
if alias:
alias_dir = base_path / "alias"
# PATCH: convert abstract path `alias_dir` to concrete IO-specific path
# before handing it to `mkdir`.
io.mkdir(io.url2transport_path(alias_dir))
try:
# go for a relative path to keep the alias links valid
# when moving a store
io.symlink(
# PATCH: convert abstract relative path to concrete IO-specific
# path before handing it to `symlink`.
io.url2transport_path(
PurePosixPath('..') / dsgit_dir.relative_to(base_path)
),
# PATCH: convert abstract alias-path to concrete IO-specific path
# before handing it to `symlink`.
io.url2transport_path(alias_dir / alias)
)
except FileExistsError:
lgr.warning("Alias %r already exists in the RIA store, not adding an "
"alias.", alias)
_ensure_version = ria_utils__ensure_version
# Overwrite `create_store` to handle paths properly
apply_patch(
'datalad.customremotes.ria_utils',
None,
'create_store',
ria_utils_create_store,
)
# Overwrite `create_ds_in_store` to handle paths properly
apply_patch(
'datalad.customremotes.ria_utils',
None,
'create_ds_in_store',
ria_utils_create_ds_in_store,
)
# Overwrite `_ensure_version` to handle paths properly
apply_patch(
'datalad.customremotes.ria_utils',
None,
'_ensure_version',
ria_utils__ensure_version,
)