📜 ⬆️ ⬇️

diff for lazy developers or how to compare the incomparable

In the old days, on Windows, for comparing oracle-schemes (read databases), I was satisfied with the compiler built into Quest Software TOAD. He was not bad, and coped with his task. But transferring to linux, I was disappointed. None of the [and so few] tools provides even half of the former comfort. Namely, an elementary comparison and merging of two files (DDL, SQL, any source code is not the essence) of several thousand lines in each, where each is formatted in its own way and the real changes are all-nothing, becomes natural torture.



Understanding the futility of trying to find the necessary functionality in one tool, I decided to look for crutches in the form of third-party tools. Namely - independent comparisons and interlocks ([visual] compare and merging tools). After going through almost all the popular tools , it turned out that very few (read almost no one) were able to skip line end characters in the comparison of two text files.
')
For clarity, I will explain with an example. Suppose we have 2 files, typically old and new.

Old (ora1.sql):

declare
nfunctionresult NUMBER(9);
begin

nFunctionResult :=
orauser.pack_util.FGetNeededValue (
in_nSomeParam => somevalue
);

dbms_output.put_line( 'Function result: ' ||
nFunctionResult);
exception
when SOME_EXCEPTION THEN
orauser.pack_util.PReportError( 'SOME_EXCEPTION' );
when OTHERS THEN
orauser.pack_util.PReportError( 'OTHER exception' );
end ;


New (ora2.sql):

declare
nFunctionResult NUMBER(9);
begin
nFunctionResult := orauser.pack_util.FGetNeededValue (in_nSomeParam => somevalue);
dbms_output.put_line( 'Function result: ' ||nFunctionResult);
exception
when SOME_EXCEPTION THEN
orauser.pack_util.PReportError( 'SOME_EXCEPTION' );
when OTHERS THEN
orauser.pack_util.PReportError( 'OTHER' );
end ;



As can be seen with an inquiring human eye, the essence of the differences between ora1.sql and ora2.sql files is in one word and different formatting, but their diff is completely unreadable. Here is the classic result of comparing them:

[bugman@localhost 1]$ diff ora1.sql ora2.sql
2c2
< nfunctionresult NUMBER(9);
---
> nFunctionResult NUMBER(9);
4,11c4,5
<
< nFunctionResult :=
< orauser.pack_util.FGetNeededValue (
< in_nSomeParam => somevalue
< );
<
< dbms_output.put_line('Function result: '||
< nFunctionResult);
---
> nFunctionResult := orauser.pack_util.FGetNeededValue (in_nSomeParam => somevalue);
> dbms_output.put_line('Function result: '||nFunctionResult);
16c10
< orauser.pack_util.PReportError('OTHER exception');
---
> orauser.pack_util.PReportError('OTHER');


The key "put on all spaces" -w does not improve the situation:

[bugman@localhost 1]$ diff -wi ora1.sql ora2.sql
4,11c4,5
<
< nFunctionResult :=
< orauser.pack_util.FGetNeededValue (
< in_nSomeParam => somevalue
< );
<
< dbms_output.put_line('Function result: '||
< nFunctionResult);
---
> nFunctionResult := orauser.pack_util.FGetNeededValue (in_nSomeParam => somevalue);
> dbms_output.put_line('Function result: '||nFunctionResult);
16c10
< orauser.pack_util.PReportError('OTHER exception');
---
> orauser.pack_util.PReportError('OTHER');


Despite the fact that the original documentation states that the spaces are the end-of-line characters , the bug I started was closed in a redhat bugzilla with the mark “NOT BAG”, and the GNUs themselves unsubscribed that they say yes, this is BAG, but BAG documentation . And in the last letter, they promised to fix everything in the world.

Of all the tried and tested utilities, the most convenient was xxdiff (and more specifically its ignore per-hunk whitespaces option ), but unfortunately, the utility itself was not able to work with Unicode files, did not have a built-in editor. to edit files on the fly, did not provide the CLI for possible integration with other tools, and besides, it didn’t have the most pleasant interface.

But the utility of the dwdiff command line came closest. This small wrapper around diff delivers exactly what I need - differences at the level of WORDS. But there was no costing a spoon of tar - the output of this utility is unique and there are no standard options to bring the difference to diff:

[bugman@localhost 1]$ dwdiff -P -i ora1.sql ora2.sql
declare
nFunctionResult NUMBER(9);
begin
nFunctionResult := orauser.pack_util.FGetNeededValue (in_nSomeParam => somevalue);
dbms_output.put_line('Function result: '||nFunctionResult);
exception
when SOME_EXCEPTION THEN
orauser.pack_util.PReportError('SOME_EXCEPTION');
when OTHERS THEN
orauser.pack_util.PReportError('OTHER [-exception-]');
end;


On the other hand, it is not surprising, because the standard patch has a line level, and in what form can the difference of two files be displayed if they differ in each line? I was puzzled by this question and got in touch with the author of this utility, commander GP Halkes, the result of the correspondence was a small crutch:

[bugman@localhost 1]$ ./diffwrap.sh ora1.sql ora2.sql diff -i
10c10
< orauser.pack_util.PReportError('OTHER exception');
---
> orauser.pack_util.PReportError('OTHER');


This vrapper allows you to use with visual differentials, such as kdiff3. The script itself, the perfected version of which will soon become part of dwdiff and will be distributed with it to the joy of lazy coders, but who can't wait to try it out now, there is no magic here:

[bugman@localhost 1]$ cat ~/diffwrap.sh
#!/bin/bash

if [ $# -lt 3 ] ; then
echo "Usage: script.sh "
exit 1
fi

OLD="$1"
NEW="$2"
shift 2

# First create a version of the old file that is formated like
# the new file...
TMP="`mktemp oldconvertXXXXXX`"
dwdiff -P -2 -w '' -x '' "$OLD" "$NEW" > "$TMP"

# ... and then call a diff program to show the changes (per line).
"$@" "$TMP" "$NEW"

# Finally, clean up the temporary file
rm "$TMP"


PS . - - . : 1) coding style guide, , , ; 2) , - , - ?

Source: https://habr.com/ru/post/75716/


All Articles