1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112

media / ffmpeg / scripts / check_merge.py [blame]

#!/usr/bin/env python3
#
# Copyright 2018 The Chromium Authors.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# Verify HEAD against upstream to see if anything bad has been added to
# HEAD that we would not want to roll.  For example, if HEAD introduces any
# UNCHECKED_BITSTREAM_READERs, then we definitely want to fix that before
# including HEAD in Chromium.
#
# Usage: check_merge.py [new_branch]
# where |new_branch| is the branch that we'd like to compare to upstream.

import os
import re
import sys
import subprocess

# The current good ffmpeg + config that we're diffing against.
EXISTING_COMMIT = "origin/master"  # nocheck

# If any of these regexes match, it indicates failure.  Generally, we want to
# catch any change in how these are defined.  These are checked against things
# that are added with respect to |EXISTING_COMMIT| by the commit we're checking.
#
# Remember that we're going to check ffmpeg files and Chromium files (e.g.,
# the build configs for each platform, ffmpeg_generated.gni, etc.).
# TODO(liberato): consider making these a dictionary, with the value as some
# descriptive text (e.g., the bug number) about why it's not allowed.
INSERTION_TRIPWIRES = [
    # In Chromium, all codecs should use the safe bitstream reader. Roller must
    # undo any new usage of the unchecked reader.
    "^.define.*UNCHECKED_BITSTREAM_READER.*1",

    # In Chromium, explicitly skipping some matroskadec code blocks for
    # the following CONFIG variables (which should remain defined as 0) is
    # necessary to remove code that may be a security risk. Discuss with cevans@
    # before removing these explicit skips or enabling these variables.
    "^.define.*CONFIG_LZO.*1",
    "^.define.*CONFIG_SIPR_DECODER.*1",
    "^.define.*CONFIG_RA_288_DECODER.*1",
    "^.define.*CONFIG_COOK_DECODER.*1",
    "^.define.*CONFIG_ATRAC3_DECODER.*1",

    # Miscellaneous tripwires.
    "^.define.*CONFIG_SPDIF_DEMUXER.*1",
    "^.define.*CONFIG_W64_DEMUXER.*1",
    "^.define.*[Vv]4[Ll]2.*1",
    "^.define.*CONFIG_PRORES_.*1",
]

# Filenames that will be excluded from the regex matching.
# Note: chromium/scripts can be removed once the scripts move out of ffmpeg.
EXCLUDED_FILENAMES = [
    r"^configure$",
    r"^chromium/scripts/",
    r"^chromium/patches/",
]


def search_regexps(text, regexps):
    return [r for r in regexps if re.search(r, text)]


def main(argv):
    # What we're considering merging, and would like to check.  Normally, this
    # is HEAD, but you might want to verify some previous merge.
    if len(argv) > 1:
        new_commit = argv[1]
    else:
        new_commit = "HEAD"

    print(f"Comparing {new_commit} to baseline {EXISTING_COMMIT}...")

    diff = subprocess.Popen(
        ["git", "diff", "-U0", EXISTING_COMMIT, new_commit],
        stdout=subprocess.PIPE).communicate()[0].decode(sys.stdout.encoding)
    filename = None
    skip = False
    files_encountered = 0
    files_skipped = 0
    failures = set()
    for line in diff.splitlines():
        if line.startswith("+++"):
            # +++ b/filename => filename
            filename = line.split("/", 1)[1]
            skip = False
            files_encountered += 1
            if search_regexps(filename, EXCLUDED_FILENAMES):
                skip = True
                files_skipped += 1
        elif line.startswith("+") and not skip:
            # |line| is an insertion into |new_commit|.
            # Drop the leading "+" from the string being searched.
            tripwire = search_regexps(line[1:], INSERTION_TRIPWIRES)
            if tripwire:
                failures.add("Tripwire '%s' found in %s" %
                             (tripwire, filename))

    # If we have failures, then print them and fail.
    if failures:
        for failure in failures:
            print(f"Failure: {failure}")
        sys.exit(2)

    checked = files_encountered - files_skipped
    print(f"No problems found! Checked {checked}, skipped {files_skipped}.")


if __name__ == '__main__':
    main(sys.argv)