Make gn --version work

Because GN_BUILD wasn't defined, gn --version was silently "UNKNOWN".
Implement a --version similar to the version that was used in Chromium
by using the number of commits on master + a fixed base larger than the
last commit position in Chromium. This will only really be meaningful
when built by the bots, but that's probably OK.

Change-Id: I744e2ae48cefd80eeb8d352ad67eda9daaac2385
Reviewed-on: https://gn-review.googlesource.com/1980
Reviewed-by: Brett Wilson <brettw@chromium.org>
Commit-Queue: Scott Graham <scottmg@chromium.org>
diff --git a/build/gen.py b/build/gen.py
index 41ed3cd..6fdf6ef 100755
--- a/build/gen.py
+++ b/build/gen.py
@@ -40,10 +40,39 @@
   out_dir = os.path.join(REPO_ROOT, 'out')
   if not os.path.isdir(out_dir):
     os.makedirs(out_dir)
-  write_gn_ninja(os.path.join(out_dir, 'build.ninja'), options, linux_sysroot)
+  GenerateLastCommitPosition(os.path.join(out_dir, 'last_commit_position.h'))
+  WriteGNNinja(os.path.join(out_dir, 'build.ninja'), options, linux_sysroot)
   return 0
 
 
+def GenerateLastCommitPosition(header):
+  # When gn was forked from Chromium the revisions were ~550000. Use 600000 as a
+  # non-conflicting base that also makes it relatively easy to see that it's
+  # built from a post-fork build.
+  BASE_COMMIT_POSITION = 600000
+  commit_position = int(len(
+      subprocess.check_output('git log --oneline', shell=True).splitlines()))
+  contents = '''// Generated by build/gen.py.
+
+#ifndef OUT_LAST_COMMIT_POSITION_H_
+#define OUT_LAST_COMMIT_POSITION_H_
+
+#define LAST_COMMIT_POSITION "%d"
+
+#endif  // OUT_LAST_COMMIT_POSITION_H_
+''' % (BASE_COMMIT_POSITION + commit_position)
+
+  # Only write/touch this file if the commit position has changed.
+  old_contents = ''
+  if os.path.isfile(header):
+    with open(header, 'rb') as f:
+      old_contents = f.read()
+
+  if old_contents != contents:
+    with open(header, 'wb') as f:
+      f.write(contents)
+
+
 def UpdateLinuxSysroot():
   # Sysroot revision from:
   # https://cs.chromium.org/chromium/src/build/linux/sysroot_scripts/sysroots.json
@@ -88,10 +117,10 @@
   return sysroot
 
 
-def write_generic_ninja(path, static_libraries, executables,
-                        cc, cxx, ar, ld, options,
-                        cflags=[], cflags_cc=[], ldflags=[], libflags=[],
-                        include_dirs=[], solibs=[]):
+def WriteGenericNinja(path, static_libraries, executables,
+                      cc, cxx, ar, ld, options,
+                      cflags=[], cflags_cc=[], ldflags=[], libflags=[],
+                      include_dirs=[], solibs=[]):
   ninja_header_lines = [
     'cc = ' + cc,
     'cxx = ' + cxx,
@@ -191,7 +220,7 @@
             os.path.relpath(template_filename, os.path.dirname(path)) + '\n')
 
 
-def write_gn_ninja(path, options, linux_sysroot):
+def WriteGNNinja(path, options, linux_sysroot):
   if is_win:
     cc = os.environ.get('CC', 'cl.exe')
     cxx = os.environ.get('CXX', 'cl.exe')
@@ -580,9 +609,9 @@
   executables['gn']['libs'].extend(static_libraries.keys())
   executables['gn_unittests']['libs'].extend(static_libraries.keys())
 
-  write_generic_ninja(path, static_libraries, executables, cc, cxx, ar, ld,
-                      options, cflags, cflags_cc, ldflags, libflags,
-                      include_dirs, libs)
+  WriteGenericNinja(path, static_libraries, executables, cc, cxx, ar, ld,
+                    options, cflags, cflags_cc, ldflags, libflags, include_dirs,
+                    libs)
 
 
 if __name__ == '__main__':
diff --git a/tools/gn/gn_main.cc b/tools/gn/gn_main.cc
index a38aa42..b18c211 100644
--- a/tools/gn/gn_main.cc
+++ b/tools/gn/gn_main.cc
@@ -16,13 +16,7 @@
 #include "util/msg_loop.h"
 #include "util/sys_info.h"
 
-// Only the GN-generated build makes this header for now.
-// TODO(brettw) consider adding this if we need it in GYP.
-#if defined(GN_BUILD)
-#include "tools/gn/last_commit_position.h"
-#else
-#define LAST_COMMIT_POSITION "UNKNOWN"
-#endif
+#include "out/last_commit_position.h"
 
 namespace {
 
diff --git a/tools/gn/last_commit_position.py b/tools/gn/last_commit_position.py
deleted file mode 100644
index a91f722..0000000
--- a/tools/gn/last_commit_position.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# 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:
-  value = 'UNKNOWN'
-
-WriteHeader(output_file, header_guard, value)