blob: 07ea2009532db553dadf9b61f9324e881bde2dac [file] [log] [blame]
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# Copyright 2019 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Returns the latest llvm version's hash."""
from __future__ import print_function
from pipes import quote
import argparse
import os
import re
import shutil
import tempfile
from cros_utils import command_executer
from get_google3_llvm_version import LLVMVersion
class LLVMHash(object):
"""Provides two methods to retrieve a llvm hash."""
def __init__(self, log_level='none'):
self._ce = command_executer.GetCommandExecuter(log_level=log_level)
self._llvm_url = 'https://chromium.googlesource.com/external' \
'/github.com/llvm/llvm-project'
@staticmethod
def _CreateTempDirectory():
"""Creates a temporary directory in /tmp."""
return tempfile.mkdtemp()
@staticmethod
def _DeleteTempDirectory(temp_dir):
"""Deletes the directory created by CreateTempDirectory()."""
shutil.rmtree(temp_dir)
def _CloneLLVMRepo(self, temp_dir):
"""Clones the llvm repo."""
clone_cmd = 'git clone %s %s' % (quote(self._llvm_url), quote(temp_dir))
ret, _, err = self._ce.RunCommandWOutput(clone_cmd, print_to_console=False)
if ret: # failed to create repo
raise ValueError('Failed to clone the llvm repo: %s' % err)
def _ParseCommitMessages(self, subdir, hash_vals, llvm_version):
"""Parses the hashes that match the llvm version.
Args:
subdir: The directory where the git history resides.
hash_vals: All the hashes that match the llvm version.
llvm_version: The version to compare to in the commit message.
Returns:
The hash that matches the llvm version.
Raises:
Exception: Failed to parse a commit message.
"""
# create regex
llvm_svn_pattern = re.compile(r'llvm-svn: ([0-9]+)')
# For each hash, grab the last "llvm-svn:" line
# and compare the llvm version of that line against
# the llvm version we are looking for and return
# that hash only if they match.
for cur_commit in hash_vals.splitlines():
cur_hash = cur_commit.split()[0] # get hash
# cmd to output the commit body
find_llvm_cmd = 'git -C %s log --format=%%B -n 1 %s' % \
(quote(subdir), cur_hash)
ret, out, err = self._ce.RunCommandWOutput(
find_llvm_cmd, print_to_console=False)
if ret: # failed to parse the commit message
raise ValueError('Failed to parse commit message: %s' % err)
# find all "llvm-svn:" instances
llvm_versions = llvm_svn_pattern.findall(out)
# check the last llvm version against the llvm version we are looking for
if llvm_versions and int(llvm_versions[-1]) == llvm_version:
return cur_hash
# failed to find the commit hash
raise ValueError('Could not find commit hash.')
def GetGitHashForVersion(self, llvm_git_dir, llvm_version):
"""Finds the commit hash(es) of the llvm version in the git log history.
Args:
llvm_git_dir: The LLVM git directory.
llvm_version: The version to search for in the git log history.
Returns:
A string of the hash corresponding to the llvm version.
Raises:
Exception: The hash was not found in the git log history.
"""
# base directory to search the git log history
subdir = os.path.join(llvm_git_dir, 'llvm')
hash_cmd = """git -C %s log --oneline --no-abbrev --grep \"llvm-svn: %d\"
""" % (quote(subdir), llvm_version)
ret, hash_vals, err = self._ce.RunCommandWOutput(
hash_cmd, print_to_console=False)
if ret: # failed to find hash
raise ValueError('Hash not found: %s' % err)
return self._ParseCommitMessages(subdir, hash_vals, llvm_version)
def GetLLVMHash(self, llvm_version):
"""Retrieves the llvm hash corresponding to the llvm version passed in.
Args:
llvm_version: The llvm version to use as a delimiter.
Returns:
The hash as a string that corresponds to the llvm version.
"""
try:
# create a temporary directory for the LLVM repo
llvm_git_dir = self._CreateTempDirectory()
# clone the "llvm-project" repo
self._CloneLLVMRepo(llvm_git_dir)
# find the hash
hash_value = self.GetGitHashForVersion(llvm_git_dir, llvm_version)
finally:
# delete temporary directory
self._DeleteTempDirectory(llvm_git_dir)
return hash_value
def GetGoogle3LLVMHash(self):
"""Retrieves the google3 llvm hash."""
google3_llvm = LLVMVersion(self._ce.GetLogLevel())
google3_llvm_version = google3_llvm.GetGoogle3LLVMVersion()
return self.GetLLVMHash(google3_llvm_version)
def main():
"""Prints the google3 llvm version.
Parses the command line for the optional command line
arguments.
"""
# create parser and add optional command-line arguments
parser = argparse.ArgumentParser(description='Finds the llvm hash.')
parser.add_argument(
'--log_level',
default='none',
choices=['none', 'quiet', 'average', 'verbose'],
help='the level for the logs (default: %(default)s)')
parser.add_argument('--llvm_version', type=int,
help='the llvm version to use as the delimiter ' \
'(default: uses the google3 llvm version)')
# parse command-line arguments
args_output = parser.parse_args()
cur_log_level = args_output.log_level # get log level
cur_llvm_version = args_output.llvm_version # get llvm version
new_llvm_hash = LLVMHash(log_level=cur_log_level)
if cur_llvm_version: # passed in a specific llvm version
print(new_llvm_hash.GetLLVMHash(cur_llvm_version))
else: # find the google3 llvm hash
print(new_llvm_hash.GetGoogle3LLVMHash())
if __name__ == '__main__':
main()