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

Cylc config add --platform-names #4576

Merged
merged 19 commits into from
Jan 27, 2022
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
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ Added a metadata section to the platform and platform group configurations.
workflow back into Cylc from Cylc Docs to make it a packaged resource for
anyone with a Cylc installation.

[#4576](https://github.com/cylc/cylc-flow/pull/4576) - Added
`--platform-names` and `--platforms` options to `cylc config` for easy
access to information on configured platforms.

### Fixes

[#4566](https://github.com/cylc/cylc-flow/pull/4566) - Fix `cylc scan`
Expand Down
43 changes: 42 additions & 1 deletion cylc/flow/cfgspec/globalcfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
"""Cylc site and user configuration file spec."""

import os
from sys import stderr
from typing import List, Optional, Tuple, Any

from contextlib import suppress
from pkg_resources import parse_version

from cylc.flow import LOG
Expand All @@ -29,15 +31,22 @@
ConfigNode as Conf,
ParsecConfig,
)
from cylc.flow.parsec.exceptions import ParsecError
from cylc.flow.parsec.exceptions import ParsecError, ItemNotFoundError
from cylc.flow.parsec.upgrade import upgrader
from cylc.flow.parsec.util import printcfg
from cylc.flow.parsec.validate import (
CylcConfigValidator as VDR,
DurationFloat,
Range,
cylc_config_validate,
)


PLATFORM_REGEX_TEXT = '''
Configured names are regular expressions; any match is a valid platform.
They are searched from the bottom up, until the first match is found.'''


# Nested dict of spec items.
# Spec value is [value_type, default, allowed_2, allowed_3, ...]
# where:
Expand Down Expand Up @@ -1448,3 +1457,35 @@ def _no_platform_group_name_overlap(self):
for name in names_in_platforms_and_groups:
msg += f'\n * {name}'
raise GlobalConfigError(msg)

def platform_dump(
self,
print_platform_names: bool = True,
print_platforms: bool = True
) -> None:
"""Print informations about platforms currently defined.
"""
if print_platform_names:
with suppress(ItemNotFoundError):
self.dump_platform_names(self)
if print_platforms:
with suppress(ItemNotFoundError):
self.dump_platform_details(self)

@staticmethod
def dump_platform_names(cfg) -> None:
"""Print a list of defined platforms and groups.
"""
platforms = '\n'.join(cfg.get(['platforms']).keys())
platform_groups = '\n'.join(cfg.get(['platform groups']).keys())
print(f'{PLATFORM_REGEX_TEXT}\n\nPlatforms\n---------', file=stderr)
print(platforms)
print('\n\nPlatform Groups\n--------------', file=stderr)
print(platform_groups)

@staticmethod
def dump_platform_details(cfg) -> None:
"""Print platform and platform group configs.
"""
for config in ['platforms', 'platform groups']:
printcfg({config: cfg.get([config], sparse=True)})
37 changes: 37 additions & 0 deletions cylc/flow/scripts/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
from cylc.flow.cfgspec.glbl_cfg import glbl_cfg
from cylc.flow.config import WorkflowConfig
from cylc.flow.id_cli import parse_id
from cylc.flow.exceptions import UserInputError
from cylc.flow.option_parsers import CylcOptionParser as COP
from cylc.flow.pathutil import get_workflow_run_dir
from cylc.flow.templatevars import get_template_vars
Expand Down Expand Up @@ -102,6 +103,25 @@ def get_option_parser():
"overrides any settings it shares with those higher up."),
action="store_true", default=False, dest="print_hierarchy")

platform_listing_options_group = parser.add_option_group(
'Platform printing options')
platform_listing_options_group.add_option(
'--platform-names',
help=(
'Print a list of platforms and platform group names from the '
'configuration.'
),
action='store_true', default=False, dest='print_platform_names'
)
platform_listing_options_group.add_option(
'--platforms',
help=(
'Print platform and platform group configurations, '
'including metadata.'
),
action='store_true', default=False, dest='print_platforms'
)

parser.add_cylc_rose_options()

return parser
Expand All @@ -123,10 +143,27 @@ def main(
options: 'Values',
*ids,
) -> None:

if options.print_platform_names and options.print_platforms:
options.print_platform_names = False

if options.print_platform_names or options.print_platforms:
# Get platform information:
if ids:
raise UserInputError(
"Workflow IDs are incompatible with --platform options."
)
glbl_cfg().platform_dump(
options.print_platform_names,
options.print_platforms
)
return

if not ids:
if options.print_hierarchy:
print("\n".join(get_config_file_hierarchy()))
return

glbl_cfg().idump(
options.item,
not options.defaults,
Expand Down
65 changes: 65 additions & 0 deletions tests/functional/cylc-config/09-platforms.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#-------------------------------------------------------------------------------
# Test cylc config --platform-names and --platforms
. "$(dirname "$0")/test_header"
#-------------------------------------------------------------------------------
set_test_number 5
#-------------------------------------------------------------------------------
cat > "global.cylc" <<__HEREDOC__
[platforms]
[[foo]]
hosts = of_melkor, of_valar
[[bar]]
hosts = of_orcs, of_gondor
[platform groups]
[[FOO]]
platforms = foo, bar
[task events]
# Just make sure this doesn't get included
__HEREDOC__

export CYLC_CONF_PATH="${PWD}"

TEST_NAME="${TEST_NAME_BASE}-names"
run_ok "${TEST_NAME}" cylc config --platform-names
cmp_ok "${TEST_NAME}.stdout" <<__HEREDOC__
localhost
foo
bar
FOO
__HEREDOC__

cmp_ok "${TEST_NAME}.stderr" <<__HEREDOC__

Configured names are regular expressions; any match is a valid platform.
They are searched from the bottom up, until the first match is found.

Platforms
---------


Platform Groups
--------------
__HEREDOC__

TEST_NAME="${TEST_NAME_BASE}-s"
head -n 8 > just_platforms < global.cylc
run_ok "${TEST_NAME}" cylc config --platforms
cmp_ok "${TEST_NAME}.stdout" "just_platforms"

exit
60 changes: 60 additions & 0 deletions tests/unit/cfgspec/test_globalcfg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Tests for the Cylc GlobalConfig object."""

from cylc.flow.cfgspec.globalcfg import GlobalConfig, SPEC
from io import StringIO

import pytest

TEST_CONF = '''
[platforms]
[[foo]]
hosts = of_morgoth
[platform groups]
[[BAR]]
platforms = mario, sonic
[task events]
# Checking that config items that aren't platforms or platform groups
# are not output.
'''


@pytest.fixture
def fake_global_conf(tmp_path):
glblcfg = GlobalConfig(SPEC)
(tmp_path / 'global.cylc').write_text(TEST_CONF)
glblcfg.loadcfg(tmp_path / 'global.cylc')
return glblcfg


def test_dump_platform_names(capsys, fake_global_conf):
"""It dumps lists of platform names, nothing else."""
fake_global_conf.dump_platform_names(fake_global_conf)
stdout, _ = capsys.readouterr()
expected = 'localhost\nfoo\nBAR\n'
assert stdout == expected


def test_dump_platform_details(capsys, fake_global_conf):
"""It dumps lists of platform spec."""
fake_global_conf.dump_platform_details(fake_global_conf)
out, _ = capsys.readouterr()
expected = (
'[platforms]\n [[foo]]\n hosts = of_morgoth\n'
'[platform groups]\n [[BAR]]\n platforms = mario, sonic\n'
)
assert expected == out
3 changes: 3 additions & 0 deletions tests/unit/scripts/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@

import os
from pathlib import Path
from types import SimpleNamespace
from typing import Any, Optional, List
from cylc.flow.exceptions import UserInputError

import pytest
from pytest import param

from cylc.flow.scripts.config import get_config_file_hierarchy
from cylc.flow.cfgspec.globalcfg import GlobalConfig
Expand Down