Skip to content

Commit

Permalink
Merge 960836b into afe3db7
Browse files Browse the repository at this point in the history
  • Loading branch information
mih committed Mar 6, 2018
2 parents afe3db7 + 960836b commit 1e11a69
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 0 deletions.
1 change: 1 addition & 0 deletions datalad/interface/__init__.py
Expand Up @@ -58,6 +58,7 @@
_group_misc = (
'Miscellaneous commands',
[
('datalad.interface.configure', 'Configure'),
('datalad.interface.test', 'Test'),
('datalad.interface.crawl', 'Crawl'),
('datalad.interface.crawl_init', 'CrawlInit', 'crawl-init'),
Expand Down
161 changes: 161 additions & 0 deletions datalad/interface/configure.py
@@ -0,0 +1,161 @@
# emacs: -*- mode: python; py-indent-offset: 4; tab-width: 4; indent-tabs-mode: nil -*-
# ex: set sts=4 ts=4 sw=4 noet:
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
#
# See COPYING file distributed along with the datalad package for the
# copyright and license terms.
#
# ## ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##

__docformat__ = 'restructuredtext'

from collections import OrderedDict

from datalad.ui import ui
from .base import Interface
from ..support.param import Parameter
from datalad.dochelpers import exc_str
from datalad.utils import getpwd

from datalad.support.constraints import EnsureNone
from datalad.distribution.dataset import EnsureDataset
from datalad.distribution.dataset import require_dataset
from datalad.distribution.dataset import datasetmethod
from datalad.interface.utils import eval_results
from datalad.interface.base import build_doc
from datalad.interface.results import get_status_dict

from logging import getLogger
lgr = getLogger('datalad.interface.configure')

from datalad import cfg as dlcfg


# using the style from datalad.interface.common_cfg
init_definitions = OrderedDict([
('user.name', {
'ui': ('question', {
'title': 'Your name',
'text': 'Name to be associated with changes recorded by Git'}),
'destination': 'global',
}),
('user.email', {
'ui': ('question', {
'title': 'Your email address',
'text': 'Email address to be associated with changes recorded by Git'}),
'destination': 'global',
}),
])


@build_doc
class Configure(Interface):
"""Configure DataLad interactively
This command allows to configure DataLad, or an individual dataset
interactively, by answering select questions. The answers will
be stored in the appropriate Git or DataLad configuration files,
and can be edited subsequently for further customization.
"""

_params_ = dict(
dataset=Parameter(
args=("-d", "--dataset"),
doc="""if set, configuration items for datasets will be
presented too, and stored in the specified dataset.""",
constraints=EnsureDataset() | EnsureNone()),
)

@staticmethod
@datasetmethod(name='configure')
@eval_results
def __call__(dataset=None):
cfg = dlcfg
if dataset:
dataset = require_dataset(
dataset,
check_installed=True,
purpose='configuration')
# be able to configure a dataset
cfg = dataset.config
# TODO compose the candidate cfg items from other
# sources to -- maybe some for initializing a dataset
# when --dataset is given
for var, props in init_definitions.items():
default = props.get('default', None)
val = cfg.get(var, None)
dialog_type = props.get('ui', [None])[0]
dialog_props = props.get('ui', [None, {}])[1]
valtype = props.get('type', None)
where = props.get('destination', 'local')

if where == 'dataset' and dataset is None:
lgr.debug(
'Skip configuration of dataset config variable %s, no dataset available', var)
continue
if not dialog_type:
# errr, cannot ask
continue
status = None
while status not in ('ok', 'notneeded'):
res = get_status_dict(
ds=dataset if where == 'dataset' else None,
action='configure',
logger=lgr)
if where != 'dataset':
# must have a path in the result
res['path'] = getpwd()
entry = getattr(ui, dialog_type)(
default=val if val else default,
**dialog_props if dialog_props else {})
# type check, skip on any set of weird input (escape chars)
# as a sign of user struggle
if valtype and '\x1b' not in entry:
try:
valtype(entry)
except Exception as e:
ui.message("Value incompatible with target type ({})".format(
exc_str(e)))
status = 'error'
continue
action = '?'
while action == '?':
action = ui.question(
"{} {}={} in the {} configuration?".format(
'Set' if val is None else 'Update',
var,
repr(entry),
where),
title=None,
choices=['y', 'n', 'r', 'x', '?'],
# default to re-enter whenever there is a sign of
# struggle
default='r'
if '\x1b' in entry else 'y'
if entry != val else 'n',
hidden=False)
if action == '?':
ui.message('Response alternatives: (y)es, (n)o, (r)e-enter, e(x)it')
if action == 'y':
if entry != val:
cfg.set(
var,
entry,
where=where,
# repeated access is not part of the usage
# pattern here, hence no need
reload=False,
# this command does not support multi-value
# options (yet), let it fail
force=False)
status = 'ok'
else:
status = 'notneeded'
res['status'] = status
yield res
continue
elif action == 'n':
status = 'ok'
continue
elif action == 'x':
return
1 change: 1 addition & 0 deletions docs/source/cmdline.rst
Expand Up @@ -63,6 +63,7 @@ Miscellaneous commands

generated/man/datalad-add-archive-content
generated/man/datalad-clean
generated/man/datalad-configure
generated/man/datalad-crawl
generated/man/datalad-crawl-init
generated/man/datalad-download-url
Expand Down
1 change: 1 addition & 0 deletions docs/source/modref.rst
Expand Up @@ -76,6 +76,7 @@ Miscellaneous commands
:toctree: generated

api.add_archive_content
api.configure
api.crawl
api.crawl_init
api.test
Expand Down

0 comments on commit 1e11a69

Please sign in to comment.