Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show the default for switch options in transport CLI #4223

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions aiida/transports/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,25 +71,33 @@ def transport_option_default(name, computer):
return default


def interactive_default(transport_type, key, also_noninteractive=False):
"""Create a contextual_default value callback for an auth_param key."""
def interactive_default(key, also_non_interactive=False):
"""Create a contextual_default value callback for an auth_param key.
:param key: the name of the option.
:param also_non_interactive: indicates whether this option should provide a default also in non-interactive mode. If
False, the option will raise `MissingParameter` if no explicit value is specified when the command is called in
non-interactive mode.
"""

@with_dbenv()
def get_default(ctx):
"""Determine the default value from the context."""
from aiida import orm

if not also_non_interactive and ctx.params['non_interactive']:
raise click.MissingParameter()

user = ctx.params['user'] or orm.User.objects.get_default()
computer = ctx.params['computer']

try:
authinfo = orm.AuthInfo.objects.get(dbcomputer_id=computer.id, aiidauser_id=user.id)
except NotExistent:
authinfo = orm.AuthInfo(computer=computer, user=user)
non_interactive = ctx.params['non_interactive']
old_authparams = authinfo.get_auth_params()
if not also_noninteractive and non_interactive:
raise click.MissingParameter()
suggestion = old_authparams.get(key)

auth_params = authinfo.get_auth_params()
suggestion = auth_params.get(key)
suggestion = suggestion or transport_option_default(key, computer)
return suggestion

Expand All @@ -99,25 +107,25 @@ def get_default(ctx):
def create_option(name, spec):
"""Create a click option from a name and partial specs as used in transport auth_options."""
from copy import deepcopy

spec = deepcopy(spec)
name_dashed = name.replace('_', '-')
option_name = '--{}'.format(name_dashed)
existing_option = spec.pop('option', None)

if spec.pop('switch', False):
option_name = '--{name}/--no-{name}'.format(name=name_dashed)
kwargs = {}

if 'default' in spec:
kwargs['show_default'] = True
else:
kwargs['contextual_default'] = interactive_default(
'ssh', name, also_noninteractive=spec.pop('non_interactive_default', False)
)
kwargs = {'cls': InteractiveOption, 'show_default': True}

non_interactive_default = spec.pop('non_interactive_default', False)
kwargs['contextual_default'] = interactive_default(name, also_non_interactive=non_interactive_default)

kwargs['cls'] = InteractiveOption
kwargs.update(spec)

if existing_option:
return existing_option(**kwargs)

return click.option(option_name, **kwargs)


Expand Down
23 changes: 17 additions & 6 deletions aiida/transports/plugins/ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,17 @@ class SshTransport(Transport): # pylint: disable=too-many-public-methods
'non_interactive_default': True
}
),
('port', {
'option': options.PORT,
'prompt': 'Port number',
'non_interactive_default': True
}),
(
'port',
{
'option': options.PORT,
'prompt': 'Port number',
'non_interactive_default': True,
},
),
(
'look_for_keys', {
'default': True,
'switch': True,
'prompt': 'Look for keys',
'help': 'Automatically look for private keys in the ~/.ssh folder.',
Expand All @@ -106,6 +110,7 @@ class SshTransport(Transport): # pylint: disable=too-many-public-methods
),
(
'allow_agent', {
'default': False,
'switch': True,
'prompt': 'Allow ssh agent',
'help': 'Switch to allow or disallow using an SSH agent.',
Expand All @@ -115,13 +120,14 @@ class SshTransport(Transport): # pylint: disable=too-many-public-methods
(
'proxy_command', {
'prompt': 'SSH proxy command',
'help': 'SSH proxy command for tunneling through a proxy server.' +
'help': 'SSH proxy command for tunneling through a proxy server.'
' Leave empty to parse the proxy command from the SSH config file.',
'non_interactive_default': True
}
), # Managed 'manually' in connect
(
'compress', {
'default': True,
'switch': True,
'prompt': 'Compress file transfers',
'help': 'Turn file transfer compression on or off.',
Expand All @@ -130,6 +136,7 @@ class SshTransport(Transport): # pylint: disable=too-many-public-methods
),
(
'gss_auth', {
'default': False,
'type': bool,
'prompt': 'GSS auth',
'help': 'Enable when using GSS kerberos token to connect.',
Expand All @@ -138,6 +145,7 @@ class SshTransport(Transport): # pylint: disable=too-many-public-methods
),
(
'gss_kex', {
'default': False,
'type': bool,
'prompt': 'GSS kex',
'help': 'GSS kex for kerberos, if not configured in SSH config file.',
Expand All @@ -146,6 +154,7 @@ class SshTransport(Transport): # pylint: disable=too-many-public-methods
),
(
'gss_deleg_creds', {
'default': False,
'type': bool,
'prompt': 'GSS deleg_creds',
'help': 'GSS deleg_creds for kerberos, if not configured in SSH config file.',
Expand Down Expand Up @@ -177,6 +186,7 @@ class SshTransport(Transport): # pylint: disable=too-many-public-methods
_valid_auth_options = _valid_connect_options + [
(
'load_system_host_keys', {
'default': True,
'switch': True,
'prompt': 'Load system host keys',
'help': 'Load system host keys from default SSH location.',
Expand All @@ -185,6 +195,7 @@ class SshTransport(Transport): # pylint: disable=too-many-public-methods
),
(
'key_policy', {
'default': 'RejectPolicy',
'type': click.Choice(['RejectPolicy', 'WarningPolicy', 'AutoAddPolicy']),
'prompt': 'Key policy',
'help': 'SSH key policy if host is not known.',
Expand Down
2 changes: 1 addition & 1 deletion tests/cmdline/params/options/test_interactive.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ def test_non_interactive(self):
def test_non_interactive_default(self):
"""
scenario: InteractiveOption, invoked with only --non-interactive
behaviour: fail
behaviour: success
"""
cmd = self.simple_command(default='default')
runner = CliRunner()
Expand Down