1 # This Source Code Form is subject to the terms of the Mozilla Public
2 # License, v. 2.0. If a copy of the MPL was not distributed with this
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 from mozversioncontrol
import get_repository_object
12 from perfdocs
.logger
import PerfDocLogger
14 logger
= PerfDocLogger()
16 ON_TRY
= "MOZ_AUTOMATION" in os
.environ
19 def save_file(file_content
, path
, extension
="rst"):
21 Saves data into a file.
23 :param str path: Location and name of the file being saved
24 (without an extension).
25 :param str data: Content to write into the file.
26 :param str extension: Extension to save the file as.
28 new_file
= pathlib
.Path("{}.{}".format(str(path
), extension
))
29 with new_file
.open("wb") as f
:
30 f
.write(file_content
.encode("utf-8"))
33 def read_file(path
, stringify
=False):
35 Opens a file and returns its contents.
37 :param str path: Path to the file.
38 :return list: List containing the lines in the file.
40 with path
.open(encoding
="utf-8") as f
:
41 return f
.read() if stringify
else f
.readlines()
44 def read_yaml(yaml_path
):
46 Opens a YAML file and returns the contents.
48 :param str yaml_path: Path to the YAML to open.
49 :return dict: Dictionary containing the YAML content.
53 with yaml_path
.open(encoding
="utf-8") as f
:
54 contents
= yaml
.safe_load(f
)
55 except Exception as e
:
57 "Error opening file {}: {}".format(str(yaml_path
), str(e
)), str(yaml_path
)
63 def are_dirs_equal(dir_1
, dir_2
):
65 Compare two directories to see if they are equal. Files in each
66 directory are assumed to be equal if their names and contents
69 :param dir_1: First directory path
70 :param dir_2: Second directory path
71 :return: True if the directory trees are the same and False otherwise.
74 dirs_cmp
= filecmp
.dircmp(str(dir_1
.resolve()), str(dir_2
.resolve()))
75 if dirs_cmp
.left_only
or dirs_cmp
.right_only
or dirs_cmp
.funny_files
:
76 logger
.log("Some files are missing or are funny.")
77 for file in dirs_cmp
.left_only
:
78 logger
.log(f
"Missing in existing docs: {file}")
79 for file in dirs_cmp
.right_only
:
80 logger
.log(f
"Missing in new docs: {file}")
81 for file in dirs_cmp
.funny_files
:
82 logger
.log(f
"The following file is funny: {file}")
85 _
, mismatch
, errors
= filecmp
.cmpfiles(
86 str(dir_1
.resolve()), str(dir_2
.resolve()), dirs_cmp
.common_files
, shallow
=False
89 if mismatch
or errors
:
90 logger
.log(f
"Found mismatches: {mismatch}")
92 # The root for where to save the diff will be different based on
93 # whether we are running in CI or not
94 os_root
= pathlib
.Path
.cwd().anchor
95 diff_root
= pathlib
.Path(os_root
, "builds", "worker")
97 diff_root
= pathlib
.Path(PerfDocLogger
.TOP_DIR
, "artifacts")
98 diff_root
.mkdir(parents
=True, exist_ok
=True)
100 diff_path
= pathlib
.Path(diff_root
, "diff.txt")
101 with diff_path
.open("w", encoding
="utf-8") as diff_file
:
102 for entry
in mismatch
:
103 logger
.log(f
"Mismatch found on {entry}")
105 with pathlib
.Path(dir_1
, entry
).open(encoding
="utf-8") as f
:
106 newlines
= f
.readlines()
107 with pathlib
.Path(dir_2
, entry
).open(encoding
="utf-8") as f
:
108 baselines
= f
.readlines()
109 for line
in difflib
.unified_diff(
110 baselines
, newlines
, fromfile
="base", tofile
="new"
114 # Here we want to add to diff.txt in a patch format, we use
115 # the basedir to make the file names/paths relative and this is
116 # different in CI vs local runs.
117 basedir
= pathlib
.Path(
118 os_root
, "builds", "worker", "checkouts", "gecko"
123 relative_path
= str(pathlib
.Path(dir_2
, entry
)).split(str(basedir
))[-1]
124 patch
= difflib
.unified_diff(
125 baselines
, newlines
, fromfile
=relative_path
, tofile
=relative_path
132 f
"diff --git a/{relative_path} b/{relative_path}\n"
135 diff_file
.write(line
)
137 logger
.log(f
"Completed diff on {entry}")
139 logger
.log(f
"Saved diff to {diff_path}")
143 for common_dir
in dirs_cmp
.common_dirs
:
144 subdir_1
= pathlib
.Path(dir_1
, common_dir
)
145 subdir_2
= pathlib
.Path(dir_2
, common_dir
)
146 if not are_dirs_equal(subdir_1
, subdir_2
):
152 def get_changed_files(top_dir
):
154 Returns the changed files found with duplicates removed.
156 repo
= get_repository_object(top_dir
)
157 return list(set(repo
.get_changed_files() + repo
.get_outgoing_files()))