Blame client.py

Packit f0b94e
#!/usr/bin/python
Packit f0b94e
# This Source Code Form is subject to the terms of the Mozilla Public
Packit f0b94e
# License, v. 2.0. If a copy of the MPL was not distributed with this
Packit f0b94e
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
Packit f0b94e
Packit f0b94e
Packit f0b94e
LIBFFI_DIRS = (('js/ctypes/libffi', 'libffi'),)
Packit f0b94e
HG_EXCLUSIONS = ['.hg', '.hgignore', '.hgtags']
Packit f0b94e
Packit f0b94e
CVSROOT_LIBFFI = ':pserver:anoncvs@sources.redhat.com:/cvs/libffi'
Packit f0b94e
Packit f0b94e
import os
Packit f0b94e
import sys
Packit f0b94e
import datetime
Packit f0b94e
import shutil
Packit f0b94e
import glob
Packit f0b94e
from optparse import OptionParser
Packit f0b94e
from subprocess import check_call
Packit f0b94e
Packit f0b94e
topsrcdir = os.path.dirname(__file__)
Packit f0b94e
if topsrcdir == '':
Packit f0b94e
    topsrcdir = '.'
Packit f0b94e
Packit f0b94e
def check_call_noisy(cmd, *args, **kwargs):
Packit f0b94e
    print "Executing command:", cmd
Packit f0b94e
    check_call(cmd, *args, **kwargs)
Packit f0b94e
Packit f0b94e
def do_hg_pull(dir, repository, hg):
Packit f0b94e
    fulldir = os.path.join(topsrcdir, dir)
Packit f0b94e
    # clone if the dir doesn't exist, pull if it does
Packit f0b94e
    if not os.path.exists(fulldir):
Packit f0b94e
        check_call_noisy([hg, 'clone', repository, fulldir])
Packit f0b94e
    else:
Packit f0b94e
        cmd = [hg, 'pull', '-u', '-R', fulldir]
Packit f0b94e
        if repository is not None:
Packit f0b94e
            cmd.append(repository)
Packit f0b94e
        check_call_noisy(cmd)
Packit f0b94e
    check_call([hg, 'parent', '-R', fulldir,
Packit f0b94e
                '--template=Updated to revision {node}.\n'])
Packit f0b94e
Packit f0b94e
def do_hg_replace(dir, repository, tag, exclusions, hg):
Packit f0b94e
    """
Packit f0b94e
        Replace the contents of dir with the contents of repository, except for
Packit f0b94e
        files matching exclusions.
Packit f0b94e
    """
Packit f0b94e
    fulldir = os.path.join(topsrcdir, dir)
Packit f0b94e
    if os.path.exists(fulldir):
Packit f0b94e
        shutil.rmtree(fulldir)
Packit f0b94e
Packit f0b94e
    assert not os.path.exists(fulldir)
Packit f0b94e
    check_call_noisy([hg, 'clone', '-u', tag, repository, fulldir])
Packit f0b94e
Packit f0b94e
    for thing in exclusions:
Packit f0b94e
        for excluded in glob.iglob(os.path.join(fulldir, thing)):
Packit f0b94e
            if os.path.isdir(excluded):
Packit f0b94e
                shutil.rmtree(excluded)
Packit f0b94e
            else:
Packit f0b94e
                os.remove(excluded)
Packit f0b94e
Packit f0b94e
def do_cvs_export(modules, tag, cvsroot, cvs):
Packit f0b94e
    """Check out a CVS directory without CVS metadata, using "export"
Packit f0b94e
    modules is a list of directories to check out and the corresponding
Packit f0b94e
    cvs module, e.g. (('js/ctypes/libffi', 'libffi'),)
Packit f0b94e
    """
Packit f0b94e
    for module_tuple in modules:
Packit f0b94e
        module = module_tuple[0]
Packit f0b94e
        cvs_module = module_tuple[1]
Packit f0b94e
        fullpath = os.path.join(topsrcdir, module)
Packit f0b94e
        if os.path.exists(fullpath):
Packit f0b94e
            print "Removing '%s'" % fullpath
Packit f0b94e
            shutil.rmtree(fullpath)
Packit f0b94e
Packit f0b94e
        (parent, leaf) = os.path.split(module)
Packit f0b94e
        print "CVS export begin: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
Packit f0b94e
        check_call_noisy([cvs, '-d', cvsroot,
Packit f0b94e
                          'export', '-r', tag, '-d', leaf, cvs_module],
Packit f0b94e
                         cwd=os.path.join(topsrcdir, parent))
Packit f0b94e
        print "CVS export end: " + datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
Packit f0b94e
Packit f0b94e
def toggle_trailing_blank_line(depname):
Packit f0b94e
  """If the trailing line is empty, then we'll delete it.
Packit f0b94e
  Otherwise we'll add a blank line."""
Packit f0b94e
  lines = open(depname, "r").readlines()
Packit f0b94e
  if not lines:
Packit f0b94e
      print >>sys.stderr, "unexpected short file"
Packit f0b94e
      return
Packit f0b94e
Packit f0b94e
  if not lines[-1].strip():
Packit f0b94e
      # trailing line is blank, removing it
Packit f0b94e
      open(depname, "wb").writelines(lines[:-1])
Packit f0b94e
  else:
Packit f0b94e
      # adding blank line
Packit f0b94e
      open(depname, "ab").write("\n")
Packit f0b94e
Packit f0b94e
def get_trailing_blank_line_state(depname):
Packit f0b94e
  lines = open(depname, "r").readlines()
Packit f0b94e
  if not lines:
Packit f0b94e
      print >>sys.stderr, "unexpected short file"
Packit f0b94e
      return "no blank line"
Packit f0b94e
Packit f0b94e
  if not lines[-1].strip():
Packit f0b94e
      return "has blank line"
Packit f0b94e
  else:
Packit f0b94e
      return "no blank line"
Packit f0b94e
Packit f0b94e
def update_nspr_or_nss(tag, depfile, destination, hgpath):
Packit f0b94e
  destination = destination.rstrip('/')
Packit f0b94e
  permanent_patch_dir = destination + '/patches'
Packit f0b94e
  temporary_patch_dir = destination + '.patches'
Packit f0b94e
  if os.path.exists(temporary_patch_dir):
Packit f0b94e
    print "please clean up leftover directory " + temporary_patch_dir
Packit f0b94e
    sys.exit(2)
Packit f0b94e
  warn_if_patch_exists(permanent_patch_dir)
Packit f0b94e
  # protect patch directory from being removed by do_hg_replace
Packit f0b94e
  if os.path.exists(permanent_patch_dir):
Packit f0b94e
    shutil.move(permanent_patch_dir, temporary_patch_dir)
Packit f0b94e
  # now update the destination
Packit f0b94e
  print "reverting to HG version of %s to get its blank line state" % depfile
Packit f0b94e
  check_call_noisy([options.hg, 'revert', depfile])
Packit f0b94e
  old_state = get_trailing_blank_line_state(depfile)
Packit f0b94e
  print "old state of %s is: %s" % (depfile, old_state)
Packit f0b94e
  do_hg_replace(destination, hgpath, tag, HG_EXCLUSIONS, options.hg)
Packit f0b94e
  new_state = get_trailing_blank_line_state(depfile)
Packit f0b94e
  print "new state of %s is: %s" % (depfile, new_state)
Packit f0b94e
  if old_state == new_state:
Packit f0b94e
    print "toggling blank line in: ", depfile
Packit f0b94e
    toggle_trailing_blank_line(depfile)
Packit f0b94e
  tag_file = destination + "/TAG-INFO"
Packit f0b94e
  print >>file(tag_file, "w"), tag
Packit f0b94e
  # move patch directory back to a subdirectory
Packit f0b94e
  if os.path.exists(temporary_patch_dir):
Packit f0b94e
    shutil.move(temporary_patch_dir, permanent_patch_dir)
Packit f0b94e
Packit f0b94e
def warn_if_patch_exists(path):
Packit f0b94e
  # If the given patch directory exists and contains at least one file,
Packit f0b94e
  # then print warning and wait for the user to acknowledge.
Packit f0b94e
  if os.path.isdir(path) and os.listdir(path):
Packit f0b94e
    print "========================================"
Packit f0b94e
    print "WARNING: At least one patch file exists"
Packit f0b94e
    print "in directory: " + path
Packit f0b94e
    print "You must manually re-apply all patches"
Packit f0b94e
    print "after this script has completed!"
Packit f0b94e
    print "========================================"
Packit f0b94e
    raw_input("Press Enter to continue...")
Packit f0b94e
    return
Packit f0b94e
Packit f0b94e
o = OptionParser(usage="client.py [options] update_nspr tagname | update_nss tagname | update_libffi tagname")
Packit f0b94e
o.add_option("--skip-mozilla", dest="skip_mozilla",
Packit f0b94e
             action="store_true", default=False,
Packit f0b94e
             help="Obsolete")
Packit f0b94e
Packit f0b94e
o.add_option("--cvs", dest="cvs", default=os.environ.get('CVS', 'cvs'),
Packit f0b94e
             help="The location of the cvs binary")
Packit f0b94e
o.add_option("--cvsroot", dest="cvsroot",
Packit f0b94e
             help="The CVSROOT for libffi (default : %s)" % CVSROOT_LIBFFI)
Packit f0b94e
o.add_option("--hg", dest="hg", default=os.environ.get('HG', 'hg'),
Packit f0b94e
             help="The location of the hg binary")
Packit f0b94e
o.add_option("--repo", dest="repo",
Packit f0b94e
             help="the repo to update from (default: upstream repo)")
Packit f0b94e
Packit f0b94e
try:
Packit f0b94e
    options, args = o.parse_args()
Packit f0b94e
    action = args[0]
Packit f0b94e
except IndexError:
Packit f0b94e
    o.print_help()
Packit f0b94e
    sys.exit(2)
Packit f0b94e
Packit f0b94e
if action in ('checkout', 'co'):
Packit f0b94e
    print >>sys.stderr, "Warning: client.py checkout is obsolete."
Packit f0b94e
    pass
Packit f0b94e
elif action in ('update_nspr'):
Packit f0b94e
    tag, = args[1:]
Packit f0b94e
    depfile = "nsprpub/config/prdepend.h"
Packit f0b94e
    if not options.repo:
Packit f0b94e
        options.repo = 'https://hg.mozilla.org/projects/nspr'
Packit f0b94e
    update_nspr_or_nss(tag, depfile, 'nsprpub', options.repo)
Packit f0b94e
elif action in ('update_nss'):
Packit f0b94e
    tag, = args[1:]
Packit f0b94e
    depfile = "security/nss/coreconf/coreconf.dep"
Packit f0b94e
    if not options.repo:
Packit f0b94e
	    options.repo = 'https://hg.mozilla.org/projects/nss'
Packit f0b94e
    update_nspr_or_nss(tag, depfile, 'security/nss', options.repo)
Packit f0b94e
elif action in ('update_libffi'):
Packit f0b94e
    tag, = args[1:]
Packit f0b94e
    if not options.cvsroot:
Packit f0b94e
        options.cvsroot = CVSROOT_LIBFFI
Packit f0b94e
    do_cvs_export(LIBFFI_DIRS, tag, options.cvsroot, options.cvs)
Packit f0b94e
else:
Packit f0b94e
    o.print_help()
Packit f0b94e
    sys.exit(2)