def zipResult(self, eggFullName, eggTempFolder): '''Zips the result and removes the egg temp folder.''' zipFile = zipfile.ZipFile(eggFullName, 'w', zipfile.ZIP_DEFLATED) # Put the Python module inside the egg. prefix = os.path.dirname(eggTempFolder) for dir, dirnames, filenames in os.walk(eggTempFolder): for f in filenames: fileName = os.path.join(dir, f) zipFile.write(fileName, fileName[len(prefix):]) # Put the Appy module inside it if required. if self.includeAppy: eggPrefix = '%s/%s' % (eggTempFolder[len(prefix):], self.moduleName.replace('.', '/')) # Where is Appy? appyPath = os.path.dirname(appy.__file__) appyPrefix = os.path.dirname(appyPath) # Clean the Appy folder Cleaner().run(verbose=False) # Insert appy files into the zip for dir, dirnames, filenames in os.walk(appyPath): if not self.dirInZip(dir): continue for f in filenames: fileName = os.path.join(dir, f) zipName = eggPrefix + fileName[len(appyPrefix):] zipFile.write(fileName, zipName) zipFile.close() # Remove the temp egg folder. FolderDeleter.delete(eggTempFolder)
def eggify(self): '''Let's wrap a nice Python module into an ugly egg.''' j = os.path.join # First, clean the Python module cleanFolder(self.pythonModule, verbose=False) # Create the egg folder eggFullName = j(self.eggFolder, self.eggName) if os.path.exists(eggFullName): os.remove(eggFullName) print 'Existing "%s" was removed.' % eggFullName # Create a temp folder where to store the egg eggTempFolder = os.path.splitext(eggFullName)[0] if os.path.exists(eggTempFolder): FolderDeleter.delete(eggTempFolder) print 'Removed "%s" that was in my way.' % eggTempFolder os.mkdir(eggTempFolder) # Create the "Products" sub-folder if we must wrap the package in this # namespace eggModulePath = j(j(eggTempFolder, self.moduleName.replace('.', '/'))) # Copy the Python module into the egg. os.makedirs(eggModulePath) copyFolder(self.pythonModule, eggModulePath) # Create setup files in the root egg folder self.createSetupFile(eggTempFolder) self.createInitFile(eggTempFolder) self.zipResult(eggFullName, eggTempFolder)
def zipResult(self, eggFullName, eggTempFolder): '''Zips the result and removes the egg temp folder.''' zipFile = zipfile.ZipFile(eggFullName, 'w', zipfile.ZIP_DEFLATED) # Put the Python module inside the egg. prefix = os.path.dirname(eggTempFolder) for dir, dirnames, filenames in os.walk(eggTempFolder): for f in filenames: fileName = os.path.join(dir, f) zipFile.write(fileName, fileName[len(prefix):]) # Put the Appy module inside it if required. if self.includeAppy: eggPrefix = '%s/%s' % (eggTempFolder[len(prefix):], self.moduleName.replace('.', '/')) # Where is Appy? appyPath = os.path.dirname(appy.__file__) appyPrefix = os.path.dirname(appyPath) # Clean the Appy folder Cleaner().run(verbose=False) # Insert appy files into the zip for dir, dirnames, filenames in os.walk(appyPath): if not self.dirInZip(dir): continue for f in filenames: fileName = os.path.join(dir, f) zipName = eggPrefix + fileName[len(appyPrefix):] zipFile.write(fileName, zipName) zipFile.close() # Remove the temp egg folder. FolderDeleter.delete(eggTempFolder)
def createDistRelease(self): """Create the distutils package.""" curdir = os.getcwd() distFolder = "%s/dist" % self.genFolder # Create setup.py os.mkdir(distFolder) f = file("%s/setup.py" % distFolder, "w") # List all packages to include packages = [] os.chdir(os.path.dirname(appyPath)) for dir, dirnames, filenames in os.walk("appy"): if self.isDistExcluded(dir): continue packageName = dir.replace("/", ".") packages.append('"%s"' % packageName) f.write(distInfo % (self.versionShort, ",".join(packages))) f.close() # Create MANIFEST.in f = file("%s/MANIFEST.in" % distFolder, "w") f.write(manifestInfo) f.close() # Move appy sources within the dist folder os.rename("%s/appy" % self.genFolder, "%s/appy" % distFolder) # Create the source distribution os.chdir(distFolder) self.executeCommand("python setup.py sdist") # DistUtils has created the .tar.gz file. Move it to folder "versions" name = "appy-%s.tar.gz" % self.versionShort os.rename("%s/dist/%s" % (distFolder, name), "%s/versions/%s" % (appyPath, name)) # Clean temp files os.chdir(curdir) # Keep the Appy source for building the Debian package afterwards os.rename(os.path.join(self.genFolder, "dist", "appy"), os.path.join(self.genFolder, "appy")) FolderDeleter.delete(os.path.join(self.genFolder, "dist")) return name
def eggify(self): '''Let's wrap a nice Python module into an ugly egg.''' j = os.path.join # First, clean the Python module cleanFolder(self.pythonModule, verbose=False) # Create the egg folder eggFullName = j(self.eggFolder, self.eggName) if os.path.exists(eggFullName): os.remove(eggFullName) print('Existing "%s" was removed.' % eggFullName) # Create a temp folder where to store the egg eggTempFolder = os.path.splitext(eggFullName)[0] if os.path.exists(eggTempFolder): FolderDeleter.delete(eggTempFolder) print('Removed "%s" that was in my way.' % eggTempFolder) os.mkdir(eggTempFolder) # Create the "Products" sub-folder if we must wrap the package in this # namespace eggModulePath = j(j(eggTempFolder, self.moduleName.replace('.', '/'))) # Copy the Python module into the egg. os.makedirs(eggModulePath) copyFolder(self.pythonModule, eggModulePath) # Create setup files in the root egg folder self.createSetupFile(eggTempFolder) self.createInitFile(eggTempFolder) self.zipResult(eggFullName, eggTempFolder)
def __init__(self): # Delete the "egg" folder on not-yet-copied local site. eggFolder = "%s/temp/egg" % appyPath if os.path.isdir(eggFolder): FolderDeleter.delete(eggFolder) # Ask user id and password for FTP transfer userId, userPassword = askLogin() self.site = ftplib.FTP(self.name) self.site.login(userId, userPassword) self.rootFolder = None # Root folder of appy site ~FtpFolder~ self.currentFolder = None # Currently visited folder ~FtpFolder~
def __init__(self, app, pythonVersions=('2.6',)): self.appName = os.path.basename(app) self.pythonVersions = pythonVersions appFolder = os.path.dirname(app) # Prepare the output folder (remove any existing one) cortexFolder = os.path.join(appFolder, 'cortex.admin') if os.path.exists(cortexFolder): FolderDeleter.delete(cortexFolder) allFolders = os.path.join(cortexFolder, 'applications', self.appName) os.makedirs(allFolders) self.out = allFolders
def __init__(self, app, pythonVersions=('2.6', )): self.appName = os.path.basename(app) self.pythonVersions = pythonVersions appFolder = os.path.dirname(app) # Prepare the output folder (remove any existing one) cortexFolder = os.path.join(appFolder, 'cortex.admin') if os.path.exists(cortexFolder): FolderDeleter.delete(cortexFolder) allFolders = os.path.join(cortexFolder, 'applications', self.appName) os.makedirs(allFolders) self.out = allFolders
def run(self, verbose=True): cleanFolder(appyPath, verbose=verbose) # Remove all files in temp folders for tempFolder in ('%s/temp' % appyPath, '%s/pod/test/temp' % appyPath): if os.path.exists(tempFolder): FolderDeleter.delete(tempFolder) # Remove test reports if any for testReport in ('%s/pod/test/Tester.report.txt' % appyPath, ): if os.path.exists(testReport): os.remove(testReport)
def run(self, verbose=True): cleanFolder(appyPath, verbose=verbose) # Remove all files in temp folders for tempFolder in ('%s/temp' % appyPath, '%s/pod/test/temp' % appyPath): if os.path.exists(tempFolder): FolderDeleter.delete(tempFolder) # Remove test reports if any for testReport in ('%s/pod/test/Tester.report.txt' % appyPath,): if os.path.exists(testReport): os.remove(testReport)
def finalize(self): msg = '%d/%d successful test(s)' % \ (self.nbOfSuccesses, (self.nbOfTests-self.nbOfIgnoredTests)) if self.nbOfIgnoredTests >0: msg += ', but %d ignored test(s) not counted' % \ self.nbOfIgnoredTests msg += '.' self.report.say(msg, force=True) self.report.close() if not self.keepTemp: if os.path.exists(self.tempFolder): FolderDeleter.delete(self.tempFolder)
def finalize(self): msg = '%d/%d successful test(s)' % \ (self.nbOfSuccesses, (self.nbOfTests-self.nbOfIgnoredTests)) if self.nbOfIgnoredTests >0: msg += ', but %d ignored test(s) not counted' % \ self.nbOfIgnoredTests msg += '.' self.report.say(msg, force=True) self.report.close() if not self.keepTemp: if os.path.exists(self.tempFolder): FolderDeleter.delete(self.tempFolder)
def setStylesMapping(self, stylesMapping): '''Establishes a correspondence between, on one hand, CSS styles or XHTML tags that will be found inside XHTML content given to POD, and, on the other hand, ODT styles found into the template.''' try: stylesMapping = self.stylesManager.checkStylesMapping(stylesMapping) self.stylesManager.setStylesMapping(stylesMapping) except PodError, po: self.contentParser.env.currentBuffer.content.close() self.stylesParser.env.currentBuffer.content.close() if os.path.exists(self.tempFolder): FolderDeleter.delete(self.tempFolder) raise po
def setStylesMapping(self, stylesMapping): '''Establishes a correspondance between, on one hand, CSS styles or XHTML tags that will be found inside XHTML content given to POD, and, on the other hand, ODT styles found into the template.''' try: stylesMapping = self.stylesManager.checkStylesMapping( stylesMapping) self.stylesManager.stylesMapping = stylesMapping except PodError, po: self.contentParser.env.currentBuffer.content.close() self.stylesParser.env.currentBuffer.content.close() if os.path.exists(self.tempFolder): FolderDeleter.delete(self.tempFolder) raise po
def run(self): '''Renders the result.''' try: # Remember which parser is running self.currentParser = self.contentParser # Create the resulting content.xml self.currentParser.parse(self.contentXml) self.currentParser = self.stylesParser # Create the resulting styles.xml self.currentParser.parse(self.stylesXml) # Patch META-INF/manifest.xml self.patchManifest() # Re-zip the result self.finalize() finally: FolderDeleter.delete(self.tempFolder)
def run(self): Cleaner().run(verbose=False) # Perform a small analysis on the Appy code LinesCounter(appy).run() print 'Generating site in %s...' % self.genFolder minimalist = askQuestion('Minimalist (shipped without tests)?', default='no') self.prepareGenFolder(minimalist) self.createDocToc() self.applyTemplate() self.createZipRelease() #self.createCodeAndEggReleases() if askQuestion('Do you want to publish the site on ' \ 'appyframework.org?', default='no'): AppySite().publish() if askQuestion('Delete locally generated site ?', default='no'): FolderDeleter.delete(self.genFolder)
def run(self): self.report.say('-' * 79) self.report.say('- Test %s.' % self.data['Name']) self.report.say('- %s\n' % self.description) # Prepare test data self.tempFolder = os.path.join(self.testFolder, 'temp') if os.path.exists(self.tempFolder): FolderDeleter.delete(self.tempFolder) os.mkdir(self.tempFolder) try: self.do() self.report.say('Checking result...') testFailed = self.checkResult() except: testFailed = self.onError() self.finalize() return testFailed
def run(self): self.report.say('-' * 79) self.report.say('- Test %s.' % self.data['Name']) self.report.say('- %s\n' % self.description) # Prepare test data self.tempFolder = os.path.join(self.testFolder, 'temp', self.data['Name']) if os.path.exists(self.tempFolder): time.sleep(0.3) # Sometimes I can't remove it, so I wait FolderDeleter.delete(self.tempFolder) os.makedirs(self.tempFolder) try: self.do() self.report.say('Checking result...') testFailed = self.checkResult() except: testFailed = self.onError() self.finalize() return testFailed
def run(self): Cleaner().run(verbose=False) # Perform a small analysis on the Appy code LinesCounter(appy).run() print "Generating site in %s..." % self.genFolder minimalist = self.askQuestion("Minimalist (shipped without tests)?", default="no") self.prepareGenFolder(minimalist) self.createDocToc() self.applyTemplate() self.createZipRelease() tarball = self.createDistRelease() self.createDebianRelease() if self.askQuestion("Upload %s on PyPI?" % tarball, default="no"): self.uploadOnPypi(tarball) if self.askQuestion("Publish on appyframework.org?", default="no"): AppySite().publish() if self.askQuestion("Delete locally generated site ?", default="yes"): FolderDeleter.delete(self.genFolder)
def setStylesMapping(self, stylesMapping): '''Establishes a correspondance between, on one hand, CSS styles or XHTML tags that will be found inside XHTML content given to POD, and, on the other hand, ODT styles found into the template.''' try: stylesMapping = self.stylesManager.checkStylesMapping(stylesMapping) # The predefined styles below are currently ignored, because the # xhtml2odt parser does not take into account span tags. if 'span[font-weight=bold]' not in stylesMapping: stylesMapping['span[font-weight=bold]'] = 'podBold' if 'span[font-style=italic]' not in stylesMapping: stylesMapping['span[font-style=italic]'] = 'podItalic' self.stylesManager.stylesMapping = stylesMapping except PodError, po: self.contentParser.env.currentBuffer.content.close() self.stylesParser.env.currentBuffer.content.close() if os.path.exists(self.tempFolder): FolderDeleter.delete(self.tempFolder) raise po
def walkFile(self, fileName): '''Unzip p_fileName in a temp folder, call self.script, and then re-zip the result.''' print 'Walking %s...' % fileName # Create a temp folder name = 'f%f' % time.time() tempFolder = os.path.join(self.tempFolder, name) os.mkdir(tempFolder) # Unzip the file in it unzip(fileName, tempFolder) # Call self.script py = sys.executable or 'python' cmd = [py, self.script, tempFolder] print ' Running %s...' % cmd, out, err = executeCommand(cmd) # Re-zip the result zip(fileName, tempFolder, odf=True) FolderDeleter.delete(tempFolder) print 'done.'
def grepFile(self, fileName): '''Unzips the .xml files from file named p_fileName and performs a grep on it.''' # Unzip the file in the temp folder name = 'f%f' % time.time() tempFolder = os.path.join(self.tempFolder, name) os.mkdir(tempFolder) zip = zipfile.ZipFile(fileName) for zippedFile in zip.namelist(): if zippedFile not in self.toGrep: continue destFile = os.path.join(tempFolder, zippedFile) f = open(destFile, 'wb') fileContent = zip.read(zippedFile) f.write(fileContent) f.close() # Run "grep" in this folder match = self.callGrep(tempFolder) if match: print('Found in %s' % fileName) FolderDeleter.delete(tempFolder)
def grepFile(self, fileName): '''Unzips the .xml files from file named p_fileName and performs a grep on it.''' # Unzip the file in the temp folder name = 'f%f' % time.time() tempFolder = os.path.join(self.tempFolder, name) os.mkdir(tempFolder) zip = zipfile.ZipFile(fileName) for zippedFile in zip.namelist(): if zippedFile not in self.toGrep: continue destFile = os.path.join(tempFolder, zippedFile) f = open(destFile, 'wb') fileContent = zip.read(zippedFile) f.write(fileContent) f.close() # Run "grep" in this folder match = self.callGrep(tempFolder) if match: print('Found in %s' % fileName) FolderDeleter.delete(tempFolder)
def __init__(self, testPlan, flavours, testFactory): # Check test plan if (not os.path.exists(testPlan)) or (not os.path.isfile(testPlan)) \ or (not testPlan.endswith('.rtf')): raise TesterError(WRONG_TEST_PLAN) self.testPlan = testPlan self.testFolder = os.path.abspath(os.path.dirname(testPlan)) # Check flavours if (not isinstance(flavours, list)) and \ (not isinstance(flavours, tuple)): raise TesterError(FLAVOURS_NOT_LIST) for flavour in flavours: if not isinstance(flavour, basestring): raise TesterError(FLAVOUR_NOT_STRING) self.flavours = flavours self.flavour = None # Check test factory if not issubclass(testFactory, TestFactory): raise TesterError(WRONG_TEST_FACTORY) self.testFactory = testFactory self.getOptions() self.report = TestReport('%s/Tester.report.txt' % self.testFolder, self.verbose) self.report.say('Parsing RTF file... ') t1 = time.time() self.tables = RtfTablesParser(testPlan).parse() t2 = time.time() - t1 self.report.say('Done in %d seconds' % t2) self.config = None ext = '' if self.flavour: ext = '.%s' % self.flavour configTableName = 'Configuration%s' % ext if self.tables.has_key(configTableName): self.config = self.tables[configTableName].asDict() self.tempFolder = os.path.join(self.testFolder, 'temp') if os.path.exists(self.tempFolder): FolderDeleter.delete(self.tempFolder) self.nbOfTests = 0 self.nbOfSuccesses = 0 self.nbOfIgnoredTests = 0
def __init__(self, testPlan, flavours, testFactory): # Check test plan if (not os.path.exists(testPlan)) or (not os.path.isfile(testPlan)) \ or (not testPlan.endswith('.rtf')): raise TesterError(WRONG_TEST_PLAN) self.testPlan = testPlan self.testFolder = os.path.abspath(os.path.dirname(testPlan)) # Check flavours if (not isinstance(flavours, list)) and \ (not isinstance(flavours, tuple)): raise TesterError(FLAVOURS_NOT_LIST) for flavour in flavours: if not isinstance(flavour, str): raise TesterError(FLAVOUR_NOT_STRING) self.flavours = flavours self.flavour = None # Check test factory if not issubclass(testFactory, TestFactory): raise TesterError(WRONG_TEST_FACTORY) self.testFactory = testFactory self.getOptions() self.report = TestReport('%s/Tester.report.txt' % self.testFolder, self.verbose) self.report.say('Parsing RTF file... ') t1 = time.time() self.tables = RtfTablesParser(testPlan).parse() t2 = time.time() - t1 self.report.say('Done in %d seconds' % t2) self.config = None ext = '' if self.flavour: ext = '.%s' % self.flavour configTableName = 'Configuration%s' % ext if configTableName in self.tables: self.config = self.tables[configTableName].asDict() self.tempFolder = os.path.join(self.testFolder, 'temp') if os.path.exists(self.tempFolder): FolderDeleter.delete(self.tempFolder) self.nbOfTests = 0 self.nbOfSuccesses = 0 self.nbOfIgnoredTests = 0
def createZipRelease(self): '''Creates a zip file with the appy sources.''' newZipRelease = '%s/versions/appy%s.zip' % (appyPath, self.versionShort) if os.path.exists(newZipRelease): if not askQuestion('"%s" already exists. Replace it?' % \ newZipRelease, default='yes'): print 'Publication cancelled.' sys.exit(1) print 'Removing obsolete %s...' % newZipRelease os.remove(newZipRelease) zipFile = zipfile.ZipFile(newZipRelease, 'w', zipfile.ZIP_DEFLATED) curdir = os.getcwd() os.chdir(self.genFolder) for dir, dirnames, filenames in os.walk('appy'): for f in filenames: fileName = os.path.join(dir, f) zipFile.write(fileName) # [2:] is there to avoid havin './' in the path in the zip file. zipFile.close() os.chdir(curdir) # Remove the "appy" folder within the gen folder. FolderDeleter.delete(os.path.join(self.genFolder, 'appy'))
def prepareGenFolder(self, minimalist=False): '''Creates the basic structure of the temp folder where the appy website will be generated.''' # Reinitialise temp folder where the generated website will be dumped if os.path.exists(self.genFolder): FolderDeleter.delete(self.genFolder) shutil.copytree('%s/doc' % appyPath, self.genFolder) # Create a temp clean copy of appy sources (without .svn folders, etc) genSrcFolder = '%s/appy' % self.genFolder os.mkdir(genSrcFolder) for aFile in ('__init__.py', 'install.txt'): shutil.copy('%s/%s' % (appyPath, aFile), genSrcFolder) for aFolder in ('gen', 'pod', 'shared', 'bin'): shutil.copytree('%s/%s' % (appyPath, aFolder), '%s/%s' % (genSrcFolder, aFolder)) # Remove some scripts from bin for script in self.privateScripts: os.remove('%s/bin/%s' % (genSrcFolder, script)) if minimalist: FolderDeleter.delete('%s/pod/test' % genSrcFolder) # Write the appy version into the code itself (in appy/version.py)''' print 'Publishing version %s...' % self.versionShort # Dump version info in appy/version.py f = file('%s/version.py' % genSrcFolder, 'w') f.write('short = "%s"\n' % self.versionShort) f.write('verbose = "%s"' % self.versionLong) f.close() # Remove unwanted files os.remove('%s/version.txt' % self.genFolder) os.remove('%s/license.txt' % self.genFolder) os.remove('%s/template.html' % self.genFolder) os.remove('%s/artwork.odg' % self.genFolder) # Remove subversion folders for root, dirs, files in os.walk(self.genFolder): for dirName in dirs: if dirName == '.svn': FolderDeleter.delete(os.path.join(root, dirName))
def run(self): '''Generates the Debian package.''' curdir = os.getcwd() j = os.path.join tempFolder = getOsTempFolder() # Create, in the temp folder, the required sub-structure for the Debian # package. debFolder = j(tempFolder, 'debian') if os.path.exists(debFolder): FolderDeleter.delete(debFolder) # Copy the Python package into it srcFolder = j(debFolder, 'usr', 'lib') for version in self.pythonVersions: libFolder = j(srcFolder, 'python%s' % version) os.makedirs(libFolder) destFolder = j(libFolder, self.appName) shutil.copytree(self.app, destFolder) # Clean dest folder (.svn/.bzr files) cleanFolder(destFolder, folders=('.svn', '.bzr')) # When packaging Appy itself, everything is in /usr/lib/pythonX. When # packaging an Appy app, we will generate more files for creating a # running instance. if self.appName != 'appy': # Create the folders that will collectively represent the deployed # Zope instance. binFolder = j(debFolder, 'usr', 'bin') os.makedirs(binFolder) # <app>ctl name = '%s/%sctl' % (binFolder, self.appNameLower) f = file(name, 'w') f.write(appCtl % self.appNameLower) os.chmod(name, 0744) # Make it executable by owner. f.close() # <app>run name = '%s/%srun' % (binFolder, self.appNameLower) f = file(name, 'w') f.write(appRun % self.appNameLower) os.chmod(name, 0744) # Make it executable by owner. f.close() # startoo name = '%s/startoo' % binFolder f = file(name, 'w') f.write(ooStart) f.close() os.chmod(name, 0744) # Make it executable by owner. # /var/lib/<app> (will store Data.fs, lock files, etc) varLibFolder = j(debFolder, 'var', 'lib', self.appNameLower) os.makedirs(varLibFolder) f = file('%s/README' % varLibFolder, 'w') f.write('This folder stores the %s database.\n' % self.appName) f.close() # /var/log/<app> (will store event.log and Z2.log) varLogFolder = j(debFolder, 'var', 'log', self.appNameLower) os.makedirs(varLogFolder) f = file('%s/README' % varLogFolder, 'w') f.write('This folder stores the log files for %s.\n' % self.appName) f.close() # /etc/<app>.conf (Zope configuration file) etcFolder = j(debFolder, 'etc') os.makedirs(etcFolder) name = '%s/%s.conf' % (etcFolder, self.appNameLower) n = self.appNameLower f = file(name, 'w') productsFolder = '/usr/lib/python%s/%s/zope' % \ (self.pythonVersions[0], self.appName) f.write(zopeConf % ('/var/lib/%s' % n, '/var/lib/%s' % n, '/var/log/%s' % n, str(self.zopePort), 'products %s\n' % productsFolder)) f.close() # /etc/init.d/<app> (start the app at boot time) initdFolder = j(etcFolder, 'init.d') os.makedirs(initdFolder) name = '%s/%s' % (initdFolder, self.appNameLower) f = file(name, 'w') n = self.appNameLower f.write(initScript % (n, n, 'Start Zope with the Appy-based %s ' \ 'application.' % n, '%sctl start' % n, '%sctl restart' % n, '%sctl stop' % n)) f.close() os.chmod(name, 0744) # Make it executable by owner. # /etc/init.d/oo (start OpenOffice at boot time) name = '%s/oo' % initdFolder f = file(name, 'w') f.write(initScript % ('oo', 'oo', 'Start OpenOffice in server mode', 'startoo', 'startoo', "#Can't stop OO.")) f.write('\n') f.close() os.chmod(name, 0744) # Make it executable by owner. # Get the size of the app, in Kb. os.chdir(tempFolder) cmd = subprocess.Popen(['du', '-b', '-s', 'debian'], stdout=subprocess.PIPE) size = int(int(cmd.stdout.read().split()[0]) / 1024.0) os.chdir(debFolder) # Create data.tar.gz based on it. os.system('tar czvf data.tar.gz *') # Create the control file f = file('control', 'w') nameSuffix = '' dependencies = [] if self.appName != 'appy': nameSuffix = '-%s' % self.appNameLower dependencies.append('python-appy') if self.depends: for d in self.depends: dependencies.append(d) depends = '' if dependencies: depends = ', ' + ', '.join(dependencies) f.write(debianInfo % (nameSuffix, self.appVersion, size, self.pythonVersions[0], depends)) f.close() # Create md5sum file f = file('md5sums', 'w') toWalk = ['usr'] if self.appName != 'appy': toWalk += ['etc', 'var'] for folderToWalk in toWalk: for dir, dirnames, filenames in os.walk(folderToWalk): for name in filenames: m = md5.new() pathName = j(dir, name) currentFile = file(pathName, 'rb') while True: data = currentFile.read(8096) if not data: break m.update(data) currentFile.close() # Add the md5 sum to the file f.write('%s %s\n' % (m.hexdigest(), pathName)) f.close() # Create postinst, a script that will: # - bytecompile Python files after the Debian install # - change ownership of some files if required # - [in the case of an app-package] call update-rc.d for starting it at # boot time. f = file('postinst', 'w') content = '#!/bin/sh\nset -e\n' for version in self.pythonVersions: bin = '/usr/bin/python%s' % version lib = '/usr/lib/python%s' % version cmds = ' %s -m compileall -q %s/%s 2> /dev/null\n' % (bin, lib, self.appName) content += 'if [ -e %s ]\nthen\n%sfi\n' % (bin, cmds) if self.appName != 'appy': # Allow user "zope", that runs the Zope instance, to write the # database and log files. content += 'chown -R zope:root /var/lib/%s\n' % self.appNameLower content += 'chown -R zope:root /var/log/%s\n' % self.appNameLower # Call update-rc.d for starting the app at boot time content += 'update-rc.d %s defaults\n' % self.appNameLower content += 'update-rc.d oo defaults\n' # (re-)start the app content += '%sctl restart\n' % self.appNameLower # (re-)start oo content += 'startoo\n' f.write(content) f.close() # Create prerm, a script that will remove all pyc files before removing # the Debian package. f = file('prerm', 'w') content = '#!/bin/sh\nset -e\n' for version in self.pythonVersions: content += 'find /usr/lib/python%s/%s -name "*.pyc" -delete\n' % \ (version, self.appName) f.write(content) f.close() # Create control.tar.gz os.system('tar czvf control.tar.gz ./control ./md5sums ./postinst ' \ './prerm') # Create debian-binary f = file('debian-binary', 'w') f.write('2.0\n') f.close() # Create the signature if required if self.sign: # Create the concatenated version of all files within the deb os.system('cat debian-binary control.tar.gz data.tar.gz > ' \ '/tmp/combined-contents') os.system('gpg -abs -o _gpgorigin /tmp/combined-contents') signFile = '_gpgorigin ' os.remove('/tmp/combined-contents') # Export the public key and name it according to its ID as found by # analyzing the result of command "gpg --fingerprint". cmd = subprocess.Popen(['gpg', '--fingerprint'], stdout=subprocess.PIPE) fingerprint = cmd.stdout.read().split('\n') id = 'pubkey' for line in fingerprint: if '=' not in line: continue id = line.split('=')[1].strip() id = ''.join(id.split()[-4:]) break os.system('gpg --export -a > %s/%s.asc' % (self.out, id)) else: signFile = '' # Create the .deb package debName = 'python-appy%s-%s.deb' % (nameSuffix, self.appVersion) os.system('ar -r %s %sdebian-binary control.tar.gz data.tar.gz' % \ (debName, signFile)) # Move it to self.out os.rename(j(debFolder, debName), j(self.out, debName)) # Clean temp files FolderDeleter.delete(debFolder) os.chdir(curdir)
if (resultType == '.odt') and not self.forceOoCall: # Simply move the ODT result to the result os.rename(resultOdtName, self.result) else: if resultType.startswith('.'): resultType = resultType[1:] if not resultType in FILE_TYPES.keys(): raise PodError(BAD_RESULT_TYPE % (self.result, FILE_TYPES.keys())) # Call OpenOffice to perform the conversion or document update output = self.callOpenOffice(resultOdtName, resultType) # I (should) have the result. Move it to the correct name resPrefix = os.path.splitext(resultOdtName)[0] + '.' if resultType == 'odt': # converter.py has (normally!) created a second file # suffixed .res.odt resultName = resPrefix + 'res.odt' if not os.path.exists(resultName): resultName = resultOdtName # In this case OO in server mode could not be called to # update indexes, sections, etc. else: resultName = resPrefix + resultType if not os.path.exists(resultName): raise PodError(CONVERT_ERROR % output) os.rename(resultName, self.result) finally: FolderDeleter.delete(self.tempFolder) # ------------------------------------------------------------------------------
def run(self): '''Generates the Debian package.''' curdir = os.getcwd() j = os.path.join tempFolder = getOsTempFolder() # Create, in the temp folder, the required sub-structure for the Debian # package. debFolder = j(tempFolder, 'debian') if os.path.exists(debFolder): FolderDeleter.delete(debFolder) # Copy the Python package into it srcFolder = j(debFolder, 'usr', 'lib') for version in self.pythonVersions: libFolder = j(srcFolder, 'python%s' % version) os.makedirs(libFolder) destFolder = j(libFolder, self.appName) shutil.copytree(self.app, destFolder) # Clean dest folder (.svn/.bzr files) cleanFolder(destFolder, folders=('.svn', '.bzr')) # When packaging Appy itself, everything is in /usr/lib/pythonX. When # packaging an Appy app, we will generate more files for creating a # running instance. if self.appName != 'appy': # Create the folders that will collectively represent the deployed # Zope instance. binFolder = j(debFolder, 'usr', 'bin') os.makedirs(binFolder) # <app>ctl name = '%s/%sctl' % (binFolder, self.appNameLower) f = file(name, 'w') f.write(appCtl % self.appNameLower) os.chmod(name, 0744) # Make it executable by owner. f.close() # <app>run name = '%s/%srun' % (binFolder, self.appNameLower) f = file(name, 'w') f.write(appRun % self.appNameLower) os.chmod(name, 0744) # Make it executable by owner. f.close() # startlo name = '%s/startlo' % binFolder f = file(name, 'w') f.write(loStart) f.close() os.chmod(name, 0744) # Make it executable by owner. # /var/lib/<app> (will store Data.fs, lock files, etc) varLibFolder = j(debFolder, 'var', 'lib', self.appNameLower) os.makedirs(varLibFolder) f = file('%s/README' % varLibFolder, 'w') f.write('This folder stores the %s database.\n' % self.appName) f.close() # /var/log/<app> (will store event.log and Z2.log) varLogFolder = j(debFolder, 'var', 'log', self.appNameLower) os.makedirs(varLogFolder) f = file('%s/README' % varLogFolder, 'w') f.write('This folder stores the log files for %s.\n' % self.appName) f.close() # /etc/<app>.conf (Zope configuration file) etcFolder = j(debFolder, 'etc') os.makedirs(etcFolder) name = '%s/%s.conf' % (etcFolder, self.appNameLower) n = self.appNameLower f = file(name, 'w') productsFolder = '/usr/lib/python%s/%s/zope' % \ (self.pythonVersions[0], self.appName) f.write(zopeConf % ('/var/lib/%s' % n, '/var/lib/%s' % n, '/var/log/%s' % n, str(self.zopePort), 'products %s\n' % productsFolder)) f.close() # /etc/init.d/<app> (start the app at boot time) initdFolder = j(etcFolder, 'init.d') os.makedirs(initdFolder) name = '%s/%s' % (initdFolder, self.appNameLower) f = file(name, 'w') n = self.appNameLower f.write(initScript % (n, n, 'Start Zope with the Appy-based %s ' \ 'application.' % n, '%sctl start' % n, '%sctl restart' % n, '%sctl stop' % n)) f.close() os.chmod(name, 0744) # Make it executable by owner # /etc/init.d/lo (start LibreOffice at boot time) name = '%s/lo' % initdFolder f = file(name, 'w') f.write(initScript % ('lo','lo', 'Start LibreOffice in server mode', 'startlo', 'startlo', "#Can't stop LO.")) f.write('\n') f.close() os.chmod(name, 0744) # Make it executable by owner. # Get the size of the app, in Kb. os.chdir(tempFolder) out, err = executeCommand(['du', '-b', '-s', 'debian']) size = int(int(out.split()[0])/1024.0) os.chdir(debFolder) # Create data.tar.gz based on it executeCommand(['tar', 'czvf', 'data.tar.gz', '*']) # Create the control file f = file('control', 'w') nameSuffix = '' dependencies = [] if self.appName != 'appy': nameSuffix = '-%s' % self.appNameLower dependencies.append('python-appy') if self.depends: for d in self.depends: dependencies.append(d) depends = '' if dependencies: depends = ', ' + ', '.join(dependencies) f.write(debianInfo % (nameSuffix, self.appVersion, size, self.pythonVersions[0], depends)) f.close() # Create md5sum file f = file('md5sums', 'w') toWalk = ['usr'] if self.appName != 'appy': toWalk += ['etc', 'var'] for folderToWalk in toWalk: for dir, dirnames, filenames in os.walk(folderToWalk): for name in filenames: m = md5.new() pathName = j(dir, name) currentFile = file(pathName, 'rb') while True: data = currentFile.read(8096) if not data: break m.update(data) currentFile.close() # Add the md5 sum to the file f.write('%s %s\n' % (m.hexdigest(), pathName)) f.close() # Create postinst, a script that will: # - bytecompile Python files after the Debian install # - change ownership of some files if required # - [in the case of an app-package] call update-rc.d for starting it at # boot time. f = file('postinst', 'w') content = '#!/bin/sh\nset -e\n' for version in self.pythonVersions: bin = '/usr/bin/python%s' % version lib = '/usr/lib/python%s' % version cmds = ' %s -m compileall -q %s/%s 2> /dev/null\n' % (bin, lib, self.appName) content += 'if [ -e %s ]\nthen\n%sfi\n' % (bin, cmds) if self.appName != 'appy': # Allow user "zope", that runs the Zope instance, to write the # database and log files. content += 'chown -R zope:root /var/lib/%s\n' % self.appNameLower content += 'chown -R zope:root /var/log/%s\n' % self.appNameLower # Call update-rc.d for starting the app at boot time content += 'update-rc.d %s defaults\n' % self.appNameLower content += 'update-rc.d lo defaults\n' # (re-)start the app content += '%sctl restart\n' % self.appNameLower # (re-)start lo content += 'startlo\n' f.write(content) f.close() # Create prerm, a script that will remove all pyc files before removing # the Debian package. f = file('prerm', 'w') content = '#!/bin/sh\nset -e\n' for version in self.pythonVersions: content += 'find /usr/lib/python%s/%s -name "*.pyc" -delete\n' % \ (version, self.appName) f.write(content) f.close() # Create control.tar.gz executeCommand(['tar', 'czvf', 'control.tar.gz', './control', './md5sums', './postinst', './prerm']) # Create debian-binary f = file('debian-binary', 'w') f.write('2.0\n') f.close() # Create the signature if required if self.sign: # Create the concatenated version of all files within the deb out, err = executeCommand(['cat', 'debian-binary', 'control.tar.gz', 'data.tar.gz']) f = file('/tmp/combined-contents', 'wb') f.write(out) f.close() executeCommand(['gpg', '-abs', '-o', '_gpgorigin', '/tmp/combined-contents']) signFile = '_gpgorigin' os.remove('/tmp/combined-contents') # Export the public key and name it according to its ID as found by # analyzing the result of command "gpg --fingerprint". out, err = executeCommand(['gpg', '--fingerprint']) fingerprint = out.split('\n') id = 'pubkey' for line in fingerprint: if '=' not in line: continue id = line.split('=')[1].strip() id = ''.join(id.split()[-4:]) break out, err = executeCommand(['gpg', '--export', '-a']) f = file('%s/%s.asc' % (self.out, id), 'w') f.write(out) f.close() else: signFile = None # Create the .deb package debName = 'python-appy%s-%s.deb' % (nameSuffix, self.appVersion) cmd = ['ar', '-r', debName] if signFile: cmd.append(signFile) cmd += ['debian-binary', 'control.tar.gz', 'data.tar.gz'] out, err = executeCommand(cmd) # Move it to self.out os.rename(j(debFolder, debName), j(self.out, debName)) # Clean temp files FolderDeleter.delete(debFolder) os.chdir(curdir)
if (resultType == '.odt') and not self.forceOoCall: # Simply move the ODT result to the result os.rename(resultOdtName, self.result) else: if resultType.startswith('.'): resultType = resultType[1:] if not resultType in FILE_TYPES.keys(): raise PodError(BAD_RESULT_TYPE % ( self.result, FILE_TYPES.keys())) # Call OpenOffice to perform the conversion or document update print 'At this point, %s must exist'% resultOdtName assert os.path.exists(resultOdtName) output = self.callOpenOffice(resultOdtName, resultType) # I (should) have the result. Move it to the correct name resPrefix = os.path.splitext(resultOdtName)[0] + '.' if resultType == 'odt': # converter.py has (normally!) created a second file # suffixed .res.odt resultName = resPrefix + 'res.odt' if not os.path.exists(resultName): resultName = resultOdtName # In this case OO in server mode could not be called to # update indexes, sections, etc. else: resultName = resPrefix + resultType if not os.path.exists(resultName): raise PodError(CONVERT_ERROR % output) os.rename(resultName, self.result) finally: FolderDeleter.delete(self.tempFolder) # ------------------------------------------------------------------------------