1#!/usr/bin/python -u
2# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""This module creates the version information of this firmware test suite.
7
8This module is expected to be executed from the chroot of a host so that
9it could extract the git repo information to create the version information.
10
11The version file contains a pair of a date-time string and a hash like
12
13  version: 2014-01-23.16:18:24 1feddb865cf3f9c158d8cca17a6e68c71b500571
14
15where the hash is the git hash of the latest patch that satisfies
16both conditions:
17  (1) it could be found in cros/master remote branch on the host, and
18  (2) it modifies firmware_TouchMTB test,
19and the date-time string is the commit time of the above latest patch in the
20format of yyyy-mm-dd.hh:mm:ss.
21
22If the there are any commits on the current local branch on top of the
23above latest patch that have modified this test, the version information
24will be shown like
25
26version: revised since 2014-01-23.16:18:24 1feddb865cf3f9c158d8cca17a6e68c71b500
27571
28
29We use "revised since ..." to indicate that some modifications have been made
30since the above latest patch.
31"""
32
33
34import os
35import re
36import sys
37
38import common
39from common_util import simple_system_output
40
41
42VERSION_FILENAME = '/tmp/.version'
43
44LOCAL_BR = 'HEAD'
45TOT_BR = 'cros/master'
46
47
48def _run_git_cmd(cmd):
49    """Run git command.
50
51    When a server test is invoked, the present working directory may look
52    like "/tmp/test_that.xxxx/..."  To be able to run git commands
53    against the autotest repo, it is required to pushd to autotest project
54    temporarily.
55    """
56    new_cmd = ('pushd %s > /dev/null; %s; popd > /dev/null' %
57               (common.client_dir, cmd))
58    return simple_system_output(new_cmd)
59
60
61def _get_common_ancestor(branch_a, branch_b):
62    """Get the nearest common ancestor of the given branches."""
63    return _run_git_cmd('git merge-base %s %s' % (branch_a, branch_b))
64
65
66def _get_first_commit_matching_pattern(commit, pattern):
67    """Get the first commit previous to this commit that matches the pattern."""
68    cmd = 'git log {} --grep="{}" --pretty=format:"%H" -1'
69    return _run_git_cmd(cmd.format(commit, pattern))
70
71
72def _get_git_commit(branch):
73    return _run_git_cmd('git rev-parse %s' % branch)
74
75
76def _get_date_time(commit):
77    """Get the commit date time in ISO 8601 format."""
78    cmd = 'git log {} --pretty=format:"%ci" -1'
79    ts = _run_git_cmd(cmd.format(commit))
80    date, time, _ = ts.split()
81    return '%s.%s' % (date, time)
82
83
84def create_version_file(version_filename):
85    file_path = os.path.dirname(os.path.abspath(sys.modules[__name__].__file__))
86    result = re.search('site_tests\/(.*?)\/', file_path)
87    if result is None:
88        print 'Failed to find the test name.'
89    test_name = result.group(1)
90    common_ancestor = _get_common_ancestor(LOCAL_BR, TOT_BR)
91    latest_test_commit = _get_first_commit_matching_pattern(common_ancestor,
92                                                            test_name)
93    date_time_str = _get_date_time(latest_test_commit)
94
95    local_commit = _get_git_commit(LOCAL_BR)
96    if local_commit == latest_test_commit:
97        version_template = 'version: %s %s '
98    else:
99        version_template = 'version: revised since %s %s '
100
101    version_info = version_template % (date_time_str, latest_test_commit)
102    with open(version_filename, 'w') as version_file:
103        version_file.write(version_info)
104
105
106if __name__ == '__main__':
107    version_filename = sys.argv[1] if len(sys.argv) > 1 else VERSION_FILENAME
108    create_version_file(version_filename)
109