text: #!/usr/bin/env python
  # -*- coding: utf-8 -*-
  """
      make-release
      ~~~~~~~~~~~~
  
      Helper script that performs a release.  Does pretty much everything
      automatically for us.
  
      :copyright: (c) 2011 by Armin Ronacher.
      :license: BSD, see LICENSE for more details.
  """
  import sys
  import os
  import re
  from datetime import datetime, date
  from subprocess import Popen, PIPE
  
  
  _date_strip_re = re.compile(r'(?<=\d)(st|nd|rd|th)')
  
  
  def parse_changelog():
      with open('CHANGES') as f:
          lineiter = iter(f)
          for line in lineiter:
              match = re.search('^Version\s+(.*)', line.strip())
              if match is None:
                  continue
              length = len(match.group(1))
              version = match.group(1).strip()
              if lineiter.next().count('-') != len(match.group(0)):
                  continue
              while 1:
                  change_info = lineiter.next().strip()
                  if change_info:
                      break
  
              match = re.search(r'(?:codename (.*),\s*)?'
                                r'released on (\w+\s+\d+\w+\s+\d+)(?i)',
                                change_info)
              if match is None:
                  continue
  
              codename, datestr = match.groups()
              return version, parse_date(datestr), codename
  
  
  def bump_version(version):
      try:
          parts = map(int, version.split('.'))
      except ValueError:
          fail('Current version is not numeric')
      parts[-1] += 1
      return '.'.join(map(str, parts))
  
  
  def parse_date(string):
      string = _date_strip_re.sub('', string)
      return datetime.strptime(string, '%B %d %Y')
  
  
  def set_filename_version(filename, version_number, pattern):
      changed = []
      def inject_version(match):
          before, old, after = match.groups()
          changed.append(True)
          return before + version_number + after
      with open(filename) as f:
          contents = re.sub(r"^(\s*%s\s*=\s*')(.+?)(')(?sm)" % pattern,
                            inject_version, f.read())
  
      if not changed:
          fail('Could not find %s in %s', pattern, filename)
  
      with open(filename, 'w') as f:
          f.write(contents)
  
  
  def set_init_version(version):
      info('Setting __init__.py version to %s', version)
      set_filename_version('jinja2/__init__.py', version, '__version__')
  
  
  def set_setup_version(version):
      info('Setting setup.py version to %s', version)
      set_filename_version('setup.py', version, 'version')
  
  
  def build_and_upload():
      Popen([sys.executable, 'setup.py', 'release', 'sdist', 'upload']).wait()
  
  
  def fail(message, *args):
      print >> sys.stderr, 'Error:', message % args
      sys.exit(1)
  
  
  def info(message, *args):
      print >> sys.stderr, message % args
  
  
  def get_git_tags():
      return set(Popen(['git', 'tag'], stdout=PIPE).communicate()[0].splitlines())
  
  
  def git_is_clean():
      return Popen(['git', 'diff', '--quiet']).wait() == 0
  
  
  def make_git_commit(message, *args):
      message = message % args
      Popen(['git', 'commit', '-am', message]).wait()
  
  
  def make_git_tag(tag):
      info('Tagging "%s"', tag)
      Popen(['git', 'tag', tag]).wait()
  
  
  def main():
      os.chdir(os.path.join(os.path.dirname(__file__), '..'))
  
      rv = parse_changelog()
      if rv is None:
          fail('Could not parse changelog')
  
      version, release_date, codename = rv
      dev_version = bump_version(version) + '-dev'
  
      info('Releasing %s (codename %s, release date %s)',
           version, codename, release_date.strftime('%d/%m/%Y'))
      tags = get_git_tags()
  
      if version in tags:
          fail('Version "%s" is already tagged', version)
      if release_date.date() != date.today():
          fail('Release date is not today (%s != %s)', release_date.date(), date.today())
  
      if not git_is_clean():
          fail('You have uncommitted changes in git')
  
      set_init_version(version)
      set_setup_version(version)
      make_git_commit('Bump version number to %s', version)
      make_git_tag(version)
      build_and_upload()
      set_init_version(dev_version)
      set_setup_version(dev_version)
  
  
  if __name__ == '__main__':
      main()
  