<commit_before>#!/usr/bin/env python
# Copyright 2013 The Swarming Authors. All rights reserved.
# Use of this source code is governed by the Apache v2.0 license that can be
# found in the LICENSE file.

"""Updates an isolateserver instance."""

import logging
import optparse
import os
import subprocess
import sys

import find_gae_sdk

APP_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


def git(cmd):
  return subprocess.check_output(['git'] + cmd, cwd=APP_DIR)


def calculate_version(tag):
  """Returns a tag for a git checkout."""
  describe = git(['describe', 'HEAD']).rstrip()
  if not describe.startswith('baserev-'):
    print >> sys.stderr, 'Make sure to run git fetch --tags'
    sys.exit(1)

  # describe has a format similar to 'baserev-124-g33c3dca'.
  _, pseudo_revision, commit = describe.split('-', 2)
  commit = commit[1:]

  remote = 'origin/master'
  mergebase = git(['merge-base', 'HEAD', remote]).rstrip()
  logging.info('commit: %s, mergebase: %s', commit, mergebase)
  if not mergebase.startswith(commit):
    pristine = False
    # Using a local commit hash is not useful, use the real base commit instead.
    # Trim it to 7 characters like 'git describe' does.
    commit = mergebase[:7]
  else:
    pristine = not git(['diff', mergebase])
    logging.info('was diff clear? %s', pristine)

  version = '%s-%s' % (pseudo_revision, commit)
  if not pristine:
    version += '-tainted'
  if tag:
    version += '-' + tag
  return version


def main():
  parser = optparse.OptionParser(description=sys.modules[__name__].__doc__)
  parser.add_option('-v', '--verbose', action='store_true')
  parser.add_option('-A', '--app-id', help='Defaults to name in app.yaml')
  parser.add_option(
      '-t', '--tag', help='Tag to attach to a tainted version')
  parser.add_option(
      '-s', '--sdk-path',<commit_msg>Change update.py to use the pseudo revision of mergebase, not HEAD.<commit_after>#!/usr/bin/env python
# Copyright 2013 The Swarming Authors. All rights reserved.
# Use of this source code is governed by the Apache v2.0 license that can be
# found in the LICENSE file.

"""Updates an AppEngine instance with the version derived from the current git
checkout state.
"""

import logging
import optparse
import os
import subprocess
import sys

import find_gae_sdk

APP_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


def git(cmd):
  return subprocess.check_output(['git'] + cmd, cwd=APP_DIR)


def get_pseudo_revision(remote, baserev_tag_name):
  """Returns the pseudo revision number and commit hash describing
  the base upstream commit this branch is based on.

  The base upstream commit hash is determined by 'git merge-base'. See the man
  page for more information.

  The pseudo revision is calculated by the number of commits separating the base
  upstream commit from a predetermined tag created with 'git tag'. The proper
  setup is to create a git tag of the earliest commit (the root commit) with:

    git tag -a baserev <earliest commit>

  where 'baserev' matches |baserev_tag_name|. Do not forget to push the tag
  upstream! The earliest commit should be a root commit, e.g. a commit with no
  parent. A git tree can have multiple root commits when git repositories are
  merged together so the developer should select the one that makes the most
  sense. The list of all root commits can be retrieved with:

    git rev-list --parents HEAD | egrep "^[a-f0-9]{40}$"

  Then this function uses 'git describe' which will implicitly use the tag
  created above to count the number of commits separating the tag from the merge
  base commit. This is the pseudo revision number.

  Returns:
    tuple of:
    - pseudo revision number as a int
    - upstream commit hash this branch is based of.
  """
  mergebase = git(['merge-base', 'HEAD', remote]).rstrip()
  describe = git(['describe', mergebase]).rstrip()
  if not describe.startswith(baserev_tag_name + '-'):
    print >> sys.stderr, 'Make sure to run git fetch --tags'
    sys.exit(1)

  # describe has a format similar to 'baserev-124-g33c3dca'.
  _, pseudo_revision, commit = describe.split('-', 2)
  assert commit.startswith('g'), commit
  pseudo_revision = int(pseudo_revision)
  assert mergebase.startswith(commit[1:]), (mergebase, commit)
  return pseudo_revision, mergebase


def calculate_version(tag):
  """Returns a tag for a git checkout.

  Uses the pseudo revision number from the upstream commit this branch is based
  on, the abbreviated commit hash. Adds -tainted if the code is not
  pristine and optionally adds a tag to further describe it.
  """
  pseudo_revision, mergebase = get_pseudo_revision('origin/master', 'baserev')
  head = git(['rev-parse', 'HEAD']).rstrip()

  logging.info('head: %s, mergebase: %s', head, mergebase)
  if head != mergebase:
    pristine = False
  else:
    # Look for local uncommitted diff.
    pristine = not (
        git(['diff', mergebase]) or git(['diff', '--cached', mergebase]))
    logging.info('was diff clear? %s', pristine)

  # Trim it to 7 characters like 'git describe' does. 40 characters is
  # overwhelming!
  version = '%s-%s' % (pseudo_revision, mergebase[:7])
  if not pristine:
    version += '-tainted'
  if tag:
    version += '-' + tag
  return version


def main():
  parser = optparse.OptionParser(description=sys.modules[__name__].__doc__)
  parser.add_option('-v', '--verbose', action='store_true')
  parser.add_option('-A', '--app-id', help='Defaults to name in app.yaml')
  parser.add_option(
      '-t', '--tag', help='Tag to attach to a tainted version')
  parser.add_option(
      '-s', '--sdk-path',
{'fraction_non_alphanumeric': 0.11545988258317025, 'fraction_numerical': 0.007116171499733144, 'mean_word_length': 3.875975715524718, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3898477', 'n_tokens_mistral': 1788, 'n_tokens_neox': 1686, 'n_words': 641}