Bug 1844662 - [mach vendor] Warn if replace-in-file finds a match but no changes were made. r=tjr

If replace-in-file[-regex] doesn't make any changes it throws an Exception
thinking that no match was found. In some cases the replacement could be the
same as the matched text. In this case, warn but don't raise an exception.

Non-regex patterns are escaped with re.escape() to simplify the function a bit.

Differential Revision: https://phabricator.services.mozilla.com/D184165
This commit is contained in:
Rob Lemley 2023-08-03 19:55:56 +00:00
Родитель 9308e83bc6
Коммит 4a65b455c4
4 изменённых файлов: 147 добавлений и 7 удалений

Просмотреть файл

@ -37,6 +37,7 @@ subsuite = mozbuild
[frontend/test_reader.py]
[frontend/test_sandbox.py]
[repackaging/test_deb.py]
[vendor/test_vendor_manifest.py]
[test_artifact_cache.py]
[test_artifacts.py]
[test_base.py]

0
python/mozbuild/mozbuild/test/vendor/__init__.py поставляемый Normal file
Просмотреть файл

134
python/mozbuild/mozbuild/test/vendor/test_vendor_manifest.py поставляемый Normal file
Просмотреть файл

@ -0,0 +1,134 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from contextlib import nullcontext as does_not_raise
import pytest
from mozunit import main
from mozbuild.vendor.vendor_manifest import _replace_in_file
@pytest.mark.parametrize(
"pattern,replacement,input_data,expected,exception",
[
(
"lookup.c",
"vorbis_lookup.c",
'#include "lookup.c"\n',
'#include "vorbis_lookup.c"\n',
does_not_raise(),
),
(
"lookup.c",
"vorbis_lookup.c",
'#include "vorbis_lookup.c"\n',
'#include "vorbis_lookup.c"\n',
pytest.raises(Exception),
),
(
"@VCS_TAG@",
"616bfd1506a8a75c6a358e578cbec9ca11931502",
'#define DAV1D_VERSION "@VCS_TAG@"\n',
'#define DAV1D_VERSION "616bfd1506a8a75c6a358e578cbec9ca11931502"\n',
does_not_raise(),
),
(
"@VCS_TAG@",
"616bfd1506a8a75c6a358e578cbec9ca11931502",
'#define DAV1D_VERSION "8a651f3a1f40fe73847423fb6a5776103cb42218"\n',
'#define DAV1D_VERSION "616bfd1506a8a75c6a358e578cbec9ca11931502"\n',
pytest.raises(Exception),
),
(
"[regexy pattern]",
"replaced",
"here\nis [regexy pattern]\n",
"here\nis replaced\n",
does_not_raise(),
),
(
"some (other) regex.",
"replaced,",
"This can be some (other) regex. Yo!\n",
"This can be replaced, Yo!\n",
does_not_raise(),
),
],
)
def test_replace_in_file(
tmp_path, pattern, replacement, input_data, expected, exception
):
file = tmp_path / "file.txt"
file.write_text(input_data)
with exception:
_replace_in_file(file, pattern, replacement, regex=False)
assert file.read_text() == expected
@pytest.mark.parametrize(
"pattern,replacement,input_data,expected,exception",
[
(
r"\[tag v[1-9\.]+\]",
"[tag v1.2.13]",
"Version:\n#[tag v1.2.12]\n",
"Version:\n#[tag v1.2.13]\n",
does_not_raise(),
),
(
r"\[tag v[1-9\.]+\]",
"[tag v1.2.13]",
"Version:\n#[tag v1.2.13]\n",
"Version:\n#[tag v1.2.13]\n",
does_not_raise(),
),
(
r"\[tag v[1-9\.]+\]",
"[tag v0.17.0]",
"Version:\n#[tag v0.16.3]\n",
"Version:\n#[tag v0.17.0]\n",
pytest.raises(Exception),
),
(
r"\[tag v[1-9\.]+\]",
"[tag v0.17.0]",
"Version:\n#[tag v0.16.3]\n",
"Version:\n#[tag v0.17.0]\n",
pytest.raises(Exception),
),
(
r'DEFINES\["OPUS_VERSION"\] = "(.+)"',
'DEFINES["OPUS_VERSION"] = "5023249b5c935545fb02dbfe845cae996ecfc8bb"',
'DEFINES["OPUS_BUILD"] = True\nDEFINES["OPUS_VERSION"] = "8a651f3a1f40fe73847423fb6a5776103cb42218"\nDEFINES["USE_ALLOCA"] = True\n',
'DEFINES["OPUS_BUILD"] = True\nDEFINES["OPUS_VERSION"] = "5023249b5c935545fb02dbfe845cae996ecfc8bb"\nDEFINES["USE_ALLOCA"] = True\n',
does_not_raise(),
),
(
r'DEFINES\["OPUS_VERSION"\] = "(.+)"',
'DEFINES["OPUS_VERSION"] = "5023249b5c935545fb02dbfe845cae996ecfc8bb"',
'DEFINES["OPUS_BUILD"] = True\nDEFINES["OPUS_TAG"] = "8a651f3a1f40fe73847423fb6a5776103cb42218"\nDEFINES["USE_ALLOCA"] = True\n',
'DEFINES["OPUS_BUILD"] = True\nDEFINES["OPUS_VERSION"] = "5023249b5c935545fb02dbfe845cae996ecfc8bb"\nDEFINES["USE_ALLOCA"] = True\n',
pytest.raises(Exception),
),
],
)
def test_replace_in_file_regex(
tmp_path, pattern, replacement, input_data, expected, exception
):
file = tmp_path / "file.txt"
file.write_text(input_data)
with exception:
_replace_in_file(file, pattern, replacement, regex=True)
assert file.read_text() == expected
if __name__ == "__main__":
main()

Просмотреть файл

@ -35,18 +35,23 @@ def throwe():
def _replace_in_file(file, pattern, replacement, regex=False):
def replacer(matchobj: re.Match):
if matchobj.group(0) == replacement:
print(f"WARNING: {action} replaced '{matchobj.group(0)}' with same.")
return replacement
with open(file) as f:
contents = f.read()
if regex:
newcontents = re.sub(pattern, replacement, contents)
else:
newcontents = contents.replace(pattern, replacement)
action = "replace-in-file-regex"
if not regex:
pattern = re.escape(pattern)
action = "replace-in-file"
if newcontents == contents:
newcontents, count = re.subn(pattern, replacer, contents)
if count < 1:
raise Exception(
"Could not find '%s' in %s to %sreplace with '%s'"
% (pattern, file, "regex-" if regex else "", replacement)
f"{action} could not find '{pattern}' in {file} to replace with '{replacement}'."
)
with open(file, "w") as f: