First Commit
This commit is contained in:
146
3rdparty/shaderc/utils/add_copyright.py
vendored
Executable file
146
3rdparty/shaderc/utils/add_copyright.py
vendored
Executable file
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2015 The Shaderc Authors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Adds copyright notices to all the files that need them under the current
|
||||
directory.
|
||||
|
||||
usage: add_copyright.py [--check]
|
||||
|
||||
With --check, prints out all the files missing the copyright notice and exits
|
||||
with status 1 if any such files are found, 0 if none.
|
||||
"""
|
||||
|
||||
import fileinput
|
||||
import fnmatch
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
COPYRIGHTRE = re.compile(
|
||||
r'Copyright \d+ The Shaderc Authors. All rights reserved.')
|
||||
COPYRIGHT = 'Copyright 2016 The Shaderc Authors. All rights reserved.'
|
||||
LICENSED = """
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License."""
|
||||
|
||||
|
||||
def find(top, filename_glob, skip_glob_list):
|
||||
"""Returns files in the tree rooted at top matching filename_glob but not
|
||||
in directories matching skip_glob_list."""
|
||||
|
||||
file_list = []
|
||||
for path, dirs, files in os.walk(top):
|
||||
for glob in skip_glob_list:
|
||||
for match in fnmatch.filter(dirs, glob):
|
||||
dirs.remove(match)
|
||||
for filename in fnmatch.filter(files, filename_glob):
|
||||
file_list.append(os.path.join(path, filename))
|
||||
return file_list
|
||||
|
||||
|
||||
def filtered_descendants(glob):
|
||||
"""Returns glob-matching filenames under the current directory, but skips
|
||||
some irrelevant paths."""
|
||||
return find('.', glob, ['third_party', 'external', 'build*', 'out*',
|
||||
'CompilerIdCXX', '.venv', 'glslang'])
|
||||
|
||||
|
||||
def skip(line):
|
||||
"""Returns true if line is all whitespace or shebang."""
|
||||
stripped = line.lstrip()
|
||||
return stripped == '' or stripped.startswith('#!')
|
||||
|
||||
|
||||
def comment(text, prefix):
|
||||
"""Returns commented-out text.
|
||||
|
||||
Each line of text will be prefixed by prefix and a space character.
|
||||
Any trailing whitespace will be trimmed.
|
||||
"""
|
||||
accum = []
|
||||
for line in text.split('\n'):
|
||||
accum.append((prefix + ' ' + line).rstrip())
|
||||
return '\n'.join(accum)
|
||||
|
||||
|
||||
def insert_copyright(glob, comment_prefix):
|
||||
"""Finds all glob-matching files under the current directory and inserts
|
||||
the copyright message into them unless they already have it or are empty.
|
||||
|
||||
The copyright message goes into the first non-whitespace, non-
|
||||
shebang line in a file. It is prefixed on each line by
|
||||
comment_prefix and a space.
|
||||
"""
|
||||
copyright = comment(COPYRIGHT, comment_prefix) + '\n'
|
||||
licensed = comment(LICENSED, comment_prefix) + '\n\n'
|
||||
for file in filtered_descendants(glob):
|
||||
has_copyright = False
|
||||
for line in fileinput.input(file, inplace=1):
|
||||
has_copyright = has_copyright or COPYRIGHTRE.search(line)
|
||||
if not has_copyright and not skip(line):
|
||||
sys.stdout.write(copyright)
|
||||
sys.stdout.write(licensed)
|
||||
has_copyright = True
|
||||
sys.stdout.write(line)
|
||||
if not has_copyright:
|
||||
open(file, 'a').write(copyright + licensed)
|
||||
|
||||
|
||||
def alert_if_no_copyright(glob, comment_prefix):
|
||||
"""Prints names of all files missing a copyright message.
|
||||
|
||||
Finds all glob-matching files under the current directory and checks if they
|
||||
contain the copyright message. Prints the names of all the files that
|
||||
don't.
|
||||
|
||||
Returns the total number of file names printed.
|
||||
"""
|
||||
printed_count = 0
|
||||
for file in filtered_descendants(glob):
|
||||
has_copyright = False
|
||||
with open(file) as contents:
|
||||
for line in contents:
|
||||
if COPYRIGHTRE.search(line):
|
||||
has_copyright = True
|
||||
break
|
||||
if not has_copyright:
|
||||
print(file, ' has no copyright message.')
|
||||
printed_count += 1
|
||||
return printed_count
|
||||
|
||||
|
||||
def main():
|
||||
glob_comment_pairs = [('*.h', '//'), ('*.hpp', '//'), ('*.cc', '//'),
|
||||
('*.py', '#'), ('*.cpp', '//')]
|
||||
if '--check' in sys.argv:
|
||||
count = 0
|
||||
for pair in glob_comment_pairs:
|
||||
count += alert_if_no_copyright(*pair)
|
||||
sys.exit(count > 0)
|
||||
else:
|
||||
for pair in glob_comment_pairs:
|
||||
insert_copyright(*pair)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
282
3rdparty/shaderc/utils/git-sync-deps
vendored
Executable file
282
3rdparty/shaderc/utils/git-sync-deps
vendored
Executable file
@@ -0,0 +1,282 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2014 Google Inc.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""Parse a DEPS file and git checkout all of the dependencies.
|
||||
|
||||
Args:
|
||||
An optional list of deps_os values.
|
||||
|
||||
Environment Variables:
|
||||
GIT_EXECUTABLE: path to "git" binary; if unset, will look for one of
|
||||
['git', 'git.exe', 'git.bat'] in your default path.
|
||||
|
||||
GIT_SYNC_DEPS_PATH: file to get the dependency list from; if unset,
|
||||
will use the file ../DEPS relative to this script's directory.
|
||||
|
||||
GIT_SYNC_DEPS_QUIET: if set to non-empty string, suppress messages.
|
||||
|
||||
Git Config:
|
||||
To disable syncing of a single repository:
|
||||
cd path/to/repository
|
||||
git config sync-deps.disable true
|
||||
|
||||
To re-enable sync:
|
||||
cd path/to/repository
|
||||
git config --unset sync-deps.disable
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
from builtins import bytes
|
||||
|
||||
|
||||
def git_executable():
|
||||
"""Find the git executable.
|
||||
|
||||
Returns:
|
||||
A string suitable for passing to subprocess functions, or None.
|
||||
"""
|
||||
envgit = os.environ.get('GIT_EXECUTABLE')
|
||||
searchlist = ['git', 'git.exe', 'git.bat']
|
||||
if envgit:
|
||||
searchlist.insert(0, envgit)
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
for git in searchlist:
|
||||
try:
|
||||
subprocess.call([git, '--version'], stdout=devnull)
|
||||
except (OSError,):
|
||||
continue
|
||||
return git
|
||||
return None
|
||||
|
||||
|
||||
DEFAULT_DEPS_PATH = os.path.normpath(
|
||||
os.path.join(os.path.dirname(__file__), os.pardir, 'DEPS'))
|
||||
|
||||
|
||||
def usage(deps_file_path = None):
|
||||
sys.stderr.write(
|
||||
'Usage: run to grab dependencies, with optional platform support:\n')
|
||||
sys.stderr.write(' %s %s' % (sys.executable, __file__))
|
||||
if deps_file_path:
|
||||
parsed_deps = parse_file_to_dict(deps_file_path)
|
||||
if 'deps_os' in parsed_deps:
|
||||
for deps_os in parsed_deps['deps_os']:
|
||||
sys.stderr.write(' [%s]' % deps_os)
|
||||
sys.stderr.write('\n\n')
|
||||
sys.stderr.write(__doc__)
|
||||
|
||||
|
||||
def git_repository_sync_is_disabled(git, directory):
|
||||
try:
|
||||
disable = subprocess.check_output(
|
||||
[git, 'config', 'sync-deps.disable'], cwd=directory)
|
||||
return disable.lower().strip() in ['true', '1', 'yes', 'on']
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
|
||||
def is_git_toplevel(git, directory):
|
||||
"""Return true iff the directory is the top level of a Git repository.
|
||||
|
||||
Args:
|
||||
git (string) the git executable
|
||||
|
||||
directory (string) the path into which the repository
|
||||
is expected to be checked out.
|
||||
"""
|
||||
try:
|
||||
toplevel = subprocess.check_output(
|
||||
[git, 'rev-parse', '--show-toplevel'], cwd=directory).strip()
|
||||
return os.path.realpath(bytes(directory, 'utf8')) == os.path.realpath(toplevel)
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
|
||||
def status(directory, checkoutable):
|
||||
def truncate(s, length):
|
||||
return s if len(s) <= length else s[:(length - 3)] + '...'
|
||||
dlen = 36
|
||||
directory = truncate(directory, dlen)
|
||||
checkoutable = truncate(checkoutable, 40)
|
||||
sys.stdout.write('%-*s @ %s\n' % (dlen, directory, checkoutable))
|
||||
|
||||
|
||||
def git_checkout_to_directory(git, repo, checkoutable, directory, verbose):
|
||||
"""Checkout (and clone if needed) a Git repository.
|
||||
|
||||
Args:
|
||||
git (string) the git executable
|
||||
|
||||
repo (string) the location of the repository, suitable
|
||||
for passing to `git clone`.
|
||||
|
||||
checkoutable (string) a tag, branch, or commit, suitable for
|
||||
passing to `git checkout`
|
||||
|
||||
directory (string) the path into which the repository
|
||||
should be checked out.
|
||||
|
||||
verbose (boolean)
|
||||
|
||||
Raises an exception if any calls to git fail.
|
||||
"""
|
||||
if not os.path.isdir(directory):
|
||||
subprocess.check_call(
|
||||
[git, 'clone', '--quiet', repo, directory])
|
||||
|
||||
if not is_git_toplevel(git, directory):
|
||||
# if the directory exists, but isn't a git repo, you will modify
|
||||
# the parent repostory, which isn't what you want.
|
||||
sys.stdout.write('%s\n IS NOT TOP-LEVEL GIT DIRECTORY.\n' % directory)
|
||||
return
|
||||
|
||||
# Check to see if this repo is disabled. Quick return.
|
||||
if git_repository_sync_is_disabled(git, directory):
|
||||
sys.stdout.write('%s\n SYNC IS DISABLED.\n' % directory)
|
||||
return
|
||||
|
||||
with open(os.devnull, 'w') as devnull:
|
||||
# If this fails, we will fetch before trying again. Don't spam user
|
||||
# with error infomation.
|
||||
if 0 == subprocess.call([git, 'checkout', '--quiet', checkoutable],
|
||||
cwd=directory, stderr=devnull):
|
||||
# if this succeeds, skip slow `git fetch`.
|
||||
if verbose:
|
||||
status(directory, checkoutable) # Success.
|
||||
return
|
||||
|
||||
# If the repo has changed, always force use of the correct repo.
|
||||
# If origin already points to repo, this is a quick no-op.
|
||||
subprocess.check_call(
|
||||
[git, 'remote', 'set-url', 'origin', repo], cwd=directory)
|
||||
|
||||
subprocess.check_call([git, 'fetch', '--quiet'], cwd=directory)
|
||||
|
||||
subprocess.check_call([git, 'checkout', '--quiet', checkoutable], cwd=directory)
|
||||
|
||||
if verbose:
|
||||
status(directory, checkoutable) # Success.
|
||||
|
||||
|
||||
def parse_file_to_dict(path):
|
||||
dictionary = {}
|
||||
contents = open(path).read()
|
||||
# Need to convert Var() to vars[], so that the DEPS is actually Python. Var()
|
||||
# comes from Autoroller using gclient which has a slightly different DEPS
|
||||
# format.
|
||||
contents = re.sub(r"Var\((.*?)\)", r"vars[\1]", contents)
|
||||
exec(contents, dictionary)
|
||||
return dictionary
|
||||
|
||||
|
||||
def git_sync_deps(deps_file_path, command_line_os_requests, verbose):
|
||||
"""Grab dependencies, with optional platform support.
|
||||
|
||||
Args:
|
||||
deps_file_path (string) Path to the DEPS file.
|
||||
|
||||
command_line_os_requests (list of strings) Can be empty list.
|
||||
List of strings that should each be a key in the deps_os
|
||||
dictionary in the DEPS file.
|
||||
|
||||
Raises git Exceptions.
|
||||
"""
|
||||
git = git_executable()
|
||||
assert git
|
||||
|
||||
deps_file_directory = os.path.dirname(deps_file_path)
|
||||
deps_file = parse_file_to_dict(deps_file_path)
|
||||
dependencies = deps_file['deps'].copy()
|
||||
os_specific_dependencies = deps_file.get('deps_os', dict())
|
||||
if 'all' in command_line_os_requests:
|
||||
for value in list(os_specific_dependencies.values()):
|
||||
dependencies.update(value)
|
||||
else:
|
||||
for os_name in command_line_os_requests:
|
||||
# Add OS-specific dependencies
|
||||
if os_name in os_specific_dependencies:
|
||||
dependencies.update(os_specific_dependencies[os_name])
|
||||
for directory in dependencies:
|
||||
for other_dir in dependencies:
|
||||
if directory.startswith(other_dir + '/'):
|
||||
raise Exception('%r is parent of %r' % (other_dir, directory))
|
||||
list_of_arg_lists = []
|
||||
for directory in sorted(dependencies):
|
||||
if '@' in dependencies[directory]:
|
||||
repo, checkoutable = dependencies[directory].split('@', 1)
|
||||
else:
|
||||
raise Exception("please specify commit or tag")
|
||||
|
||||
relative_directory = os.path.join(deps_file_directory, directory)
|
||||
|
||||
list_of_arg_lists.append(
|
||||
(git, repo, checkoutable, relative_directory, verbose))
|
||||
|
||||
multithread(git_checkout_to_directory, list_of_arg_lists)
|
||||
|
||||
for directory in deps_file.get('recursedeps', []):
|
||||
recursive_path = os.path.join(deps_file_directory, directory, 'DEPS')
|
||||
git_sync_deps(recursive_path, command_line_os_requests, verbose)
|
||||
|
||||
|
||||
def multithread(function, list_of_arg_lists):
|
||||
# for args in list_of_arg_lists:
|
||||
# function(*args)
|
||||
# return
|
||||
threads = []
|
||||
for args in list_of_arg_lists:
|
||||
thread = threading.Thread(None, function, None, args)
|
||||
thread.start()
|
||||
threads.append(thread)
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
|
||||
def main(argv):
|
||||
deps_file_path = os.environ.get('GIT_SYNC_DEPS_PATH', DEFAULT_DEPS_PATH)
|
||||
verbose = not bool(os.environ.get('GIT_SYNC_DEPS_QUIET', False))
|
||||
|
||||
if '--help' in argv or '-h' in argv:
|
||||
usage(deps_file_path)
|
||||
return 1
|
||||
|
||||
git_sync_deps(deps_file_path, argv, verbose)
|
||||
# subprocess.check_call(
|
||||
# [sys.executable,
|
||||
# os.path.join(os.path.dirname(deps_file_path), 'bin', 'fetch-gn')])
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main(sys.argv[1:]))
|
||||
35
3rdparty/shaderc/utils/remove-file-by-suffix.py
vendored
Executable file
35
3rdparty/shaderc/utils/remove-file-by-suffix.py
vendored
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright 2015 The Shaderc Authors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Removes all files with a certain suffix in a given path recursively.
|
||||
|
||||
# Arguments: path suffix
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
path = sys.argv[1]
|
||||
suffix = sys.argv[2]
|
||||
for root, _, filenames in os.walk(path):
|
||||
for filename in filenames:
|
||||
if filename.endswith(suffix):
|
||||
os.remove(os.path.join(root, filename))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
57
3rdparty/shaderc/utils/roll-deps
vendored
Executable file
57
3rdparty/shaderc/utils/roll-deps
vendored
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2019 The Shaderc Authors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Attempts to roll all entries in DEPS to tip-of-tree and create a commit.
|
||||
#
|
||||
# Depends on roll-dep from depot_path being in PATH.
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
function ExitIfIsInterestingError() {
|
||||
local return_code=$1
|
||||
if [[ ${return_code} -ne 0 && ${return_code} -ne 2 ]]; then
|
||||
exit ${return_code}
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
dependencies=("third_party/effcee/"
|
||||
"third_party/glslang/"
|
||||
"third_party/googletest/"
|
||||
"third_party/re2/"
|
||||
"third_party/spirv-headers/"
|
||||
"third_party/spirv-tools/")
|
||||
branch="origin/main"
|
||||
|
||||
# This script assumes it's parent directory is the repo root.
|
||||
repo_path=$(dirname "$0")/..
|
||||
|
||||
cd "$repo_path"
|
||||
|
||||
if [[ $(git diff --stat) != '' ]]; then
|
||||
echo "Working tree is dirty, commit changes before attempting to roll DEPS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "*** Ignore messages about running 'git cl upload' ***"
|
||||
|
||||
set +e
|
||||
|
||||
for dep in ${dependencies[@]}; do
|
||||
echo "Rolling $dep"
|
||||
roll-dep --ignore-dirty-tree --roll-to="${branch}" "${dep}"
|
||||
ExitIfIsInterestingError $?
|
||||
done
|
||||
154
3rdparty/shaderc/utils/update_build_version.py
vendored
Executable file
154
3rdparty/shaderc/utils/update_build_version.py
vendored
Executable file
@@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright 2016 The Shaderc Authors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Updates build-version.inc in the current directory, unless the update is
|
||||
# identical to the existing content.
|
||||
#
|
||||
# Args: <shaderc-dir> <spirv-tools-dir> <glslang-dir>
|
||||
#
|
||||
# For each directory, there will be a line in build-version.inc containing that
|
||||
# directory's "git describe" output enclosed in double quotes and appropriately
|
||||
# escaped.
|
||||
|
||||
import datetime
|
||||
import errno
|
||||
import os.path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
def mkdir_p(directory):
|
||||
"""Make the directory, and all its ancestors as required. Any of the
|
||||
directories are allowed to already exist."""
|
||||
|
||||
if directory == "":
|
||||
# We're being asked to make the current directory.
|
||||
return
|
||||
|
||||
try:
|
||||
os.makedirs(directory)
|
||||
except OSError as e:
|
||||
if e.errno == errno.EEXIST and os.path.isdir(directory):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
def command_output(cmd, directory):
|
||||
"""Runs a command in a directory and returns its standard output stream.
|
||||
|
||||
Captures the standard error stream.
|
||||
|
||||
Raises a RuntimeError if the command fails to launch or otherwise fails.
|
||||
"""
|
||||
p = subprocess.Popen(cmd,
|
||||
cwd=directory,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
(stdout, _) = p.communicate()
|
||||
if p.returncode != 0:
|
||||
raise RuntimeError('Failed to run {} in {}'.format(cmd, directory))
|
||||
return stdout
|
||||
|
||||
|
||||
def deduce_software_version(directory):
|
||||
"""Returns a software version number parsed from the CHANGES file in the
|
||||
given directory.
|
||||
|
||||
The CHANGES file describes most recent versions first.
|
||||
"""
|
||||
|
||||
# Match the first well-formed version-and-date line.
|
||||
# Allow trailing whitespace in the checked-out source code has
|
||||
# unexpected carriage returns on a linefeed-only system such as
|
||||
# Linux.
|
||||
pattern = re.compile(r'^(v\d+\.\d+(-dev|[\.-]rc\d+)?) \d\d\d\d-\d\d-\d\d\s*$')
|
||||
changes_file = os.path.join(directory, 'CHANGES')
|
||||
with open(changes_file, errors='replace') as f:
|
||||
for line in f.readlines():
|
||||
match = pattern.match(line)
|
||||
if match:
|
||||
return match.group(1)
|
||||
raise Exception('No version number found in {}'.format(changes_file))
|
||||
|
||||
|
||||
def describe(directory):
|
||||
"""Returns a string describing the current Git HEAD version as
|
||||
descriptively as possible.
|
||||
|
||||
Runs 'git describe', or alternately 'git rev-parse HEAD', in
|
||||
directory. If successful, returns the output; otherwise returns
|
||||
'unknown hash, <date>'.
|
||||
"""
|
||||
try:
|
||||
# decode() is needed here for Python3 compatibility. In Python2,
|
||||
# str and bytes are the same type, but not in Python3.
|
||||
# Popen.communicate() returns a bytes instance, which needs to be
|
||||
# decoded into text data first in Python3. And this decode() won't
|
||||
# hurt Python2.
|
||||
return command_output(['git', 'describe'], directory).rstrip().decode()
|
||||
except:
|
||||
try:
|
||||
return command_output(
|
||||
['git', 'rev-parse', 'HEAD'], directory).rstrip().decode()
|
||||
except:
|
||||
# This is the fallback case where git gives us no information,
|
||||
# e.g. because the source tree might not be in a git tree.
|
||||
# In this case, usually use a timestamp. However, to ensure
|
||||
# reproducible builds, allow the builder to override the wall
|
||||
# clock time with enviornment variable SOURCE_DATE_EPOCH
|
||||
# containing a (presumably) fixed timestamp.
|
||||
timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))
|
||||
formatted = datetime.date.fromtimestamp(timestamp).isoformat()
|
||||
return 'unknown hash, {}'.format(formatted)
|
||||
|
||||
|
||||
def get_version_string(project, directory):
|
||||
"""Returns a detailed version string for a given project with its
|
||||
directory, which consists of software version string and git description
|
||||
string."""
|
||||
detailed_version_string_lst = [project]
|
||||
if project != 'glslang':
|
||||
detailed_version_string_lst.append(deduce_software_version(directory))
|
||||
detailed_version_string_lst.append(describe(directory).replace('"', '\\"'))
|
||||
return ' '.join(detailed_version_string_lst)
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 5:
|
||||
print(('usage: {} <shaderc-dir> <spirv-tools-dir> <glslang-dir> <output-file>'.format(
|
||||
sys.argv[0])))
|
||||
sys.exit(1)
|
||||
|
||||
projects = ['shaderc', 'spirv-tools', 'glslang']
|
||||
new_content = ''.join([
|
||||
'"{}\\n"\n'.format(get_version_string(p, d))
|
||||
for (p, d) in zip(projects, sys.argv[1:])
|
||||
])
|
||||
|
||||
output_file = sys.argv[4]
|
||||
mkdir_p(os.path.dirname(output_file))
|
||||
|
||||
if os.path.isfile(output_file):
|
||||
with open(output_file, 'r') as f:
|
||||
if new_content == f.read():
|
||||
return
|
||||
with open(output_file, 'w') as f:
|
||||
f.write(new_content)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user