Hash :
1239266b
        
        Author :
  
        
        Date :
2025-07-16T16:28:12
        
      
Do not read .git/packed-refs if the git refstorage is reftables Traditionally, git is configured with: extensions.refStorage==file. It means if .git/HEAD stores a symbolic reference, e.g. /refs/heads/main, the hash of main branch is stored in either: 1) .git/refs/heads/main 2) .git/packed-refs However, on the newer version of git where the git is configured with: extensions.refStorage == reftable, neither of the above files exist. Git will store the reference in binary files under .git/reftable. We should add different files as gn action input based on if git is configured with reftable or file backend. Bug: chromium:432289353 Change-Id: Ib42828313f3a7200e55420574a8ddac2ba63f2e4 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6761844 Auto-Submit: Yuxin Hu <yuxinhu@google.com> Reviewed-by: Amirali Abdolrashidi <abdolrashidi@google.com> Commit-Queue: Yuxin Hu <yuxinhu@google.com>
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 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
#!/usr/bin/env python3
#  Copyright 2018 The ANGLE Project Authors. All rights reserved.
#  Use of this source code is governed by a BSD-style license that can be
#  found in the LICENSE file.
# Generate commit.h with git commit hash.
#
import pathlib
import subprocess as sp
import sys
import os
usage = """\
Usage: commit_id.py position               - print commit position
       commit_id.py gen <output> [depfile] - generate commit.h"""
def grab_output(command, cwd):
    return sp.Popen(
        command, stdout=sp.PIPE, shell=True, cwd=cwd).communicate()[0].strip().decode('utf-8')
def get_git_dir(cwd):
    return grab_output('git rev-parse --git-dir', cwd)
def get_git_common_dir(cwd):
    return grab_output('git rev-parse --git-common-dir', cwd)
def get_commit_position(cwd):
    return grab_output('git rev-list HEAD --count', cwd)
def does_git_dir_exist(cwd):
    ret = os.path.exists(os.path.join(cwd, '.git', 'HEAD'))
    # .git may be a file with a gitdir directive pointing elsewhere.
    if not ret and os.path.exists(os.path.join(cwd, '.git')):
        ret = 'true' == grab_output('git rev-parse --is-inside-work-tree', cwd)
    return ret
def unpack_ref(ref_file, ref_file_full_path, packed_refs_full_path):
    with open(packed_refs_full_path) as fin:
        refs = fin.read().strip().split('\n')
    # Strip comments
    refs = [ref.split(' ') for ref in refs if ref.strip()[0] != '#']
    # Parse lines (which are in the format <hash> <ref_file>) and find the input file
    refs = [git_hash for (git_hash, file_path) in refs if file_path == ref_file]
    assert (len(refs) == 1)
    git_hash = refs[0]
    with open(ref_file_full_path, 'w') as fout:
        fout.write(git_hash + '\n')
# Get the files that GN action target angle_commit_id depends on.
# If any of these files changed, the build system should rerun the commit_id.py
# script to regenerate the angle_commit.h
# Case 1: git config extensions.refStorage == file (or empty)
# Case 1.1: .git/HEAD contains the hash.
#           Return .git/HEAD
# Case 1.2: .git/HEAD contains non-hash: e.g. refs/heads/<branch_name>
#           Return .git/HEAD
#           Return .git/refs/heads/<branch_name>
# Case 2: git config extensions.refStorage == reftable
# In this case, HEAD will just store refs/heads/.invalid. If any reference is
# updated, .git/reftable/table.list will be updated.
#           Return .git/reftable/table.list
def get_git_inputs_and_maybe_unpack_ref(cwd):
    # check git extensions.refStorage type
    gitRefStorageType = grab_output('git config --get extensions.refStorage', cwd)
    isRefTableStorage = gitRefStorageType and gitRefStorageType == "reftable"
    git_dir = os.path.normpath(os.path.join(cwd, get_git_dir(cwd)))
    head_file = os.path.join(git_dir, 'HEAD')
    ret = []
    # commit id should depend on angle's HEAD revision only if
    # extensions.refStorage = file.
    # If extensions.refStorage = reftable, .git/HEAD will always contains
    # "refs/heads/.invalid", and we can't rely on it as an indicator of whether
    # to rerun this script.
    if not isRefTableStorage:
        ret.append(head_file)
    git_common_dir = os.path.normpath(os.path.join(cwd, get_git_common_dir(cwd)))
    result = pathlib.Path(head_file).read_text().split()
    if result[0] == "ref:":
        # if the extensions.refStorage is reftable, add .git/reftable/tables.list as an input to gn action target
        if isRefTableStorage:
            ret.append(os.path.join(git_common_dir, 'reftable', 'tables.list'))
        else:
            # if the extensions.refStorage is file, add loose ref file pointed by HEAD
            ref_file = result[1]
            ref_file_full_path = os.path.join(git_common_dir, ref_file)
            if not os.path.exists(ref_file_full_path):
                packed_refs_full_path = os.path.join(git_common_dir, 'packed-refs')
                unpack_ref(ref_file, ref_file_full_path, packed_refs_full_path)
            ret.append(os.path.join(git_common_dir, ref_file))
    return ret
if len(sys.argv) < 2:
    sys.exit(usage)
operation = sys.argv[1]
# Set the root of ANGLE's repo as the working directory
aosp_angle_path = os.path.join(os.path.dirname('.'), 'external', 'angle')
aosp = os.path.exists(aosp_angle_path)
cwd = aosp_angle_path if aosp else os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
git_dir_exists = does_git_dir_exist(cwd)
if operation == 'position':
    if git_dir_exists:
        print(get_commit_position(cwd))
    else:
        print("0")
    sys.exit(0)
if len(sys.argv) < 3 or operation != 'gen':
    sys.exit(usage)
output_file = sys.argv[2]
depfile = sys.argv[3] if len(sys.argv) == 4 else None
commit_id_size = 12
commit_date = 'unknown date'
commit_position = '0'
# If the ANGLE_UPSTREAM_HASH environment variable is set, use it as
# commit_id. commit_date will be 'unknown date' and commit_position will be 0
# in this case. See details in roll_aosp.sh where commit_id.py is invoked.
commit_id = os.environ.get('ANGLE_UPSTREAM_HASH')
# If ANGLE_UPSTREAM_HASH environment variable is not set, use the git command
# to get the git hash, when .git is available
if git_dir_exists and not commit_id:
    try:
        commit_id = grab_output('git rev-parse --short=%d HEAD' % commit_id_size, cwd)
        commit_date = grab_output('git show -s --format=%ci HEAD', cwd) or commit_date
        commit_position = get_commit_position(cwd) or commit_position
    except:
        pass
with open(output_file, 'w') as hfile:
    hfile.write('#define ANGLE_COMMIT_HASH "%s"\n' % (commit_id or "unknown hash"))
    hfile.write('#define ANGLE_COMMIT_HASH_SIZE %d\n' % commit_id_size)
    hfile.write('#define ANGLE_COMMIT_DATE "%s"\n' % commit_date)
    hfile.write('#define ANGLE_COMMIT_POSITION %s\n' % commit_position)
if depfile:
    inputs = []
    if git_dir_exists:
        inputs = get_git_inputs_and_maybe_unpack_ref(cwd)
    with open(depfile, 'w') as f:
        f.write(output_file)
        f.write(': ')
        f.write(' '.join(os.path.relpath(p) for p in inputs))
        f.write('\n')