Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/python
      2 
      3 """
      4 After building can be used to replace documentation,
      5 and jars with the newly built versions in SVN.
      6 """
      7 
      8 import filecmp
      9 import os
     10 import pipes
     11 import sys
     12 
     13 FILE = 'f'
     14 DIR = 'd'
     15 NO_EXIST = 'n'
     16 
     17 MIME_TYPES_BY_EXTENSION = {
     18   'html': 'text/html;charset=UTF-8',
     19   'txt': 'text/plain;charset=UTF-8',
     20   'css': 'text/css;charset=UTF-8',
     21   'js': 'text/javascript;charset=UTF-8',
     22   'jar': 'application/x-java-archive',
     23   'xsl': 'text/xml;charset=UTF-8',
     24   'gif': 'image/gif',
     25   'png': 'image/png'
     26   }
     27 
     28 def sync(src_to_dest):
     29   """
     30   Syncrhonize the destination file tree with the source file tree
     31   in both the current client and in subversion.
     32   """
     33 
     34   def classify(path):
     35     if not os.path.exists(path): return NO_EXIST
     36     if os.path.isdir(path): return DIR
     37     return FILE
     38 
     39   # If we see a case where (conflict) is present, then we need to be
     40   # sure to do svn deletes in a separate commit before svn adds.
     41   conflict = False
     42   # Keep track of changes to make in subversion
     43   svn_adds = []
     44   svn_deletes = []
     45   svn_propsets = {}
     46 
     47   # A bunch of actions that can be taken to synchronize one aspect
     48   # of a source file and a destination file
     49   def run(argv):
     50     """
     51     Prints out a command line that needs to be run.
     52     """
     53     print ' '.join([pipes.quote(arg) for arg in argv])
     54 
     55   def svn(verb_and_flags, args):
     56     cmd = ['svn']
     57     cmd.extend(verb_and_flags)
     58     cmd.extend(args)
     59     run(cmd)
     60 
     61   def remove(src, dst): run(['rm', dst])
     62 
     63   def svn_delete(src, dst): svn_deletes.append(dst)
     64 
     65   def recurse(src, dst):
     66     children = set()
     67     if os.path.isdir(src): children.update(os.listdir(src))
     68     if os.path.isdir(dst):
     69       children.update(os.listdir(dst))
     70     children.discard('.svn')
     71     for child in children:
     72       handle(os.path.join(src, child), os.path.join(dst, child))
     73 
     74   def copy(src, dst): run(['cp', '-f', src, dst])
     75 
     76   def copy_if_different(src, dst):
     77     if not filecmp.cmp(src, dst, shallow=0): copy(src, dst)
     78 
     79   def svn_add(src, dst):
     80     svn_adds.append(dst)
     81     dot = dst.rfind('.')
     82     if dot >= 0:
     83       mime_type = MIME_TYPES_BY_EXTENSION.get(dst[dot+1:])
     84       if mime_type is not None:
     85         key = ('svn:mime-type', mime_type)
     86         if key not in svn_propsets:
     87           svn_propsets[key] = []
     88         svn_propsets[key].append(dst) 
     89 
     90   def cnf(src, dst): conflict = True
     91 
     92   def mkdir(src, dst): run(['mkdir', dst])
     93 
     94   # The below table contains the actions to take for each possible
     95   # scenario.
     96   actions = {
     97   # src        dst        actions
     98     (NO_EXIST, NO_EXIST): (),
     99     (NO_EXIST, FILE)    : (remove, svn_delete,),
    100     (NO_EXIST, DIR)     : (recurse, remove, svn_delete,),
    101     (FILE,     NO_EXIST): (copy, svn_add,),
    102     (FILE,     FILE)    : (copy_if_different,),
    103     (FILE,     DIR)     : (recurse, remove, svn_delete, copy, svn_add, cnf),
    104     (DIR,      NO_EXIST): (mkdir, svn_add, recurse,),
    105     (DIR,      FILE)    : (remove, svn_delete, mkdir, svn_add, recurse, cnf),
    106     (DIR,      DIR)     : (recurse,),
    107     }
    108 
    109   # Walk the file tree (see recurse action above) and synchronize it at
    110   # each step.
    111   def handle(src, dst):
    112     src_t = classify(src)
    113     dst_t = classify(dst)
    114     for action in actions[(src_t, dst_t)]: action(src, dst)
    115 
    116   for (src, dst) in src_to_dest:
    117     handle(src, dst)
    118 
    119   if len(svn_deletes):
    120     svn(['delete'], svn_deletes)
    121     if conflict: 
    122       svn(['commit', '-m', 'remove obsolete files from the snapshot tree'],
    123           commit_args)
    124   if len(svn_adds):
    125     svn(['add', '--depth=empty'], svn_adds)
    126   for ((propname, propvalue), files) in svn_propsets.items():
    127     svn(['propset', propname, propvalue], files)
    128 
    129 if '__main__' == __name__:
    130   sync([(sys.argv[1], sys.argv[2])])
    131