ajack 2004/04/22 11:24:36
Modified: template/forrest/src/documentation/content/xdocs site.xml
python/gump/utils sync.py
python/gump/svg depdiag.py
python/gump/document/forrest documenter.py
python/gump/shared comparator.py
python/gump/output statsdb.py
Log:
1) Added stats by dependency depth, and total dependence depth (not good name)
2) Looked into sync, I feel there is a bug (I was missing files on site sync),
nothing jumps out.
3) Restored runtime dep lines (but dashed) to dependency diagram.
Revision Changes Path
1.29 +2 -1 gump/template/forrest/src/documentation/content/xdocs/site.xml
Index: site.xml
===================================================================
RCS file: /home/cvs/gump/template/forrest/src/documentation/content/xdocs/site.xml,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -r1.28 -r1.29
--- site.xml 10 Apr 2004 23:09:29 -0000 1.28
+++ site.xml 22 Apr 2004 18:24:33 -0000 1.29
@@ -55,7 +55,8 @@
<index label="by Elapsed" href="gump_stats/project_elapsed.html"/>
<index label="by Depends #" href="gump_stats/project_dependencies.html"/>
<index label="by Dependees #" href="gump_stats/project_dependees.html"/>
- <index label="by Duration" href="gump_stats/project_durstate.html"/>
+ <index label="by Depth" href="gump_stats/project_depdepth.html"/>
+ <index label="by Total Depth" href="gump_stats/project_totdepdepth.html"/>
</stats>
<stats label="XRef" tab="xref">
1.9 +110 -45 gump/python/gump/utils/sync.py
Index: sync.py
===================================================================
RCS file: /home/cvs/gump/python/gump/utils/sync.py,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- sync.py 12 Apr 2004 18:57:36 -0000 1.8
+++ sync.py 22 Apr 2004 18:24:33 -0000 1.9
@@ -23,13 +23,18 @@
import os.path
from stat import *
import shutil
+
from gump import log
from gump.utils.work import *
from gump.utils.file import *
from gump.utils.launcher import *
from gump.utils.note import *
-class Sync(Annotatable):
+SYNC_ACTION=1
+COPY_ACTION=2
+DIFF_ACTION=3
+
+class PathWalker(Annotatable):
"""
this class can be used to sync two directories
x = Sync(sourcedir, targetdir) # construct
@@ -37,54 +42,77 @@
if targetdir does not exist, it will be created
if sourcedir does not exist, the class will raise an IOError
the class can be also used to copy from one directory to another
- x = Sync(sourcedir, targetdir, 1)
+ x = Sync(sourcedir, targetdir, )
"""
- def __init__(self, sourcedir, targetdir, copyflag = 0):
+ def __init__(self, sourcedir, targetdir, action = SYNC_ACTION):
Annotatable.__init__(self)
self.sourcedir = sourcedir
self.targetdir = targetdir
- self.copyflag = copyflag
+ self.action = action
def execute(self):
- if self.copyflag:
- action = 'copy'
- else:
- action = 'sync'
- log.debug('Starting %s from [%s]' % (action,self.sourcedir))
+ log.debug('Starting %s from [%s]' % (self.action,self.sourcedir))
log.debug(' target dir [' + self.targetdir + ']')
if not os.path.exists(self.sourcedir):
log.error('Exiting sync, source directory does not exist [' +
self.sourcedir + ']')
raise IOError, 'source directory does not exist [' + self.sourcedir +
']'
- return
+
if not os.path.isdir(self.sourcedir):
log.error('Exiting sync, source is not a directory [' + self.sourcedir
+ ']')
raise IOError, 'source is not a directory [' + self.sourcedir + ']'
- return
+
if not os.path.exists(self.targetdir):
try:
os.makedirs(self.targetdir)
except Exception, details:
log.exception('failed on ' + str(details))
raise IOError, 'could not create directory [' + self.targetdir + ']'
+
self.copytree(self.sourcedir, self.targetdir, 1)
+
+
+ def isCopy(self): return (COPY_ACTION == self.action)
+ def isSync(self): return (SYNC_ACTION == self.action)
+ def isDiff(self): return (DIFF_ACTION == self.action)
def copytree(self, src, dst, symlinks=0):
+
+ #
+ # List all the files in the source location
+ #
names = os.listdir(src)
+
+ #
+ # Determine information about the destination (existence/type)
+ #
try:
- result = os.stat(dst)
+ destinationStat = os.stat(dst)
except Exception:
- result = None
- # handle case where result exists but is not a directory
- if result and not S_ISDIR(result[ST_MODE]):
+ destinationStat = None
+
+ #
+ # handle case where destinationStat exists but is not a directory
+ #
+ if destinationStat and not S_ISDIR(destinationStat[ST_MODE]):
os.remove(dst)
- result = None
- if not result:
+ destinationStat = None
+
+ #
+ # Generate the target location (even if it means making
+ # a path of directories.)
+ #
+ if not destinationStat:
os.makedirs(dst)
- if result:
+
+ if destinationStat:
names2 = os.listdir(dst)
- if not self.copyflag:
+ if not self.isCopy():
self.removenonmatching(src, dst, names, names2)
self.epurate(src, dst, names, names2)
+
+ #
+ #
+ #
for name in names:
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
@@ -93,12 +121,13 @@
linkto = os.readlink(srcname)
os.symlink(linkto, dstname)
elif os.path.isdir(srcname):
+ # Copy directories, but not CVS/SVN stuff
if not name in ['CVS','.svn']:
self.copytree(srcname, dstname, symlinks)
- #else:
- # log.debug('Skip SVN or CVS directory ' + str(srcname))
else:
+ # Selectively copy file
self.maybecopy(srcname, dstname)
+
except (IOError, os.error), why:
message = "Can't copy [%s] to [%s]: [%s]" % (`srcname`, `dstname`,
str(why))
log.exception(message)
@@ -119,13 +148,14 @@
fulldestfile = os.path.join(destdir, afile)
if not afile in acceptablefiles:
tobedeleted = os.path.join(destdir, afile)
- result = os.stat(tobedeleted)
- if S_ISDIR(result[ST_MODE]):
+ destinationStat = os.stat(tobedeleted)
+ if S_ISDIR(destinationStat[ST_MODE]):
log.debug('attempting to remove directory [%s]' %
(`tobedeleted`))
shutil.rmtree(tobedeleted)
else:
log.debug('attempting to remove file [%s]' % (`tobedeleted`))
os.remove(tobedeleted)
+
def removenonmatching(self, sourcedir, destdir, acceptablefiles, existingfiles):
"""
this routine will remove from destination
@@ -139,19 +169,24 @@
"""
removed = []
for afile in existingfiles:
- fullsourcefile = os.path.join(sourcedir, afile)
- fulldestfile = os.path.join(destdir, afile)
+
if afile in acceptablefiles:
+
+ fullsourcefile = os.path.join(sourcedir, afile)
+ fulldestfile = os.path.join(destdir, afile)
+
if os.path.isdir(fullsourcefile) and not
os.path.isdir(fulldestfile):
log.debug('removing file [%s] to be replaced by directory'
- %(`fulldestfile`))
+ %(`fulldestfile`))
os.remove(fulldestfile)
removed.append(afile)
elif os.path.isfile(fullsourcefile) and
os.path.isdir(fulldestfile):
log.debug('removing directory [%s] to be replaced by file'
- %(`fulldestfile`))
+ %(`fulldestfile`))
shutil.rmtree(fulldestfile)
removed.append(afile)
+
+ # Do the work
for afile in removed:
existingfiles.remove(afile)
@@ -162,30 +197,60 @@
or srcname and dstname have different dates
or srcname and dstname have different sizes
"""
- result = os.stat(srcname)
+ sourceStat = os.stat(srcname)
try:
- result2 = os.stat(dstname)
- except (Exception), details:
- result2 = None
- okcopy = 0
- if not result2:
- okcopy = 1
- elif S_ISDIR(result2[ST_MODE]):
+ destinationStat = os.stat(dstname)
+ except:
+ destinationStat = None
+
+ # Determine if copy is appropriate.
+ performCopy = 0
+ if not destinationStat:
+ performCopy = 1
+ elif S_ISDIR(destinationStat[ST_MODE]):
shutil.rmtree(dstname)
- okcopy = 1
- elif result[ST_SIZE] != result2[ST_SIZE]:
- okcopy = 1
- elif result[ST_MTIME] != result2[ST_MTIME]:
- okcopy = 1
- if okcopy:
+ performCopy = 1
+ elif sourceStat[ST_SIZE] != destinationStat[ST_SIZE]:
+ performCopy = 1
+ elif sourceStat[ST_MTIME] != destinationStat[ST_MTIME]:
+ performCopy = 1
+
+ if performCopy:
log.debug("Attempting copy from [%s] to [%s]" %(`srcname`, `dstname`))
- shutil.copy2(srcname, dstname)
+ shutil.copy2(srcname, dstname)
+ else:
+ log.debug("Do not copy from [%s:%s] to [%s:%s]" \
+ %(`srcname`, `sourceStat`, `dstname`,`destinationStat`))
+
+
-class Copy(Sync):
+
+class Copy(PathWalker):
"""
A Sync without the epurate
"""
def __init__(self, sourcedir, targetdir):
- Sync.__init__(self, sourcedir, targetdir, 1)
+ PathWalker.__init__(self, sourcedir, targetdir, COPY_ACTION)
-
+
+class Sync(PathWalker):
+ """
+ A Sync
+ """
+ def __init__(self, sourcedir, targetdir):
+ PathWalker.__init__(self, sourcedir, targetdir, SYNC_ACTION)
+
+
+#class Diff(Sync,FileHolder):
+# """
+# A difference analysis tool
+#
+# :TODO: Write it...
+#
+# """
+# def __init__(self, sourcedir, targetdir):
+# PathWalker.__init__(self, sourcedir, targetdir, DIFF_ACTION)
+# FileHolder.__init__(self)
+#
+# raise IOError, 'this does not work yet ...'
+
\ No newline at end of file
1.8 +9 -7 gump/python/gump/svg/depdiag.py
Index: depdiag.py
===================================================================
RCS file: /home/cvs/gump/python/gump/svg/depdiag.py,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- depdiag.py 20 Apr 2004 17:44:32 -0000 1.7
+++ depdiag.py 22 Apr 2004 18:24:33 -0000 1.8
@@ -223,9 +223,7 @@
# Draw lines to represent dependencies
for dependency in project.getDirectDependencies():
-
- if dependency.isRuntime(): continue
-
+
# For each dependent project
dependProject=dependency.getProject()
@@ -245,12 +243,16 @@
color='purple'
elif project.getFOGFactor() < 0.1:
color='red'
+
+ attributes = { 'stroke':color, \
+ 'stroke-width':width, \
+ 'comment': project.getName() + ' to ' +
dependProject.getName() }
+
+ if dependency.isRuntime():
+ attributes['stroke-dasharray']='5,2'
#print 'LINE %s,%s -> %s,%s' % (x,y,x1,y1)
- svg.addLine(x,y,x1,y1, \
- { 'stroke':color, \
- 'stroke-width':width, \
- 'comment': project.getName() + ' to ' +
dependProject.getName() } )
+ svg.addLine(x,y,x1,y1, attributes )
#
# The shapes and text
1.11 +55 -11 gump/python/gump/document/forrest/documenter.py
Index: documenter.py
===================================================================
RCS file: /home/cvs/gump/python/gump/document/forrest/documenter.py,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- documenter.py 22 Apr 2004 14:50:47 -0000 1.10
+++ documenter.py 22 Apr 2004 18:24:33 -0000 1.11
@@ -1552,12 +1552,20 @@
self.documentFileList(run,document,project,'Project-level Files')
self.documentWorkList(run,document,project,'Project-level Work')
- addnSection=document.createSection('Additional Details')
- addnPara=addnSection.createParagraph()
- addnPara.createLink(gumpSafeName(project.getName()) + '_details.html',
\
- 'For additional project details (including
dependencies) ...')
+
+ if project.isVerboseOrDebug():
+ addnSection=document.createSection('Additional Details')
+ addnPara=addnSection.createParagraph()
+ addnPara.createLink(gumpSafeName(project.getName()) + '_details.html',
\
+ 'For additional project details (including
dependencies) ...')
+
document.serialize()
+ if project.isVerboseOrDebug():
+ self.documentProjectDetails(run,project,workspace,gumpSet)
+
+ def documentProjectDetails(self,run,project,workspace,gumpSet):
+
document=XDocDocument('Project Details : ' + project.getName(), \
self.resolver.getFile(project, \
project.getName() + '_details', \
@@ -1603,8 +1611,7 @@
deps = 0
depens = 0
- depees = 0
-
+ depees = 0
#
# The 'cause' is something upstream. Possibly a project,
@@ -2401,8 +2408,7 @@
document.createParagraph("""
Statistics from Gump show the depth and health of inter-relationships.
- """)
-
+ """)
overviewSection=document.createSection('Overview')
overviewList=overviewSection.createList()
@@ -2484,6 +2490,18 @@
pstatsRow.createData().createLink(pBySeq, 'Projects By Duration in state')
pstatsRow.createData('Duration in current state.')
+ # Projects By Dependency Depth
+ pByDepD=self.documentProjectsByDependencyDepth(stats, run, workspace,
gumpSet)
+ pstatsRow=pstatsTable.createRow()
+ pstatsRow.createData().createLink(pByDepD, 'Projects By Dependency Depth')
+ pstatsRow.createData('Depth (in dependency tree) of the project.')
+
+ # Projects By Dependency Depth
+ pByTotDepD=self.documentProjectsByDependencyDepth(stats, run, workspace,
gumpSet, 1)
+ pstatsRow=pstatsTable.createRow()
+ pstatsRow.createData().createLink(pByTotDepD, 'Projects By Total Dependency
Depth')
+ pstatsRow.createData('Total Depth (sum of direct dependencies depths) of
the project.')
+
document.serialize()
def documentModulesByElapsed(self,stats,run,workspace,gumpSet):
@@ -2719,21 +2737,47 @@
return fileName + '.html'
+ def documentProjectsByDependencyDepth(self,stats,run,workspace,gumpSet,total=0):
+ if total:
+ title='Projects By Total Dependency Depth'
+ fileName='project_totdepdepth'
+ else:
+ title='Projects By Dependency Depth'
+ fileName='project_depdepth'
+ documentFile=self.resolver.getFile(stats,fileName)
+ document=XDocDocument(title, documentFile)
+ durTable=document.createTable(['Project','Dependency Depth','Total
Dependency Depth'])
+ if total:
+ list = stats.projectsByTotalDependencyDepth
+ else:
+ list = stats.projectsByDependencyDepth
+ for project in list:
+ if not gumpSet.inProjectSequence(project): continue
+ durRow=durTable.createRow()
+ self.insertLink( project, stats, durRow.createData())
+
+ durRow.createData(project.getDependencyDepth())
+ durRow.createData(project.getTotalDependencyDepth())
+
+ document.serialize()
+
+ return fileName + '.html'
+
#####################################################################
#
# XRef Pages
#
def documentXRef(self,run,workspace,gumpSet):
-
- xref=XRefGuru(workspace)
+
+ xref=XRefGuru(workspace)
document=XDocDocument('Cross Reference',self.resolver.getFile(xref))
document.createParagraph("""
Obscure views into projects/modules...
""")
-
+
##################################################################3
# Modules ...........
mxrefSection=document.createSection('Module Cross Reference')
1.2 +16 -1 gump/python/gump/shared/comparator.py
Index: comparator.py
===================================================================
RCS file: /home/cvs/gump/python/gump/shared/comparator.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- comparator.py 9 Apr 2004 22:38:25 -0000 1.1
+++ comparator.py 22 Apr 2004 18:24:36 -0000 1.2
@@ -115,4 +115,19 @@
c= int(round(seq2 - seq1,0))
if not c: c=cmp(project1,project2)
return c
+
+def compareProjectsByDependencyDepth(project1,project2):
+ dep1=project1.getDependencyDepth()
+ dep2=project2.getDependencyDepth()
+ c= int(round(dep2 - dep1,0))
+ if not c: c=cmp(project1,project2)
+ return c
+
+
+def compareProjectsByTotalDependencyDepth(project1,project2):
+ tot1=project1.getTotalDependencyDepth()
+ tot2=project2.getTotalDependencyDepth()
+ c= int(round(tot2 - tot1,0))
+ if not c: c=cmp(project1,project2)
+ return c
1.23 +2 -1 gump/python/gump/output/statsdb.py
Index: statsdb.py
===================================================================
RCS file: /home/cvs/gump/python/gump/output/statsdb.py,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -r1.22 -r1.23
--- statsdb.py 16 Apr 2004 17:28:39 -0000 1.22
+++ statsdb.py 22 Apr 2004 18:24:36 -0000 1.23
@@ -357,7 +357,6 @@
self.modulesByLastUpdated=createOrderedList(workspace.getModules(),compareModulesByLastUpdated)
-
# All Projects
self.projectsByElapsed=createOrderedList(workspace.getProjects(),compareProjectsByElapsed)
self.projectsByTotalDependencies=createOrderedList(workspace.getProjects(),compareProjectsByDependencyCount)
@@ -365,4 +364,6 @@
self.projectsByFOGFactor=createOrderedList(workspace.getProjects(),compareProjectsByFOGFactor)
self.projectsByLastUpdated=createOrderedList(workspace.getProjects(),compareProjectsByLastUpdated)
self.projectsBySequenceInState=createOrderedList(workspace.getProjects(),compareProjectsBySequenceInState)
+
self.projectsByDependencyDepth=createOrderedList(workspace.getProjects(),compareProjectsByDependencyDepth)
+
self.projectsByTotalDependencyDepth=createOrderedList(workspace.getProjects(),compareProjectsByTotalDependencyDepth)
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]