xref: /aosp_15_r20/external/deqp/scripts/src_util/common.py (revision 35238bce31c2a825756842865a792f8cf7f89930)
1# -*- coding: utf-8 -*-
2
3#-------------------------------------------------------------------------
4# drawElements Quality Program utilities
5# --------------------------------------
6#
7# Copyright 2015 The Android Open Source Project
8#
9# Licensed under the Apache License, Version 2.0 (the "License");
10# you may not use this file except in compliance with the License.
11# You may obtain a copy of the License at
12#
13#      http://www.apache.org/licenses/LICENSE-2.0
14#
15# Unless required by applicable law or agreed to in writing, software
16# distributed under the License is distributed on an "AS IS" BASIS,
17# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18# See the License for the specific language governing permissions and
19# limitations under the License.
20#
21#-------------------------------------------------------------------------
22
23import os
24import subprocess
25import sys
26
27TEXT_FILE_EXTENSION = [
28    ".bat",
29    ".c",
30    ".cfg",
31    ".cmake",
32    ".cpp",
33    ".css",
34    ".h",
35    ".hh",
36    ".hpp",
37    ".html",
38    ".inl",
39    ".java",
40    ".js",
41    ".m",
42    ".mk",
43    ".mm",
44    ".py",
45    ".rule",
46    ".sh",
47    ".test",
48    ".txt",
49    ".xml",
50    ".xsl",
51    ]
52
53BINARY_FILE_EXTENSION = [
54    ".bin",
55    ".png",
56    ".pkm",
57    ".xcf",
58    ".nspv",
59    ".h264",
60    ".h265",
61    ".ivf",
62    ".obu",
63    ".mp4",
64    ".yuv"
65]
66
67def isTextFile (filePath):
68    # Special case for a preprocessor test file that uses a non-ascii/utf8 encoding
69    if filePath.endswith("preprocessor.test"):
70        return False
71    # Special case for clang-format which is a baked binary from clang
72    if filePath.endswith("clang-format"):
73        return False
74
75    ext = os.path.splitext(filePath)[1]
76    if ext in TEXT_FILE_EXTENSION:
77        return True
78    if ext in BINARY_FILE_EXTENSION:
79        return False
80
81    # Analyze file contents, zero byte is the marker for a binary file
82    f = open(filePath, "rb")
83
84    TEST_LIMIT = 1024
85    nullFound = False
86    numBytesTested = 0
87
88    byte = f.read(1)
89    while byte and numBytesTested < TEST_LIMIT:
90        if byte == "\0":
91            nullFound = True
92            break
93
94        byte = f.read(1)
95        numBytesTested += 1
96
97    f.close()
98    return not nullFound
99
100def getProjectPath ():
101    # File system hierarchy is fixed
102    scriptDir = os.path.dirname(os.path.abspath(__file__))
103    projectDir = os.path.normpath(os.path.join(scriptDir, "../.."))
104    return projectDir
105
106def git (*args):
107    process = subprocess.Popen(['git'] + list(args), cwd=getProjectPath(), stdout=subprocess.PIPE)
108    output = process.communicate()[0]
109    if process.returncode != 0:
110        raise Exception("Failed to execute '%s', got %d" % (str(args), process.returncode))
111    return output
112
113def getAbsolutePathPathFromProjectRelativePath (projectRelativePath):
114    return os.path.normpath(os.path.join(getProjectPath(), projectRelativePath))
115
116def getChangedFiles ():
117    # Added, Copied, Moved, Renamed
118    output = git('diff', '--cached', '--name-only', '-z', '--diff-filter=ACMR')
119    if not output:
120        return []
121    relativePaths = output.decode().split('\0')[:-1] # remove trailing ''
122    return [getAbsolutePathPathFromProjectRelativePath(path) for path in relativePaths]
123
124def getFilesChangedSince (commit):
125    # Get all the files changed since a given commit
126    output = git('diff', '--name-only', '-U0', '-z', '--no-color', '--no-relative', '--diff-filter=ACMR', commit)
127    relativePaths = output.decode().split('\0')[:-1] # remove trailing ''
128    return [getAbsolutePathPathFromProjectRelativePath(path) for path in relativePaths]
129
130def getFilesCurrentlyDirty ():
131    # Get all the files currently dirty and uncommitted
132    return getFilesChangedSince('HEAD')
133
134def getFilesModifiedSinceLastCommit ():
135    # Try to get only the modified files.  In a shallow clone with depth 1,
136    # HEAD^ doesn't exist, so we have no choice but to return all the files.
137    try:
138        return getFilesChangedSince('HEAD^')
139    except:
140        return getAllProjectFiles()
141
142def getAllProjectFiles ():
143    output = git('ls-files', '--cached', '-z').decode()
144    relativePaths = output.split('\0')[:-1] # remove trailing ''
145    return [getAbsolutePathPathFromProjectRelativePath(path) for path in relativePaths]
146
147def runCommand (command):
148    process = runCommandAsync(command)
149    waitAsyncCommand(process, command)
150
151def runCommandAsync (command):
152    try:
153        return subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
154    except OSError as e:
155        raise RuntimeError('Failed to run command "%s": %s' % (' '.join(command), e.strerror))
156
157def waitAsyncCommand (process, command):
158    (out, err) = process.communicate()
159    if process.returncode == 0:
160        return out
161    else:
162        print('Failed to run command "%s": %s' % (' '.join(command), err))
163        sys.exit(process.returncode)
164