1#!/usr/bin/env python3
2
3r"""
4This module contains file functions such as file_diff.
5"""
6
7import time
8import os
9import re
10from gen_cmd import cmd_fnc_u
11robot_env = 1
12try:
13    from robot.libraries.BuiltIn import BuiltIn
14    from robot.libraries import DateTime
15except ImportError:
16    robot_env = 0
17
18
19def file_diff(file1_path,
20              file2_path,
21              diff_file_path,
22              skip_string):
23    r"""
24    Compare the contents of two text files.  The comparison uses the Unix
25    'diff' command.  Differences can be selectively ignored by use of
26    the skip_string parameter.  The output of diff command is written
27    to a user-specified file and is also written (logged) to the console.
28
29    Description of arguments:
30    file1_path       File containing text data.
31    file2_path       Text file to compare to file1.
32    diff_file_path   Text file which will contain the diff output.
33    skip_string      To allow for differences which may expected or immaterial,
34                     skip_string parameter is a word or a string of comma
35                     separated words which specify what should be ignored.
36                     For example, "size,speed".  Any line containing the word
37                     size or the word speed will be ignored when the diff is
38                     performed.  This parameter is optional.
39
40    Returns:
41    0 if both files contain the same information or they differ only in
42      items specified by the skip_string.
43    2 if FILES_DO_NOT_MATCH.
44    3 if INPUT_FILE_DOES_NOT_EXIST.
45    4 if IO_EXCEPTION_READING_FILE.
46    5 if IO_EXCEPTION_WRITING_FILE.
47    6 if INPUT_FILE_MALFORMED
48    """
49
50    FILES_MATCH = 0
51    FILES_DO_NOT_MATCH = 2
52    INPUT_FILE_DOES_NOT_EXIST = 3
53    IO_EXCEPTION_READING_FILE = 4
54    IO_EXCEPTION_WRITING_FILE = 5
55    INPUT_FILE_MALFORMED = 6
56
57    # The minimum size in bytes a file must be.
58    min_file_byte_size = 1
59
60    now = time.strftime("%Y-%m-%d %H:%M:%S")
61
62    if (not os.path.exists(file1_path) or (not os.path.exists(file2_path))):
63        return INPUT_FILE_DOES_NOT_EXIST
64    try:
65        with open(file1_path, 'r') as file:
66            initial = file.readlines()
67        with open(file2_path, 'r') as file:
68            final = file.readlines()
69    except IOError:
70        file.close()
71        return IO_EXCEPTION_READING_FILE
72    except ValueError:
73        file.close()
74        return INPUT_FILE_MALFORMED
75    else:
76        file.close()
77
78    # Must have more than a trivial number of bytes.
79    if len(initial) < min_file_byte_size:
80        return INPUT_FILE_MALFORMED
81
82    if (initial == final):
83        try:
84            file = open(diff_file_path, 'w')
85        except IOError:
86            file.close()
87        line_to_print = "Specified skip (ignore) string = " + \
88            skip_string + "\n\n"
89        file.write(line_to_print)
90        line_to_print = now + " found no difference between file " + \
91            file1_path + " and " + \
92            file2_path + "\n"
93        file.write(line_to_print)
94        file.close()
95        return FILES_MATCH
96
97    # Find the differences and write difference report to diff_file_path file
98    try:
99        file = open(diff_file_path, 'w')
100    except IOError:
101        file.close()
102        return IO_EXCEPTION_WRITING_FILE
103
104    # Form a UNIX diff command and its parameters as a string.  For example,
105    # if skip_string="size,capacity",  command = 'diff  -I "size"
106    # -I "capacity"  file1_path file2_path'.
107    skip_list = filter(None, re.split(r"[ ]*,[ ]*", skip_string))
108    ignore_string = ' '.join([("-I " + '"' + x + '"') for x in skip_list])
109    command = ' '.join(filter(None, ["diff", ignore_string, file1_path,
110                                     file2_path]))
111
112    line_to_print = now + "   " + command + "\n"
113    file.write(line_to_print)
114
115    # Run the command and get the differences
116    rc, out_buf = cmd_fnc_u(command, quiet=0, print_output=0, show_err=0)
117
118    # Write the differences to the specified diff_file and console.
119    if robot_env == 1:
120        BuiltIn().log_to_console("DIFF:\n" + out_buf)
121    else:
122        print("DIFF:\n", out_buf)
123
124    file.write(out_buf)
125    file.close()
126
127    if rc == 0:
128        # Any differences found were on the skip_string.
129        return FILES_MATCH
130    else:
131        # We have at least one difference not in the skip_string.
132        return FILES_DO_NOT_MATCH
133