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