summaryrefslogtreecommitdiffstats
path: root/tools/gn/last_commit_position.py
blob: b710ed0b80897edfef31328a95d432556f450737 (plain)
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
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Writes the most recent "Cr-Commit-Position" value on the master branch
to a C header file.

Usage: last_commit_position.py <dir> <outfile> <headerguard>

  <dir>
    Some directory inside the repo to check. This will be used as the current
    directory when running git. It's best to pass the repo toplevel directory.

  <outfile>
    C header file to write.

  <headerguard>
    String to use as the header guard for the written file.
"""

import os
import re
import subprocess
import sys

def RunGitCommand(directory, command):
  """
  Launches git subcommand.

  Errors are swallowed.

  Returns:
    A process object or None.
  """
  command = ['git'] + command
  # Force shell usage under cygwin. This is a workaround for
  # mysterious loss of cwd while invoking cygwin's git.
  # We can't just pass shell=True to Popen, as under win32 this will
  # cause CMD to be used, while we explicitly want a cygwin shell.
  if sys.platform == 'cygwin':
    command = ['sh', '-c', ' '.join(command)]
  try:
    proc = subprocess.Popen(command,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE,
                            cwd=directory,
                            shell=(sys.platform=='win32'))
    return proc
  except OSError:
    return None


def FetchCommitPosition(directory):
  regex = re.compile(r'\s*Cr-Commit-Position: refs/heads/master@\{#(\d+)\}\s*')

  # Search this far backward in the git log. The commit position should be
  # close to the top. We allow some slop for long commit messages, and maybe
  # there were some local commits after the last "official" one. Having this
  # max prevents us from searching all history in the case of an error.
  max_lines = 2048

  proc = RunGitCommand(directory, ['log'])
  for i in range(max_lines):
    line = proc.stdout.readline()
    if not line:
      return None

    match = regex.match(line)
    if match:
      return match.group(1)

  return None


def WriteHeader(header_file, header_guard, value):
  with open(header_file, 'w') as f:
    f.write('''/* Generated by last_commit_position.py. */

#ifndef %(guard)s
#define %(guard)s

#define LAST_COMMIT_POSITION "%(value)s"

#endif
''' % {'guard': header_guard, 'value': value})


if len(sys.argv) != 4:
  print "Wrong number of arguments"
  sys.exit(1)

git_directory = sys.argv[1]
output_file = sys.argv[2]
header_guard = sys.argv[3]

value = FetchCommitPosition(git_directory)
if not value:
  print "Could not get last commit position."
  sys.exit(1)

WriteHeader(output_file, header_guard, value)