bugfix: spack config blame should print all lines of config (#22598)

* bugfix: fix representation of null in spack_yaml output

Nulls were previously printed differently by `spack config blame config`
and `spack config get config`.  Fix this in the `spack_yaml` dumpers.

* bugfix: `spack config blame` should print all lines of config

`spack config blame` was not printing all lines of configuration because
there were no annotations for empty lines in the YAML dump output. Fix
this by removing empty lines.
This commit is contained in:
Todd Gamblin 2021-04-08 07:37:16 -07:00 committed by GitHub
parent f27fefc3c1
commit 19b6d3589a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 7 deletions

View File

@ -65,3 +65,31 @@ def test_config_blame_with_override(config):
check_blame('verify_ssl', config_file, 13) check_blame('verify_ssl', config_file, 13)
check_blame('checksum', config_file, 14) check_blame('checksum', config_file, 14)
check_blame('dirty', config_file, 15) check_blame('dirty', config_file, 15)
def test_config_blame_defaults():
"""check blame for an element from an override scope"""
files = {}
def get_file_lines(filename):
if filename not in files:
with open(filename, "r") as f:
files[filename] = [""] + f.read().split("\n")
return files[filename]
config_blame = config_cmd("blame", "config")
for line in config_blame.split("\n"):
# currently checking only simple lines with dict keys
match = re.match(r"^([^:]+):(\d+)\s+([^:]+):\s+(.*)", line)
# check that matches are on the lines they say they are
if match:
filename, line, key, val = match.groups()
line = int(line)
if val.lower() in ("true", "false"):
val = val.lower()
lines = get_file_lines(filename)
assert key in lines[line]
assert val in lines[line]

View File

@ -13,6 +13,7 @@
""" """
import ctypes import ctypes
import re
import sys import sys
from typing import List # novm from typing import List # novm
@ -185,6 +186,12 @@ def ignore_aliases(self, _data):
"""Make the dumper NEVER print YAML aliases.""" """Make the dumper NEVER print YAML aliases."""
return True return True
def represent_data(self, data):
result = super(OrderedLineDumper, self).represent_data(data)
if data is None:
result.value = syaml_str("null")
return result
def represent_str(self, data): def represent_str(self, data):
if hasattr(data, 'override') and data.override: if hasattr(data, 'override') and data.override:
data = data + ':' data = data + ':'
@ -262,19 +269,18 @@ def process_scalar(self):
def represent_data(self, data): def represent_data(self, data):
"""Force syaml_str to be passed through with marks.""" """Force syaml_str to be passed through with marks."""
result = super(LineAnnotationDumper, self).represent_data(data) result = super(LineAnnotationDumper, self).represent_data(data)
if isinstance(result.value, string_types): if data is None:
result.value = syaml_str("null")
elif isinstance(result.value, string_types):
result.value = syaml_str(data) result.value = syaml_str(data)
if markable(result.value): if markable(result.value):
mark(result.value, data) mark(result.value, data)
return result return result
def write_stream_start(self):
super(LineAnnotationDumper, self).write_stream_start()
_annotations.append(colorize('@K{---}'))
def write_line_break(self): def write_line_break(self):
super(LineAnnotationDumper, self).write_line_break() super(LineAnnotationDumper, self).write_line_break()
if not self.saved: if self.saved is None:
_annotations.append(colorize('@K{---}'))
return return
# append annotations at the end of each line # append annotations at the end of each line
@ -322,7 +328,10 @@ def dump_annotated(data, stream=None, *args, **kwargs):
sio = StringIO() sio = StringIO()
yaml.dump(data, sio, *args, **kwargs) yaml.dump(data, sio, *args, **kwargs)
lines = sio.getvalue().rstrip().split('\n')
# write_line_break() is not called by YAML for empty lines, so we
# skip empty lines here with \n+.
lines = re.split(r"\n+", sio.getvalue().rstrip())
getvalue = None getvalue = None
if stream is None: if stream is None: