cvsScripts.py
Scripts to handle cvs in the context of multiple branches and multiple repositories
Size 12.3 kB - File type text/python-sourceFile 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