Personal tools
You are here: Home Developers Corner General cvsScripts.py
Document Actions

cvsScripts.py

Scripts to handle cvs in the context of multiple branches and multiple repositories

Click here to get the file

Size 12.3 kB - File type text/python-source

File contents

""" CVS housekeeping scripts, to use with multi-branch multi-repository setup.

Based on the copyfromrep.py script by Wim Vranken (Thanks, Wim).

June 2007, CCPN (Rasmus Fogh)
"""

import os, sys, shutil


# generated endings
# files that must be removed to make sure they are generated again
genEndings = ('.pyc', '.pyo', '$py.class', '.~odp', '.~odm')
# files taht should cause a warning if found in repository directory
warnGenEndings = ('.pyc', '.pyo')

# names that should be skipped
skipnames = ('CVS','.cvsignore','CVSROOT','.project')

# genDirs = directories that should be generated only
# currently empty  - all candidates had exceptions
warnnames = ()

# special cases - files and directories that should not be signalled as new
# give endigns of full file names
checkEndings = ('/all/python/ccpnmr/api', '/all/python/ccpnmr/xml', 
                '/all/python/memops/api', '/all/python/memops/xml', 
                '/all/python/ccp/api', '/all/python/ccp/xml', )

# working dir directory name
workDirName = 'all'

# repository names
repNames = ('ccpn', 'ccpnint')

def checkAll():
  """ Check working directory against all repositories and report new files
  """
  
  skiplist = skipnames + warnnames
  
  curDir = os.getcwd()
  
  # set up for cvsroot
  cvsroot = os.environ.get('CCPNROOT')
  cvsrootlist = splitall(cvsroot)
  cvsdepth = len(cvsrootlist)
  
  dirlist = splitall(curDir)
  if dirlist[:cvsdepth] != cvsrootlist:
    print ('input file directory %s is not within %s.\nAborting\n' 
           %(curDir, cvsroot)) 
    return
  
  if dirlist[cvsdepth + 1] != workDirName:
    print ('input file directory %s is not within %s/???/%s.\nAborting\n' 
           %(curDir, cvsroot, workDirName)) 
    return
  
  branchDir = os.path.join(cvsroot, dirlist[cvsdepth])
  workingDir = os.path.join(branchDir, workDirName)
  repDirs = [os.path.join(branchDir, x) for x in repNames]
  
  # Check for new files in working dir
  # depth-first loop over directories:
  dirPaths = [curDir]
  while dirPaths:
    dirPath = dirPaths.pop()
  
    # loop over files to copy
    for fileName in os.listdir(dirPath):
 
      if fileName in skiplist:
        # these are always ignored
        continue
 
      filePath = os.path.join(dirPath, fileName)
           
        
      if [x for x in genEndings if fileName.endswith(x)]:
        pass
        
      elif [x for x in checkEndings if filePath.endswith(x)]:
        pass
      
      elif os.path.islink(filePath):
        pass
      
      elif os.path.isfile(filePath):
        for repDir in repDirs:
          if os.path.isfile(filePath.replace(workingDir, repDir)):
            break
        else:
          print 'NEW FILE :', filePath
      
      elif os.path.isdir(filePath):
        for repDir in repDirs:
          if os.path.isdir(filePath.replace(workingDir, repDir)):
            dirPaths.append(filePath)
            break
        else:
          print 'NEW DIR  :', filePath
  
  
  # check for files in repository dirs that are not checked in
  for repDir in repDirs:
    dirPaths = [curDir.replace(workingDir, repDir)]
    while dirPaths:
      dirPath = dirPaths.pop()
      cvsEntries = os.path.join(dirPath, 'CVS', 'Entries')
      if not os.path.isfile(cvsEntries):
        print "NO CVS DIR :",  dirPath
        continue
      entries = open(cvsEntries).read()
 
      # loop over files to copy
      for fileName in os.listdir(dirPath):
 
        if fileName in skiplist:
          # these are always ignored
          continue
 
        elif [x for x in genEndings if fileName.endswith(x)]:
          continue
 
        filePath = os.path.join(dirPath, fileName)
 
 
        if  os.path.islink(filePath):
          raise ("File %s in repository directory is a link." % filePath)
 
        else:
          if entries.find('/%s/' % fileName) == -1:
            print 'NOT IN CVS :', filePath
      
          elif os.path.isdir(filePath):
            dirPaths.append(filePath)
          
  
  
  print '... finished checking'

def updateAll(mode='copy'):
  """Update all repositories and update the links in workDirName
  """
  origDir = os.getcwd()
  
  # set up for cvsroot
  cvsroot = os.environ.get('CCPNROOT')
  cvsrootlist = splitall(cvsroot)
  cvsdepth = len(cvsrootlist)
  
  dirlist = splitall(origDir)
  if dirlist[:cvsdepth] != cvsrootlist:
    print ('input file directory %s is not within %s.\nAborting\n' 
           %(origDir, cvsroot)) 
    return
  
  repCode = dirlist[cvsdepth + 1]
  if repCode == workDirName:
    targetDir = origDir
    sourceDirs = []
    for ss in repNames:
      dirlist[cvsdepth + 1] = ss
      sourceDirs.append(os.path.join(*dirlist))
  else:
    sourceDirs = [origDir]
    dirlist[cvsdepth + 1] = workDirName
    targetDir = os.path.join(*dirlist)
  
  for sourceDir in sourceDirs:
    if os.path.exists(sourceDir):
      os.chdir(sourceDir)
      os.system('cvs update -dP .')
      updateWorkingDir(targetDir, sourceDir, mode) 
  
  
def addFiles (repCode, *infiles):
  """ Add files to repository with repCode=repCode
  copy file to target location, remocve from source, replace with softlink, 
  and cvs add in target location.
  Assumes that you are under {$CCPNROOT}/aBranch/all,
  and adds files in {$CCPNROOT}/aBranch/repCode
  NB all files must be in the same directory
  """
  
  if not infiles:
    print 'No files passed to addFiles. \nAborting\n.'
    return
  
  if repCode == workDirName:
    print 'Target repository was set to %s. \nAborting\n.' % repCode
    return
  
  # set up for cvsroot
  cvsroot = os.environ.get('CCPNROOT')
  cvsrootlist = splitall(cvsroot)
  cvsdepth = len(cvsrootlist)
  
  # validate directory
  sources = [os.path.abspath(ff) for ff in infiles]
  indir = os.path.dirname(sources[0])
  dirlist = splitall(indir)
  if dirlist[:cvsdepth] != cvsrootlist:
    print ('input file directory %s is not within %s.\nAborting\n' 
           % (indir, cvsroot))
    return
    
  if dirlist[cvsdepth + 1] != workDirName:
    print ('input file directory %s is not within %s/???/%s.\nAborting\n' 
           % (indir, cvsroot, workDirName))
    return
    
  # make target directory
  dirlist[cvsdepth+1] = repCode
  outdir = os.path.join(*dirlist)
  if not os.path.isdir(outdir):
    print ('No target directory %s.\nAborting\n' % outdir)
    return
    
  # prepare file lists
  targets = []
  files = []
  for ii in range(len(infiles)):
    ff = infiles[ii]
    if os.path.isdir(ff) or (os.path.isfile(ff) and not os.path.islink(ff)):
    
      dd, base = os.path.split(sources[ii])
      if dd != indir:
        print ('files %s and %s from different directories.\nAborting\n' % 
                (infiles[0], ff))
        return
        
      target = os.path.join(outdir, base)
      if os.path.exists(target):
        print 'file %s already exists.\nAborting\n' % target
        return
      targets.append(target)
      files.append(base)
      
    else:
      print ('input file %s not normal file or directory.\nAborting\n' 
             % ff)
      return
  
  # move, and link files
  os.chdir(outdir)
  for ii in range(len(sources)):
    source = sources[ii]
    target = targets[ii]
    if os.path.isdir(source):
      os.mkdir(target)
    else:
      os.rename(source, target)
      os.symlink(target, source)
    os.system('cvs add %s' % files[ii])
    
  
def removeFiles (*infiles):
  """ Remove files from repositories.
  file input must be symlinks and from the same directory
  Assumes that you are under {$CCPNROOT}/aBranch/all.
  Removes the symlink, the files linked to, and cvs removes the latter
  """
  
  if not infiles:
    print 'No files passed to addFiles. \nAborting\n.'
    return
  
  # set up for cvsroot
  cvsroot = os.environ.get('CCPNROOT')
  cvsrootlist = splitall(cvsroot)
  cvsdepth = len(cvsrootlist)
  
  # validate directory
  targets = []
  files = []
  targetDirs = set()
  for ff in (os.path.abspath(ff) for ff in infiles):
    if not os.path.islink(ff):
      print ('input file %s not symbolic link.\nAborting\n' 
             % ff)
      return
    indir = os.path.dirname(os.path.abspath(ff))
    dirlist = splitall(indir)
    if dirlist[:cvsdepth] != cvsrootlist:
      print ('input file directory %s is not within %s.\nAborting\n'
             % (indir, cvsroot))
      return
 
    if dirlist[cvsdepth + 1] != workDirName:
      print ('input file directory %s is not within %s/???/%s.\nAborting\n'
             % (indir, cvsroot, WorkDirNamw))
      return
      
    target = os.path.join(indir, os.readlink(ff))
    if not os.path.exists(target):
      print 'file %s linked to by %s does not exist.\nAborting\n' % (target, ff)
      return
    targets.append(target)
    targetdir, base = os.path.split(target)
    targetDirs.add(targetDir)
    files.add(base)
  
  # remove files
  if len(targetDirs) == 1:
    outDir = targetDirs.pop()
    os.chdir(outdir)
    for ii in range(len(targets)):
      os.remove(sources[ii])
      target = targets[ii]
      os.remove(target)
      os.system('cvs remove %s' % ' '.join(files))
  
  else:
    for ii in range(len(targets)):
      os.remove(sources[ii])
      target = targets[ii]
      os.chdir(os.path.dirname(target))
      os.remove(target)
      os.system('cvs remove %s' % files[ii])
    

def splitall(path):
  """ split path into list of consecutive dirs
  """
  result = []
  
  path, base = os.path.split(path)
  while base:
    result.append(base)
    path, base = os.path.split(path)
    
  result.append(path)
  
  result.reverse()
  
  return result


def updateWorkingDir(destDir, origDir, mode):
  
  print 'Updating', destDir, origDir

  # normalise directories and check
  destDir = os.path.abspath(destDir)
  origDir = os.path.abspath(origDir)
  for dd in (destDir, origDir):
    if not os.path.isdir(dd):
      raise ("Error, %s is not a directory" % dd)
  
  # depth-first loop over directories:
  dirPaths = [origDir]
  while dirPaths:
    dirPath = dirPaths.pop()
    newDirPath = dirPath.replace(origDir, destDir)
      
    # Remove .pyc and .pyo... from target (to make sure tehy are up-to-date)
    for fileName in os.listdir(newDirPath):
      for ss in genEndings:
        if fileName.endswith(ss):
          if mode == 'copy':
            os.remove(os.path.join(newDirPath, fileName))
          else:
            pass
            #print "Removing %s..." % fileName
  
    # loop over files to copy
    for fileName in os.listdir(dirPath):
 
      if fileName in skipnames:
        # these are always ignored
        continue
 
      filePath = os.path.join(dirPath, fileName)
      newFilePath = os.path.join(newDirPath, fileName)
 
      if fileName in warnnames:
        # these are always ignored
        print ("Warning: file or directory named %s in source. Skipping ..." 
           % filePath)
 
      elif os.path.isdir(filePath):
        if 'CVS' in os.listdir(filePath):
          # If this directory has a CVS subdirectory, include it in the copy...
 
          if os.path.exists(newFilePath):
            if not os.path.isdir(newFilePath):
              raise("Error, %s is a directory but %s is not"
                    % (filePath, newFilePath))
          else:
            os.mkdir(newFilePath)
            
          dirPaths.append(filePath)
          continue
        
        else:
          print ("Warning:non-CVS directory %s in source. Skipping ..." 
             % filePath)
      
      elif os.path.islink(filePath) or not os.path.isfile(filePath):
        print (
         "Warning:%s in source neither directory nor normal file. Skipping ..." 
         % filePath
        )
      
      else:
        # source is normal file
        
        if [x for x in genEndings if fileName.endswith(x)]:
          if [x for x in warnGenEndings if fileName.endswith(x)]:
            print ("Warning: file %s has 'generated' ending. Skipping ..."
                   % filePath)
            
        elif os.path.islink(newFilePath):
          # check if link is to right file
          ff = os.path.abspath(os.path.join(dirPath, os.readlink(newFilePath)))
          if ff == filePath:
            # we are OK
            pass
          else:
            raise(" Error: link %s points to %s instead of %s"
                   % (newFilePath, ff, filePath))
 
        elif os.path.exists(newFilePath):
          raise("Error,b target of %s, %s already exists"
                % (filePath, newFilePath))
 
        else:
          # target dos not exist. make link
          if mode == 'copy':
            os.symlink(filePath, newFilePath)
          print "Symlink: %s" % newFilePath
by Rasmus Fogh last modified 2007-06-08 17:31

Powered by Plone, the Open Source Content Management System

This site conforms to the following standards: