|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# |
| 3 | +# Copyright 2018 The Chromium Authors. |
| 4 | +# Use of this source code is governed by a BSD-style license that can be |
| 5 | +# found in the LICENSE file. |
| 6 | +# |
| 7 | +# Verify HEAD against upstream to see if anything bad has been added to |
| 8 | +# HEAD that we would not want to roll. For example, if HEAD introduces any |
| 9 | +# UNCHECKED_BITSTREAM_READERs, then we definitely want to fix that before |
| 10 | +# including HEAD in Chromium. |
| 11 | +# |
| 12 | +# Usage: check_merge.py [new_branch] |
| 13 | +# where |new_branch| is the branch that we'd like to compare to upstream. |
| 14 | + |
| 15 | +import os |
| 16 | +import re |
| 17 | +import sys |
| 18 | +import subprocess |
| 19 | + |
| 20 | +# The current good ffmpeg + config that we're diffing against. |
| 21 | +EXISTING_COMMIT = "origin/master" # nocheck |
| 22 | + |
| 23 | +# If any of these regexes match, it indicates failure. Generally, we want to |
| 24 | +# catch any change in how these are defined. These are checked against things |
| 25 | +# that are added with respect to |EXISTING_COMMIT| by the commit we're checking. |
| 26 | +# |
| 27 | +# Remember that we're going to check ffmpeg files and Chromium files (e.g., |
| 28 | +# the build configs for each platform, ffmpeg_generated.gni, etc.). |
| 29 | +# TODO(liberato): consider making these a dictionary, with the value as some |
| 30 | +# descriptive text (e.g., the bug number) about why it's not allowed. |
| 31 | +INSERTION_TRIPWIRES = [ |
| 32 | + # In Chromium, all codecs should use the safe bitstream reader. Roller must |
| 33 | + # undo any new usage of the unchecked reader. |
| 34 | + "^.define.*UNCHECKED_BITSTREAM_READER.*1", |
| 35 | + |
| 36 | + # In Chromium, explicitly skipping some matroskadec code blocks for |
| 37 | + # the following CONFIG variables (which should remain defined as 0) is |
| 38 | + # necessary to remove code that may be a security risk. Discuss with cevans@ |
| 39 | + # before removing these explicit skips or enabling these variables. |
| 40 | + "^.define.*CONFIG_LZO.*1", |
| 41 | + "^.define.*CONFIG_SIPR_DECODER.*1", |
| 42 | + "^.define.*CONFIG_RA_288_DECODER.*1", |
| 43 | + "^.define.*CONFIG_COOK_DECODER.*1", |
| 44 | + "^.define.*CONFIG_ATRAC3_DECODER.*1", |
| 45 | + |
| 46 | + # Miscellaneous tripwires. |
| 47 | + "^.define.*CONFIG_SPDIF_DEMUXER.*1", |
| 48 | + "^.define.*CONFIG_W64_DEMUXER.*1", |
| 49 | + "^.define.*[Vv]4[Ll]2.*1", |
| 50 | + "^.define.*CONFIG_PRORES_.*1", |
| 51 | +] |
| 52 | + |
| 53 | +# Filenames that will be excluded from the regex matching. |
| 54 | +# Note: chromium/scripts can be removed once the scripts move out of ffmpeg. |
| 55 | +EXCLUDED_FILENAMES = [ |
| 56 | + r"^configure$", |
| 57 | + r"^chromium/scripts/", |
| 58 | + r"^chromium/patches/", |
| 59 | +] |
| 60 | + |
| 61 | + |
| 62 | +def search_regexps(text, regexps): |
| 63 | + return [r for r in regexps if re.search(r, text)] |
| 64 | + |
| 65 | + |
| 66 | +def main(argv): |
| 67 | + # What we're considering merging, and would like to check. Normally, this |
| 68 | + # is HEAD, but you might want to verify some previous merge. |
| 69 | + if len(argv) > 1: |
| 70 | + new_commit = argv[1] |
| 71 | + else: |
| 72 | + new_commit = "HEAD" |
| 73 | + |
| 74 | + print(f"Comparing {new_commit} to baseline {EXISTING_COMMIT}...") |
| 75 | + |
| 76 | + diff = subprocess.Popen( |
| 77 | + ["git", "diff", "-U0", EXISTING_COMMIT, new_commit], |
| 78 | + stdout=subprocess.PIPE).communicate()[0].decode(sys.stdout.encoding) |
| 79 | + filename = None |
| 80 | + skip = False |
| 81 | + files_encountered = 0 |
| 82 | + files_skipped = 0 |
| 83 | + failures = set() |
| 84 | + for line in diff.splitlines(): |
| 85 | + if line.startswith("+++"): |
| 86 | + # +++ b/filename => filename |
| 87 | + filename = line.split("/", 1)[1] |
| 88 | + skip = False |
| 89 | + files_encountered += 1 |
| 90 | + if search_regexps(filename, EXCLUDED_FILENAMES): |
| 91 | + skip = True |
| 92 | + files_skipped += 1 |
| 93 | + elif line.startswith("+") and not skip: |
| 94 | + # |line| is an insertion into |new_commit|. |
| 95 | + # Drop the leading "+" from the string being searched. |
| 96 | + tripwire = search_regexps(line[1:], INSERTION_TRIPWIRES) |
| 97 | + if tripwire: |
| 98 | + failures.add("Tripwire '%s' found in %s" % |
| 99 | + (tripwire, filename)) |
| 100 | + |
| 101 | + # If we have failures, then print them and fail. |
| 102 | + if failures: |
| 103 | + for failure in failures: |
| 104 | + print(f"Failure: {failure}") |
| 105 | + sys.exit(2) |
| 106 | + |
| 107 | + checked = files_encountered - files_skipped |
| 108 | + print(f"No problems found! Checked {checked}, skipped {files_skipped}.") |
| 109 | + |
| 110 | + |
| 111 | +if __name__ == '__main__': |
| 112 | + main(sys.argv) |
0 commit comments