Skip to content

Commit af27874

Browse files
authored
Merge pull request #33 from exadel-inc/bugfix/EA-32
[EA-32] Exception handling/displaying when calculating a diff
2 parents 409859d + d909126 commit af27874

File tree

14 files changed

+265
-21
lines changed

14 files changed

+265
-21
lines changed

cli/src/main/java/com/exadel/etoolbox/anydiff/Main.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,6 @@
4343
@Slf4j
4444
public class Main {
4545

46-
private static final org.slf4j.Marker CONSOLE_ONLY = MarkerFactory.getMarker("CONSOLE_ONLY");
47-
private static final org.slf4j.Marker LOGFILE_ONLY = MarkerFactory.getMarker("FILE_ONLY");
48-
4946
private static final String REPLACED_FILENAME_CHARS = "[.,:/?\"<>|*\\\\]+";
5047

5148
private static final String EXTENSION_HTML = ".html";
@@ -67,7 +64,6 @@ public static void main(String[] args) {
6764
log.info("-{} (--{}) {}", option.getOpt(), option.getLongOpt(), option.getDescription()));
6865
return;
6966
}
70-
System.out.print("EToolbox AnyDiff ");
7167
AnyDiff anyDiff = new AnyDiff()
7268
.left(runArguments.getLeft())
7369
.right(runArguments.getRight());
@@ -194,8 +190,9 @@ private static void printHead(int allCount, long pendingCount) {
194190
log.info(line);
195191
log.info(StringUtils.repeat(Constants.EQUALS, line.length() - 1));
196192
} else {
197-
log.info(String.format("\nFound %d new difference(-s)", pendingCount));
193+
String line = String.format("\nFound %d new difference(-s)", pendingCount);
198194
String secondLine = String.format("There are also %d accepted difference(-s)", allCount - pendingCount);
195+
log.info(line);
199196
log.info(secondLine);
200197
log.info(StringUtils.repeat(Constants.EQUALS, secondLine.length()));
201198
}
@@ -216,11 +213,11 @@ private static void print(Diff diff, RunArguments runArguments, boolean isOneOfM
216213
log.info("No differences");
217214
}
218215
} else {
219-
if (isOneOfMany) {
216+
if (isOneOfMany && diff.getCount() > 0) {
220217
log.info("{} difference(-s)", diff.getCount());
221218
}
222-
log.info(CONSOLE_ONLY, diff.toString(OutputType.CONSOLE));
223-
log.info(LOGFILE_ONLY, diff.toString(OutputType.LOG));
219+
log.info(MarkerFactory.getMarker(Constants.MARKER_CONSOLE_ONLY), diff.toString(OutputType.CONSOLE));
220+
log.info(MarkerFactory.getMarker(Constants.MARKER_FILE_ONLY), diff.toString(OutputType.LOG));
224221
}
225222
}
226223

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License").
3+
* You may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package com.exadel.etoolbox.anydiff.log;
15+
16+
import ch.qos.logback.classic.spi.ILoggingEvent;
17+
import ch.qos.logback.classic.spi.LoggingEvent;
18+
import com.exadel.etoolbox.anydiff.Constants;
19+
import org.apache.commons.lang3.StringUtils;
20+
21+
import java.io.IOException;
22+
23+
/**
24+
* Extends {@link ch.qos.logback.core.ConsoleAppender} to handle both transient (disappearing) and persistent console
25+
* messages
26+
*/
27+
public class ConsoleAppender extends ch.qos.logback.core.ConsoleAppender<ILoggingEvent> {
28+
29+
private int transientMessageLength = 0;
30+
31+
@Override
32+
protected void writeOut(ILoggingEvent event) throws IOException {
33+
if (!(event instanceof LoggingEvent)) {
34+
super.writeOut(event);
35+
return;
36+
}
37+
if (transientMessageLength > 0) {
38+
LoggingEvent newEvent = new LoggingEvent();
39+
newEvent.setMessage("." + StringUtils.repeat('\b', transientMessageLength));
40+
super.writeOut(newEvent);
41+
transientMessageLength = 0;
42+
}
43+
if (StringUtils.startsWith(event.getMessage(), Constants.DOT)) {
44+
transientMessageLength = event.getFormattedMessage().length() - 1;
45+
}
46+
super.writeOut(event);
47+
}
48+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License").
3+
* You may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package com.exadel.etoolbox.anydiff.log;
15+
16+
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
17+
import ch.qos.logback.classic.spi.ILoggingEvent;
18+
import com.exadel.etoolbox.anydiff.Constants;
19+
import org.apache.commons.lang3.StringUtils;
20+
21+
/**
22+
* Extends {@link PatternLayoutEncoder} to handle both transient and persistent console messages
23+
*/
24+
public class ConsoleEncoder extends PatternLayoutEncoder {
25+
26+
@Override
27+
public byte[] encode(ILoggingEvent event) {
28+
if (StringUtils.startsWith(event.getMessage(), Constants.DOT)) {
29+
return event.getFormattedMessage().substring(Constants.DOT.length()).getBytes();
30+
}
31+
return super.encode(event);
32+
}
33+
}

cli/src/main/java/com/exadel/etoolbox/anydiff/log/FileAppender.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
/**
2424
* Extends {@link ch.qos.logback.core.FileAppender} to provide a custom log file cleanup logic
25-
* @param <E>
25+
* @param <E> Type of log event
2626
*/
2727
public class FileAppender<E> extends ch.qos.logback.core.FileAppender<E> {
2828

cli/src/main/resources/logback.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<configuration>
33
<timestamp key="timestamp" datePattern="yyyyMMddHHmmss"/>
44

5-
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
5+
<appender name="CONSOLE" class="com.exadel.etoolbox.anydiff.log.ConsoleAppender">
66
<filter class="ch.qos.logback.core.filter.EvaluatorFilter">
77
<evaluator class="com.exadel.etoolbox.anydiff.log.ExcludingEventEvaluator">
88
<exclude>FILE_ONLY</exclude>
@@ -12,7 +12,7 @@
1212
<OnMismatch>DENY</OnMismatch>
1313
<OnMatch>ACCEPT</OnMatch>
1414
</filter>
15-
<encoder>
15+
<encoder class="com.exadel.etoolbox.anydiff.log.ConsoleEncoder">
1616
<charset>UTF-8</charset>
1717
<pattern>%msg%n</pattern>
1818
</encoder>

core/src/main/java/com/exadel/etoolbox/anydiff/Constants.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ public class Constants {
6464
public static final char BRACKET_OPEN = '[';
6565
public static final char BRACKET_CLOSE = ']';
6666

67+
public static final String MARKER_CONSOLE_ONLY = "CONSOLE_ONLY";
68+
public static final String MARKER_FILE_ONLY = "FILE_ONLY";
69+
6770
public static final String TAG_AUTO_CLOSE = "/>";
6871
public static final String TAG_CLOSE = ">";
6972
public static final char TAG_CLOSE_CHAR = '>';

core/src/main/java/com/exadel/etoolbox/anydiff/comparison/DiffImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ private String toText(OutputType target) {
201201
.stream()
202202
.filter(Objects::nonNull)
203203
.map(PrintableEntry.class::cast)
204-
.map(entry -> entry.toString(target).trim())
204+
.map(entry -> entry.toString(target))
205205
.collect(Collectors.joining(StringUtils.LF + StringUtils.LF)) +
206206
StringUtils.LF;
207207
}

core/src/main/java/com/exadel/etoolbox/anydiff/comparison/DiffTask.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
import com.github.difflib.text.DiffRow;
2626
import com.github.difflib.text.DiffRowGenerator;
2727
import lombok.Builder;
28+
import lombok.extern.slf4j.Slf4j;
2829
import org.apache.commons.lang3.StringUtils;
30+
import org.slf4j.MarkerFactory;
2931

3032
import java.util.ArrayList;
3133
import java.util.Collections;
@@ -40,12 +42,11 @@
4042
* <u>Note</u>: This class is not a part of public API and is subject to change. You should not use it directly
4143
*/
4244
@Builder(builderClassName = "Builder")
45+
@Slf4j
4346
public class DiffTask {
4447

4548
private static final UnaryOperator<String> EMPTY_NORMALIZER = StringUtils::defaultString;
4649

47-
private static final String MESSAGE_COMPARING = "Comparing... ";
48-
4950
private final ContentType contentType;
5051

5152
private final String leftId;
@@ -118,10 +119,8 @@ public Diff run() {
118119
.build();
119120
return new DiffImpl(leftId, rightId).withChildren(miss);
120121
}
121-
System.out.print(MESSAGE_COMPARING);
122-
Diff result = contentType == ContentType.UNDEFINED ? runForBinary() : runForText();
123-
System.out.print(StringUtils.repeat('\b', MESSAGE_COMPARING.length()));
124-
return result;
122+
log.info(MarkerFactory.getMarker(Constants.MARKER_CONSOLE_ONLY), ".Comparing...");
123+
return contentType == ContentType.UNDEFINED ? runForBinary() : runForText();
125124
}
126125

127126
private Diff runForBinary() {
@@ -151,7 +150,15 @@ private Diff runForText() {
151150
String rightPreprocessed = getPreprocessor(rightId).apply(rightContent.toString());
152151
List<String> leftLines = StringUtil.splitByNewline(leftPreprocessed);
153152
List<String> rightLines = StringUtil.splitByNewline(rightPreprocessed);
154-
List<DiffRow> diffRows = generator.generateDiffRows(leftLines, rightLines);
153+
154+
List<DiffRow> diffRows;
155+
try {
156+
diffRows = generator.generateDiffRows(leftLines, rightLines);
157+
} catch (Exception e) {
158+
log.error("Exception when comparing {} and {}", leftId, rightId, e);
159+
return new DiffImpl(leftId, rightId)
160+
.withChildren(new ErrorBlockImpl(e, taskParameters.getColumnWidth() - 1));
161+
}
155162
diffRows = getPostprocessor().apply(diffRows);
156163

157164
DiffImpl result = new DiffImpl(leftId, rightId);
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License").
3+
* You may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package com.exadel.etoolbox.anydiff.comparison;
15+
16+
import com.exadel.etoolbox.anydiff.Constants;
17+
import com.exadel.etoolbox.anydiff.OutputType;
18+
import com.exadel.etoolbox.anydiff.diff.DiffState;
19+
import org.apache.commons.lang3.NotImplementedException;
20+
import org.apache.commons.lang3.StringUtils;
21+
22+
/**
23+
* Implements {@link AbstractBlock} to represent an exception in the comparison process
24+
*/
25+
class ErrorBlockImpl extends AbstractBlock {
26+
private final MarkedString message;
27+
28+
ErrorBlockImpl(Exception e, int columnWidth) {
29+
String messageString = StringUtils.defaultIfEmpty(e.getMessage(), e.getClass().getName());
30+
this.message = new MarkedString(messageString, Marker.ERROR);
31+
setColumnWidth(columnWidth);
32+
}
33+
34+
/* ---------
35+
Accessors
36+
--------- */
37+
38+
@Override
39+
public int getCount() {
40+
return 0;
41+
}
42+
43+
@Override
44+
public int getPendingCount() {
45+
return 0;
46+
}
47+
48+
@Override
49+
public DiffState getState() {
50+
return DiffState.ERROR;
51+
}
52+
53+
/* -------
54+
Content
55+
------- */
56+
57+
@Override
58+
public String getLeft(boolean includeContext) {
59+
return StringUtils.EMPTY;
60+
}
61+
62+
@Override
63+
public String getRight(boolean includeContext) {
64+
return StringUtils.EMPTY;
65+
}
66+
67+
/* ----------
68+
Operations
69+
---------- */
70+
71+
@Override
72+
public void accept() {
73+
throw new NotImplementedException();
74+
}
75+
76+
/* ------
77+
Output
78+
------ */
79+
80+
@Override
81+
public String toString(OutputType target) {
82+
if (target == OutputType.HTML) {
83+
return toHtml();
84+
} else {
85+
return toText(target);
86+
}
87+
}
88+
89+
private String toHtml() {
90+
return HtmlTags
91+
.div().withClassAttr(Constants.CLASS_LEFT).withContent(getLeftLabel())
92+
.div().withClassAttr(Constants.CLASS_RIGHT).withContent(getRightLabel())
93+
.wrapIn(HtmlTags.line())
94+
.withClassAttr(Constants.CLASS_HEADER)
95+
.wrapIn(HtmlTags.section())
96+
.withClassAttr("no-header")
97+
.withContent(message.toHtml())
98+
.toString();
99+
}
100+
101+
private String toText(OutputType target) {
102+
int fullWidth = getColumnWidth() * 2 + 3;
103+
return String.join(StringUtils.LF, message.toText(target, fullWidth));
104+
}
105+
}

core/src/main/java/com/exadel/etoolbox/anydiff/comparison/FragmentImpl.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import lombok.Getter;
1919
import lombok.Setter;
2020
import org.apache.commons.lang3.builder.HashCodeBuilder;
21+
import org.jetbrains.annotations.NotNull;
2122

2223
/**
2324
* Implements {@link Fragment} to manage a char sequence in a string that differs from another string
@@ -80,6 +81,7 @@ public char charAt(int index) {
8081
return source.charAt(index + offset);
8182
}
8283

84+
@NotNull
8385
@Override
8486
public CharSequence subSequence(int start, int end) {
8587
return source.subSequence(start + this.offset, end + this.offset);
@@ -98,6 +100,7 @@ void trim() {
98100
}
99101
}
100102

103+
@NotNull
101104
@Override
102105
public String toString() {
103106
return source.subSequence(offset, endOffset).toString();

0 commit comments

Comments
 (0)