#!/usr/bin/env python ''' install.py Webware for Python FUTURE * Look for an install.py in each component directory and run it (there's not a strong need right now). * Upon successful install, create "installed" file with info such as date, time, py ver, etc. Maybe just put the output of this in there. ''' import os, string, sys from time import time, localtime, asctime from string import count, join, rfind, split, strip, replace from glob import glob from MiscUtils.PropertiesObject import PropertiesObject try: from cStringIO import StringIO except ImportError: from StringIO import StringIO class Installer: ''' The _comps attribute is a list of components, each of which is an instance of MiscUtils.PropertiesObject. ''' ## Init ## def __init__(self): self._props = PropertiesObject('Properties.py') self._htHeader = self.htFragment('Header') self._htFooter = self.htFragment('Footer') self._comps = [] ## Running the installation ## def run(self, verbose=0): self._verbose = verbose self.printHello() self.detectComponents() self.installDocs() self.backupConfigs() self.fixPermissions() self.finished() self.printGoodbye() return self def printHello(self): print '%(name)s %(versionString)s' % self._props print 'Installer' print self.printKeyValue('Date', asctime(localtime(time()))) self.printKeyValue('Python ver', sys.version) self.printKeyValue('Op Sys', os.name) self.printKeyValue('Platform', sys.platform) self.printKeyValue('Cur dir', os.getcwd()) print def detectComponents(self): print 'Scanning for components...' filenames = os.listdir('.') maxLen = max(filter(None, map(lambda name: os.path.isdir(name) and len(name), filenames))) count = 0 needPrint = 0 for filename in os.listdir('.'): if os.path.isdir(filename): propName = os.path.join(filename, 'Properties.py') displayName = string.ljust(filename, maxLen) if os.path.exists(propName): comp = PropertiesObject(propName) comp['filename'] = filename self._comps.append(comp) print ' yes', displayName, else: print ' no', displayName, if count%2==1: print needPrint = 0 else: needPrint = 1 count = count + 1 if needPrint: print print self._comps.sort(lambda a, b: cmp(a['name'], b['name'])) def installDocs(self): self.propagateStyleSheet() self.processRawFiles() self.createBrowsableSource() self.createComponentIndex() self.createIndex() self.createComponentIndexes() def propagateStyleSheet(self): ''' Copy Docs/StyleSheet.css and GenIndex.css into other Docs dirs. ''' print 'Propagating stylesheets...' for name in ['StyleSheet.css', 'GenIndex.css']: stylesheet = open('Docs/%s' % name, 'rb').read() for comp in self._comps: #print ' %s...' % comp['filename'] target = os.path.join(comp['filename'], 'Docs', name) open(target, 'wb').write(stylesheet) print def processRawFiles(self): print 'Processing raw doc files...' self.requirePath('DocSupport') from RawToHTML import RawToHTML processor = RawToHTML() processor.main(['install.RawToHTML', 'Docs/*.raw']) print def createBrowsableSource(self): ''' Create HTML documents for class hierarchies, summaries, source files, etc. ''' print 'Creating browsable source and summaries...' self.requirePath('DocSupport') for comp in self._comps: filename = comp['filename'] print ' %s...' % filename sourceDir = '%s/Docs/Source' % filename self.makeDir(sourceDir) filesDir = sourceDir + '/Files' self.makeDir(filesDir) summariesDir = sourceDir + '/Summaries' self.makeDir(summariesDir) docsDir = sourceDir + '/Docs' # @@ 2000-08-17 ce: Eventually for pydoc/gendoc #self.makeDir(docsDir) for pyFilename in glob('%s/*.py' % filename): self.createHighlightedSource(pyFilename, filesDir) self.createSummary(pyFilename, summariesDir) #self.createDocs(pyFilename, docsDir) # @@ 2000-08-17 ce: Eventually for pydoc/gendoc self.createBrowsableClassHier(filename, sourceDir) #self.createBrowsableFileList(filename, sourceDir) print def createHighlightedSource(self, filename, dir): import py2html targetName = '%s/%s.html' % (dir, os.path.basename(filename)) if self._verbose: print ' Creating %s...' % targetName realout = sys.stdout sys.stdout = StringIO() # py2html.main([None, '-stdout', '-format:rawhtml', '-files', filename]) py2html.main([None, '-stdout', '-files', filename]) result = sys.stdout.getvalue() result = replace(result, '\t', ' ') # 4 spaces per tab open(targetName, 'w').write(result) sys.stdout = realout def createSummary(self, filename, dir): from PySummary import PySummary targetName = '%s/%s.html' % (dir, os.path.basename(filename)) if self._verbose: print ' Creating %s...' % targetName sum = PySummary() sum.readConfig('DocSupport/PySummary.config') sum.readFileNamed(filename) html = sum.html() open(targetName, 'w').write(html) def createDocs(self, filename, dir): from PySummary import PySummary targetName = '%s/%s.html' % (dir, os.path.basename(filename)) if self._verbose: print ' Creating %s...' % targetName # @@ 2000-08-17 ce: use something like pydoc or gendoc here raise NotImplementedError def createBrowsableClassHier(self, filesDir, docsDir): ''' Create HTML class hierarchy listings of the source files. ''' from classhier import ClassHier classHierName = os.path.join(os.getcwd(), docsDir, 'ClassHier.html') listName = os.path.join(os.getcwd(), docsDir, 'ClassList.html') saveDir = os.getcwd() os.chdir(filesDir) try: ch = ClassHier() # @@ 2000-08-17 ce: whoa! look at that hard-coding! ch.addFilesToIgnore(['zCookieEngine.py', 'WebKitSocketServer.py', '_on_hold_HierarchicalPage.py', 'fcgi.py']) ch.readFiles('*.py') ch.printHierForWeb(classHierName) ch.printListForWeb(listName) finally: os.chdir(saveDir) def createBrowsableFileList(self, filesDir, docsDir): ''' Create HTML list of the source files. ''' # @@ 2000-08-18 ce: not yet fullnames = glob('%s/*.py' % filesDir) filenames = map(lambda filename: os.path.basename(filename), fullnames) filenames.sort() ht = [] ht.append('\n') for filename in filenames: ht.append('' % filename) ht.append('
summary source %s
') ht = string.join(ht, '') open(docsDir+'/FileList.html', 'w').write(ht) def backupConfigs(self): ''' Copies *.config to *.config.default, if the .default files don't already exist. This allows the user to always go back to the default config file if needed (for troubleshooting for example). ''' print 'Backing up original config files...' print ' ', self._backupConfigs(os.curdir) print def _backupConfigs(self, dir): wr = sys.stdout.write for filename in os.listdir(dir): fullPath = os.path.join(dir, filename) if os.path.isdir(fullPath): self._backupConfigs(fullPath) elif filename[0]!='.' and \ os.path.splitext(filename)[1]=='.config': backupName = fullPath + '.default' if not os.path.exists(backupName): contents = open(fullPath, 'rb').read() open(backupName, 'wb').write(contents) del contents wr('.') else: wr('-') sys.stdout.flush() def fixPermissions(self): if os.name=='posix': print 'Setting permissions on CGI scripts...' for comp in self._comps: #print ' %s...' % comp['name'] for filename in glob('%s/*.cgi' % comp['filename']): #if self._verbose: print ' %s...' % os.path.basename(filename) cmd = 'chmod a+rx %s' % filename print ' %s' % cmd os.system(cmd) print def createComponentIndex(self): print 'Creating ComponentIndex.html...' ht = [] wr = ht.append wr("Don't know where to start? Try WebKit.

") wr('') wr('') row = 0 for comp in self._comps: comp['nameAsLink'] = '%(name)s' % comp comp['indexRow'] = row+1 wr('''\ ''' % comp) row = (row+1)%2 # e.g., 1, 2, 1, 2, ... wr('
Component Status Ver Py ver Summary
%(nameAsLink)s %(status)s %(versionString)s %(requiredPyVersionString)s %(synopsis)s
') ht = string.join(ht, '\n') self.writeDocFile('Webware Component Index', 'Docs/ComponentIndex.html', ht, extraHead='') def createIndex(self): print 'Creating index.html...' ht = self.htFragment('index') ht = ht % self._props self.writeDocFile('Webware Documentation', 'Docs/index.html', ht, extraHead='') # @@ 2000-12-23 Uh, we sneak in Copyright.html here until # we have a more general mechanism for adding the header # and footer to various documents ht = self.htFragment('Copyright') self.writeDocFile('Webware Copyright et al', 'Docs/Copyright.html', ht) def createComponentIndexes(self): print "Creating components' index.html..." indexFrag = self.htFragment('indexOfComponent') link = '%s
\n' for comp in self._comps: comp['webwareVersion'] = self._props['version'] comp['webwareVersionString'] = self._props['versionString'] # Create 'htDocs' as a readable HTML version comp['docs'] ht = [] for doc in comp['docs']: ht.append(link % (doc['file'], doc['name'])) ht = string.join(ht, '') comp['htDocs'] = ht # Set up release notes ht = [] releaseNotes = glob(os.path.join(comp['filename'], 'Docs', 'RelNotes-*.html')) if releaseNotes: # releaseNotes = [{'filename': os.path.basename(filename)} for filename in releaseNotes] results = [] for filename in releaseNotes: results.append({'filename': os.path.basename(filename)}) releaseNotes = results for item in releaseNotes: filename = item['filename'] item['name'] = filename[string.rfind(filename,'-')+1:string.rfind(filename,'.')] releaseNotes.sort(self.sortReleaseNotes) for item in releaseNotes: ht.append(link % (item['filename'], item['name'])) else: ht.append('None\n') ht = string.join(ht, '') comp['htReleaseNotes'] = ht # Write file title = comp['name'] + ' Documentation' filename = os.path.join(comp['filename'], 'Docs', 'index.html') contents = indexFrag % comp cssLink = '' self.writeDocFile(title, filename, contents, extraHead=cssLink) def finished(self): ''' This method is invoked just before printGoodbye(). It is a hook for subclasses. This implementation does nothing. ''' pass def printGoodbye(self): print ''' Installation looks successful. Welcome to Webware! You can find more information at: * Docs/index.html (e.g., local docs) * http://webware.sourceforge.net Installation is finished.''' ## Self utility ## def printKeyValue(self, key, value): # Handle values with line breaks by indenting extra lines value = str(value) value = string.replace(value, '\n', '\n'+' '*14) print '%12s: %s' % (key, value) def makeDir(self, dirName): if not os.path.exists(dirName): if self._verbose: print ' Making %s...' % dirName os.mkdir(dirName) def requirePath(self, path): if path not in sys.path: sys.path.insert(1, path) def sortReleaseNotes(self, a, b): ''' Used by createComponentIndexes(). You pass this to list.sort(). ''' # We append '.0' below so that values like 'x.y' and 'x.y.z' # compare the way we want them too (x.y.z is newer than x.y) a = a['name'] if string.count(a, '.')==1: a = a + '.0' b = b['name'] if string.count(b, '.')==1: b = b + '.0' return -cmp(a, b) def htFragment(self, name): ''' Returns an HTML fragment with the given name. ''' return open(os.path.join('Docs', name+'.htmlf')).read() def writeDocFile(self, title, filename, contents, extraHead=''): values = locals() file = open(filename, 'w') file.write(self._htHeader % values) file.write(contents) file.write(self._htFooter % values) file.close() if __name__=='__main__': Installer().run(verbose=0)