#!/usr/bin/python
|
|
"""
|
After building can be used to replace documentation,
|
and jars with the newly built versions in SVN.
|
"""
|
|
import filecmp
|
import os
|
import pipes
|
import sys
|
|
FILE = 'f'
|
DIR = 'd'
|
NO_EXIST = 'n'
|
|
MIME_TYPES_BY_EXTENSION = {
|
'html': 'text/html;charset=UTF-8',
|
'txt': 'text/plain;charset=UTF-8',
|
'css': 'text/css;charset=UTF-8',
|
'js': 'text/javascript;charset=UTF-8',
|
'jar': 'application/x-java-archive',
|
'xsl': 'text/xml;charset=UTF-8',
|
'gif': 'image/gif',
|
'png': 'image/png'
|
}
|
|
def sync(src_to_dest):
|
"""
|
Syncrhonize the destination file tree with the source file tree
|
in both the current client and in subversion.
|
"""
|
|
def classify(path):
|
if not os.path.exists(path): return NO_EXIST
|
if os.path.isdir(path): return DIR
|
return FILE
|
|
# If we see a case where (conflict) is present, then we need to be
|
# sure to do svn deletes in a separate commit before svn adds.
|
conflict = False
|
# Keep track of changes to make in subversion
|
svn_adds = []
|
svn_deletes = []
|
svn_propsets = {}
|
|
# A bunch of actions that can be taken to synchronize one aspect
|
# of a source file and a destination file
|
def run(argv):
|
"""
|
Prints out a command line that needs to be run.
|
"""
|
print ' '.join([pipes.quote(arg) for arg in argv])
|
|
def svn(verb_and_flags, args):
|
cmd = ['svn']
|
cmd.extend(verb_and_flags)
|
cmd.extend(args)
|
run(cmd)
|
|
def remove(src, dst): run(['rm', dst])
|
|
def svn_delete(src, dst): svn_deletes.append(dst)
|
|
def recurse(src, dst):
|
children = set()
|
if os.path.isdir(src): children.update(os.listdir(src))
|
if os.path.isdir(dst):
|
children.update(os.listdir(dst))
|
children.discard('.svn')
|
for child in children:
|
handle(os.path.join(src, child), os.path.join(dst, child))
|
|
def copy(src, dst): run(['cp', '-f', src, dst])
|
|
def copy_if_different(src, dst):
|
if not filecmp.cmp(src, dst, shallow=0): copy(src, dst)
|
|
def svn_add(src, dst):
|
svn_adds.append(dst)
|
dot = dst.rfind('.')
|
if dot >= 0:
|
mime_type = MIME_TYPES_BY_EXTENSION.get(dst[dot+1:])
|
if mime_type is not None:
|
key = ('svn:mime-type', mime_type)
|
if key not in svn_propsets:
|
svn_propsets[key] = []
|
svn_propsets[key].append(dst)
|
|
def cnf(src, dst): conflict = True
|
|
def mkdir(src, dst): run(['mkdir', dst])
|
|
# The below table contains the actions to take for each possible
|
# scenario.
|
actions = {
|
# src dst actions
|
(NO_EXIST, NO_EXIST): (),
|
(NO_EXIST, FILE) : (remove, svn_delete,),
|
(NO_EXIST, DIR) : (recurse, remove, svn_delete,),
|
(FILE, NO_EXIST): (copy, svn_add,),
|
(FILE, FILE) : (copy_if_different,),
|
(FILE, DIR) : (recurse, remove, svn_delete, copy, svn_add, cnf),
|
(DIR, NO_EXIST): (mkdir, svn_add, recurse,),
|
(DIR, FILE) : (remove, svn_delete, mkdir, svn_add, recurse, cnf),
|
(DIR, DIR) : (recurse,),
|
}
|
|
# Walk the file tree (see recurse action above) and synchronize it at
|
# each step.
|
def handle(src, dst):
|
src_t = classify(src)
|
dst_t = classify(dst)
|
for action in actions[(src_t, dst_t)]: action(src, dst)
|
|
for (src, dst) in src_to_dest:
|
handle(src, dst)
|
|
if len(svn_deletes):
|
svn(['delete'], svn_deletes)
|
if conflict:
|
svn(['commit', '-m', 'remove obsolete files from the snapshot tree'],
|
commit_args)
|
if len(svn_adds):
|
svn(['add', '--depth=empty'], svn_adds)
|
for ((propname, propvalue), files) in svn_propsets.items():
|
svn(['propset', propname, propvalue], files)
|
|
if '__main__' == __name__:
|
sync([(sys.argv[1], sys.argv[2])])
|