Skip to content

Commit d9aaf2b

Browse files
authored
Allow comment in YAML output files (#1069)
* Allow comments to be associated with map assignments * Use new comment mechanism for model comparer * Remove comment key mechanism and special processing for JSON
1 parent c79ddda commit d9aaf2b

File tree

8 files changed

+158
-32
lines changed

8 files changed

+158
-32
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates.
3+
* Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
4+
*/
5+
package oracle.weblogic.deploy.util;
6+
7+
import java.util.ArrayList;
8+
import java.util.Collections;
9+
import java.util.HashMap;
10+
import java.util.List;
11+
import java.util.Map;
12+
13+
/**
14+
* Maps dictionary keys to lists of comments, for use in output formatting.
15+
*/
16+
public class CommentMap {
17+
public static final String BLANK_LINE_KEY = "__BLANK_LINE__";
18+
19+
private final Map<String, List<String>> commentMap = new HashMap<>();
20+
21+
public void addBlankLine(String key) {
22+
getOrCreateComments(key).add(BLANK_LINE_KEY);
23+
}
24+
25+
public void addComment(String key, String comment) {
26+
getOrCreateComments(key).add(comment);
27+
}
28+
29+
public List<String> getComments(String key) {
30+
List<String> comments = commentMap.get(key);
31+
return (comments == null) ? Collections.<String>emptyList() : comments;
32+
}
33+
34+
private List<String> getOrCreateComments(String key) {
35+
List<String> comments = commentMap.get(key);
36+
if(comments == null) {
37+
comments = new ArrayList<>();
38+
commentMap.put(key, comments);
39+
}
40+
return comments;
41+
}
42+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates.
3+
* Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
4+
*/
5+
package oracle.weblogic.deploy.util;
6+
7+
import java.util.LinkedHashMap;
8+
9+
/**
10+
* A map that maintains the order of its assignments,
11+
* and has a mapping of element keys to a list of comments.
12+
*/
13+
public class OrderedMap extends LinkedHashMap<String, Object> {
14+
private CommentMap commentMap = new CommentMap();
15+
16+
public OrderedMap() {
17+
super();
18+
}
19+
20+
public CommentMap getCommentMap() {
21+
return commentMap;
22+
}
23+
24+
public void setCommentMap(CommentMap commentMap) {
25+
this.commentMap = commentMap;
26+
}
27+
}

core/src/main/java/oracle/weblogic/deploy/util/PyOrderedDict.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ public final class PyOrderedDict extends PyDictionary implements Iterable<PyObje
3737

3838
private final LinkedHashMap<PyObject, PyObject> linkedHashMap;
3939

40+
private final CommentMap commentMap = new CommentMap();
41+
4042
/**
4143
* The no-args constructor.
4244
*/
@@ -477,6 +479,14 @@ public PyList getValues() {
477479
return new PyList(v.toArray(new PyObject[0]));
478480
}
479481

482+
public CommentMap getCommentMap() {
483+
return commentMap;
484+
}
485+
486+
public void addComment(String key, String comment) {
487+
commentMap.addComment(key, comment);
488+
}
489+
480490
// private methods
481491

482492
private static PyObject dictFromKeys(PyType type, PyObject keys, PyObject value) {

core/src/main/java/oracle/weblogic/deploy/yaml/AbstractYamlTranslator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ protected void dumpInternal(Map<String, Object> data, Writer outputWriter) throw
9292

9393
if (outputWriter != null) {
9494
DumperOptions dumperOptions = getDefaultDumperOptions();
95-
Yaml yaml = new Yaml(dumperOptions);
95+
YamlRepresenter representer = new YamlRepresenter();
96+
Yaml yaml = new Yaml(representer, dumperOptions);
9697

9798
try {
9899
yaml.dump(replaceNoneInMap(data), outputWriter);
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates.
3+
* Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
4+
*/
5+
package oracle.weblogic.deploy.yaml;
6+
7+
import oracle.weblogic.deploy.util.CommentMap;
8+
import oracle.weblogic.deploy.util.OrderedMap;
9+
import org.yaml.snakeyaml.DumperOptions;
10+
import org.yaml.snakeyaml.comments.CommentLine;
11+
import org.yaml.snakeyaml.comments.CommentType;
12+
import org.yaml.snakeyaml.nodes.MappingNode;
13+
import org.yaml.snakeyaml.nodes.Node;
14+
import org.yaml.snakeyaml.nodes.NodeTuple;
15+
import org.yaml.snakeyaml.nodes.ScalarNode;
16+
import org.yaml.snakeyaml.nodes.Tag;
17+
import org.yaml.snakeyaml.representer.Representer;
18+
19+
import java.util.ArrayList;
20+
import java.util.List;
21+
import java.util.Map;
22+
23+
import static oracle.weblogic.deploy.util.CommentMap.BLANK_LINE_KEY;
24+
25+
/**
26+
* Attach comments from mappings to the associated elements.
27+
*/
28+
public class YamlRepresenter extends Representer {
29+
30+
@Override
31+
protected Node representMapping(Tag tag, Map<?, ?> mapping, DumperOptions.FlowStyle flowStyle) {
32+
MappingNode node = (MappingNode) super.representMapping(tag, mapping, flowStyle);
33+
34+
if(mapping instanceof OrderedMap) {
35+
for (NodeTuple tuple : node.getValue()) {
36+
Object keyNode = tuple.getKeyNode();
37+
if(keyNode instanceof ScalarNode) {
38+
CommentMap commentMap = ((OrderedMap) mapping).getCommentMap();
39+
String key = ((ScalarNode) keyNode).getValue();
40+
List<String> comments = commentMap.getComments(key);
41+
if(!comments.isEmpty()) {
42+
List<CommentLine> tupleComments = new ArrayList<>();
43+
for (String comment: comments) {
44+
if(BLANK_LINE_KEY.equals(comment)) {
45+
tupleComments.add(new CommentLine(null, null, "", CommentType.BLANK_LINE));
46+
} else {
47+
tupleComments.add(new CommentLine(null, null, " " + comment, CommentType.BLOCK));
48+
}
49+
}
50+
tuple.getKeyNode().setBlockComments(tupleComments);
51+
}
52+
}
53+
}
54+
}
55+
56+
return node;
57+
}
58+
}

core/src/main/python/wlsdeploy/json/json_translator.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
from wlsdeploy.logging.platform_logger import PlatformLogger
2121
import wlsdeploy.exception.exception_helper as exception_helper
2222

23-
# Unlike with yaml files, JSON files do not allow comments. remove from file
24-
COMMENT_MATCH = '# - '
2523

2624
class JsonToPython(object):
2725
"""
@@ -170,18 +168,15 @@ def _write_dictionary_to_json_file(self, dictionary, writer, indent=''):
170168

171169
indent += self._indent_unit
172170
for key, value in dictionary.iteritems():
173-
if isinstance(key, basestring) and key.startswith(COMMENT_MATCH):
174-
self._logger.finer('WLSDPLY-01714', key, class_name=self._class_name, method_name=_method_name)
171+
writer.println(end_line)
172+
end_line = ','
173+
writer.write(indent + '"' + _escape_text(key) + '" : ')
174+
if isinstance(value, dict):
175+
self._write_dictionary_to_json_file(value, writer, indent)
176+
elif isinstance(value, list):
177+
self._write_list_to_json_file(value, writer, indent)
175178
else:
176-
writer.println(end_line)
177-
end_line = ','
178-
writer.write(indent + '"' + _escape_text(key) + '" : ')
179-
if isinstance(value, dict):
180-
self._write_dictionary_to_json_file(value, writer, indent)
181-
elif isinstance(value, list):
182-
self._write_list_to_json_file(value, writer, indent)
183-
else:
184-
writer.write(_format_json_value(value))
179+
writer.write(_format_json_value(value))
185180
writer.println()
186181
writer.write(end_indent + _end_dict)
187182

core/src/main/python/wlsdeploy/tool/compare/model_comparer.py

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from wlsdeploy.aliases.model_constants import APPLICATION
1515
from wlsdeploy.aliases.model_constants import KUBERNETES
1616
from wlsdeploy.aliases.model_constants import LIBRARY
17-
from wlsdeploy.json.json_translator import COMMENT_MATCH
1817
from wlsdeploy.logging.platform_logger import PlatformLogger
1918
from wlsdeploy.util import dictionary_utils
2019
from wlsdeploy.util import model_helper
@@ -129,8 +128,9 @@ def _compare_security_folders(self, current_folder, past_folder, location, attri
129128
self._messages.add(('WLSDPLY-05716', location.get_folder_path()))
130129
comment = "Replace entire Security Provider section "
131130
new_folder = PyOrderedDict()
132-
_add_comment(comment, new_folder)
133131
new_folder.update(current_folder)
132+
if new_folder:
133+
new_folder.addComment(new_folder.keys()[0], comment)
134134
return new_folder
135135
return PyOrderedDict()
136136

@@ -359,7 +359,7 @@ def _compare_attribute(self, current_value, past_value, location, key, change_fo
359359
current_text = ','.join(current_list)
360360
previous_text = ','.join(previous_list)
361361
comment = key + ": '" + previous_text + "' -> '" + current_text + "'"
362-
_add_comment(comment, change_folder)
362+
change_folder.addComment(key, comment)
363363
change_folder[key] = ','.join(change_list)
364364

365365
elif attribute_type == PROPERTIES:
@@ -368,7 +368,7 @@ def _compare_attribute(self, current_value, past_value, location, key, change_fo
368368
else:
369369
if not isinstance(past_value, dict):
370370
comment = key + ": '" + str(past_value) + "'"
371-
_add_comment(comment, change_folder)
371+
change_folder.addComment(key, comment)
372372
change_folder[key] = current_value
373373

374374
def _compare_properties(self, current_value, past_value, key, change_folder):
@@ -387,7 +387,7 @@ def _compare_properties(self, current_value, past_value, key, change_folder):
387387
past_property_value = past_value[property_key]
388388
if past_property_value != current_property_value:
389389
comment = property_key + ": '" + str(past_property_value) + "'"
390-
_add_comment(comment, property_dict)
390+
property_dict.addComment(property_key, comment)
391391
property_dict[property_key] = current_property_value
392392
else:
393393
property_dict[property_key] = current_property_value
@@ -436,14 +436,3 @@ def _finalize_folder(self, current_folder, past_folder, change_folder, location)
436436
key_value = dictionary_utils.get_element(past_folder, key)
437437
if key_value is not None:
438438
change_folder[key] = key_value
439-
440-
def _add_comment(comment, dictionary):
441-
"""
442-
Add a comment to the specified dictionary
443-
:param comment: the comment text
444-
:param dictionary: the dictionary to be appended
445-
"""
446-
# make comment key unique, key will not appear in output
447-
# comment_key = COMMENT_MATCH + comment
448-
# dictionary[comment_key] = comment
449-
pass

core/src/main/python/wlsdeploy/yaml/yaml_translator.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@
1414
import java.lang.Long as JLong
1515
import java.lang.String as JString
1616
import java.util.ArrayList as JArrayList
17-
import java.util.LinkedHashMap as JLinkedHashMap
1817

1918
import oracle.weblogic.deploy.util.FileUtils as JFileUtils
2019
import oracle.weblogic.deploy.yaml.YamlStreamTranslator as JYamlStreamTranslator
2120
import oracle.weblogic.deploy.yaml.YamlTranslator as JYamlTranslator
21+
from oracle.weblogic.deploy.util import OrderedMap
2222
from oracle.weblogic.deploy.util import PyRealBoolean
23+
from oracle.weblogic.deploy.util import PyOrderedDict
2324

2425
from wlsdeploy.exception import exception_helper
2526
from wlsdeploy.logging.platform_logger import PlatformLogger
@@ -122,7 +123,10 @@ def convert_to_java(self):
122123
raise yaml_ex
123124

124125
def convert_dict_to_java_map(self, dictionary):
125-
result = JLinkedHashMap()
126+
result = OrderedMap()
127+
if isinstance(dictionary, PyOrderedDict):
128+
result.setCommentMap(dictionary.getCommentMap())
129+
126130
for key, value in dictionary.iteritems():
127131
java_key = JString(key)
128132
if isinstance(value, dict):

0 commit comments

Comments
 (0)